Skip to content

Commit 5ffb52d

Browse files
committed
feat: refactor tests to destructure parameters from getSignatureSchema and add return schema assertions
1 parent 1de4933 commit 5ffb52d

1 file changed

Lines changed: 157 additions & 12 deletions

File tree

test/schema/schema.test.ts

Lines changed: 157 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ describe("Schema", () => {
305305
},
306306
};
307307

308-
const [first] = getSignatureSchema(
308+
const {parameters: [first]} = getSignatureSchema(
309309
flow,
310310
DATA_TYPES,
311311
FUNCTION_SIGNATURES,
@@ -371,13 +371,13 @@ describe("Schema", () => {
371371
value: "hello",
372372
});
373373

374-
const [refResult] = getSignatureSchema(
374+
const {parameters: [refResult]} = getSignatureSchema(
375375
refFlow,
376376
DATA_TYPES,
377377
FUNCTION_SIGNATURES,
378378
"gid://sagittarius/NodeFunction/2",
379379
);
380-
const [literalResult] = getSignatureSchema(
380+
const {parameters: [literalResult]} = getSignatureSchema(
381381
literalFlow,
382382
DATA_TYPES,
383383
FUNCTION_SIGNATURES,
@@ -486,7 +486,7 @@ describe("Schema", () => {
486486
});
487487

488488
const probe = (returnValue: any) => {
489-
const [r] = getSignatureSchema(
489+
const {parameters: [r]} = getSignatureSchema(
490490
buildFlow(returnValue),
491491
DATA_TYPES,
492492
FUNCTION_SIGNATURES,
@@ -563,7 +563,7 @@ describe("Schema", () => {
563563
},
564564
};
565565

566-
const [listSchema] = getSignatureSchema(
566+
const {parameters: [listSchema]} = getSignatureSchema(
567567
flow,
568568
DATA_TYPES,
569569
FUNCTION_SIGNATURES,
@@ -609,7 +609,7 @@ describe("Schema", () => {
609609
},
610610
};
611611

612-
const [first] = getSignatureSchema(
612+
const {parameters: [first]} = getSignatureSchema(
613613
flow,
614614
DATA_TYPES,
615615
FUNCTION_SIGNATURES,
@@ -669,7 +669,7 @@ describe("Schema", () => {
669669
);
670670

671671
// payload is the 4th parameter of rest::control::respond.
672-
const payloadSchema = result[3];
672+
const payloadSchema = result.parameters[3];
673673

674674
// application/json → HTTP_PAYLOAD<S> = OBJECT<{}> → open object input.
675675
expect(payloadSchema.schema.input).toBe("data");
@@ -731,7 +731,7 @@ describe("Schema", () => {
731731
},
732732
};
733733

734-
const [valueSchema] = getSignatureSchema(
734+
const {parameters: [valueSchema]} = getSignatureSchema(
735735
flow,
736736
DATA_TYPES,
737737
[...FUNCTION_SIGNATURES, NULLABLE_TEXT_FN],
@@ -799,7 +799,7 @@ describe("Schema", () => {
799799
},
800800
};
801801

802-
const [valueSchema] = getSignatureSchema(
802+
const {parameters: [valueSchema]} = getSignatureSchema(
803803
flow,
804804
DATA_TYPES,
805805
[...FUNCTION_SIGNATURES, NULLABLE_OBJECT_FN],
@@ -871,7 +871,7 @@ describe("Schema", () => {
871871
},
872872
};
873873

874-
const [valueSchema] = getSignatureSchema(
874+
const {parameters: [valueSchema]} = getSignatureSchema(
875875
flow,
876876
DATA_TYPES,
877877
[...FUNCTION_SIGNATURES, NESTED_NULLABLE_OBJECT_FN],
@@ -940,7 +940,7 @@ describe("Schema", () => {
940940
},
941941
};
942942

943-
const [valueSchema] = getSignatureSchema(
943+
const {parameters: [valueSchema]} = getSignatureSchema(
944944
flow,
945945
DATA_TYPES,
946946
[...FUNCTION_SIGNATURES, DEEPLY_NESTED_FN],
@@ -1019,7 +1019,7 @@ describe("Schema", () => {
10191019
},
10201020
};
10211021

1022-
const [valueSchema] = getSignatureSchema(
1022+
const {parameters: [valueSchema]} = getSignatureSchema(
10231023
flow,
10241024
[...DATA_TYPES, ...RECURSIVE_DATA_TYPES],
10251025
[...FUNCTION_SIGNATURES, RECURSIVE_FN],
@@ -1050,4 +1050,149 @@ describe("Schema", () => {
10501050
expect(paths).not.toContain("chain.next.next.next.next.next.next.value");
10511051
});
10521052

1053+
describe("return schema", () => {
1054+
// Single-node flow calling `identifier` with the given parameters, probed at that node.
1055+
const singleNode = (identifier: string, params: any[]): Flow => ({
1056+
id: "gid://sagittarius/Flow/1",
1057+
startingNodeId: "gid://sagittarius/NodeFunction/1",
1058+
signature: "(): void",
1059+
nodes: {
1060+
nodes: [
1061+
{
1062+
id: "gid://sagittarius/NodeFunction/1",
1063+
functionDefinition: {identifier},
1064+
parameters: {nodes: params},
1065+
},
1066+
],
1067+
},
1068+
});
1069+
1070+
const returnOf = (identifier: string, params: any[]) =>
1071+
getSignatureSchema(
1072+
singleNode(identifier, params),
1073+
DATA_TYPES,
1074+
FUNCTION_SIGNATURES,
1075+
"gid://sagittarius/NodeFunction/1",
1076+
).return;
1077+
1078+
// Asserts every schema node in the tree (root, nested properties, list
1079+
// items) has no suggestions — a return schema describes an output, so it
1080+
// never carries input suggestions.
1081+
const expectNoSuggestionsAnywhere = (schema: any, path = "return"): void => {
1082+
expect(
1083+
schema.suggestions === undefined ||
1084+
(Array.isArray(schema.suggestions) && schema.suggestions.length === 0),
1085+
`${path} unexpectedly has suggestions: ${JSON.stringify(schema.suggestions)}`,
1086+
).toBe(true);
1087+
for (const [key, child] of Object.entries(schema.properties ?? {})) {
1088+
const children = Array.isArray(child) ? child : [child];
1089+
children.forEach((c, i) =>
1090+
expectNoSuggestionsAnywhere(c, `${path}.properties.${key}[${i}]`),
1091+
);
1092+
}
1093+
(schema.items ?? []).forEach((item: any, i: number) =>
1094+
expectNoSuggestionsAnywhere(item, `${path}.items[${i}]`),
1095+
);
1096+
};
1097+
1098+
it("resolves a NUMBER return to a number input", () => {
1099+
// std::boolean::as_number → (value: BOOLEAN): NUMBER
1100+
const ret = returnOf("std::boolean::as_number", [
1101+
{value: {__typename: "LiteralValue", value: true}},
1102+
]);
1103+
expect(ret).toEqual({input: "number"});
1104+
});
1105+
1106+
it("resolves a TEXT return to a text input", () => {
1107+
// std::boolean::as_text → (value: BOOLEAN): TEXT
1108+
const ret = returnOf("std::boolean::as_text", [
1109+
{value: {__typename: "LiteralValue", value: true}},
1110+
]);
1111+
expect(ret).toEqual({input: "text"});
1112+
});
1113+
1114+
it("resolves a BOOLEAN return to a boolean input", () => {
1115+
// std::boolean::from_number → (value: NUMBER): BOOLEAN
1116+
const ret = returnOf("std::boolean::from_number", [
1117+
{value: {__typename: "LiteralValue", value: 1}},
1118+
]);
1119+
expect(ret).toEqual({input: "boolean"});
1120+
});
1121+
1122+
it("resolves an object return (HTTP_RESPONSE) to a data input with its properties", () => {
1123+
// http::request::send → (...): HTTP_RESPONSE<any>
1124+
const ret = returnOf("http::request::send", [
1125+
{value: {__typename: "LiteralValue", value: "GET"}},
1126+
{value: {__typename: "LiteralValue", value: "/x"}},
1127+
{value: null},
1128+
{value: null},
1129+
{value: null},
1130+
{value: null},
1131+
{value: null},
1132+
{value: null},
1133+
]);
1134+
expect(ret.input).toBe("data");
1135+
const dataRet = ret as {properties: Record<string, unknown>; required: string[]};
1136+
expect(Object.keys(dataRet.properties)).toEqual(
1137+
expect.arrayContaining(["payload", "headers", "http_status_code"]),
1138+
);
1139+
expect(dataRet.required).toEqual(
1140+
expect.arrayContaining(["payload", "headers", "http_status_code"]),
1141+
);
1142+
// The return type describes an output, so it carries no input
1143+
// suggestions — at any nesting level.
1144+
expectNoSuggestionsAnywhere(ret);
1145+
});
1146+
1147+
it("instantiates a generic return type from the supplied arguments", () => {
1148+
// std::list::at → <T>(list: LIST<T>, index: NUMBER): T
1149+
// A list of numbers binds T = NUMBER, so the return is a number input.
1150+
const ret = returnOf("std::list::at", [
1151+
{value: {__typename: "LiteralValue", value: [10, 20, 30]}},
1152+
{value: {__typename: "LiteralValue", value: 0}},
1153+
]);
1154+
expect(ret).toEqual({input: "number"});
1155+
});
1156+
1157+
it("returns a generic input for a void signature and no nodeId at the flow level", () => {
1158+
const result = getSignatureSchema(
1159+
singleNode("std::boolean::as_number", [
1160+
{value: {__typename: "LiteralValue", value: true}},
1161+
]),
1162+
DATA_TYPES,
1163+
FUNCTION_SIGNATURES,
1164+
);
1165+
// Flow-level probe: no target node, flow signature is `(): void`.
1166+
expect(result.nodeId).toBeUndefined();
1167+
expect(result.return).toEqual({input: "generic"});
1168+
});
1169+
1170+
it("never carries suggestions, whatever the return type", () => {
1171+
// Primitive, object, list and generic returns all stay suggestion-free.
1172+
expectNoSuggestionsAnywhere(
1173+
returnOf("std::boolean::as_number", [
1174+
{value: {__typename: "LiteralValue", value: true}},
1175+
]),
1176+
);
1177+
expectNoSuggestionsAnywhere(
1178+
returnOf("std::list::at", [
1179+
{value: {__typename: "LiteralValue", value: [1, 2, 3]}},
1180+
{value: {__typename: "LiteralValue", value: 0}},
1181+
]),
1182+
);
1183+
expectNoSuggestionsAnywhere(
1184+
returnOf("http::request::send", [
1185+
{value: {__typename: "LiteralValue", value: "GET"}},
1186+
{value: {__typename: "LiteralValue", value: "/x"}},
1187+
{value: null},
1188+
{value: null},
1189+
{value: null},
1190+
{value: null},
1191+
{value: null},
1192+
{value: null},
1193+
]),
1194+
);
1195+
});
1196+
});
1197+
10531198
})

0 commit comments

Comments
 (0)