import test from "node:test"; import assert from "node:assert/strict"; const { cleanJSONSchemaForAntigravity } = await import( "../../open-sse/translator/helpers/geminiHelper.ts" ); test("#9268 injects type:object on nested properties without type", () => { const input = { type: "object", properties: { name: { type: "string" }, address: { // nested node with properties but NO type — should get type:object properties: { street: { type: "string" }, city: { type: "string" }, }, }, }, required: ["name"], }; const result = cleanJSONSchemaForAntigravity(input) as Record; const props = result.properties as Record; const address = props.address as Record; assert.equal(address.type, "object", "nested object with properties must get type:object"); }); test("#9268 injects type:object on nested items array schemas", () => { const input = { type: "object", properties: { items: { type: "array", items: { // array items schema with properties but NO type properties: { id: { type: "integer" }, label: { type: "string" }, }, }, }, }, }; const result = cleanJSONSchemaForAntigravity(input) as Record; const props = result.properties as Record; const items = props.items as Record; const inner = items.items as Record; assert.equal(inner.type, "object", "array items schema with properties must inject type:object"); }); test("#9268 injects type:object on deeply nested schemas (3+ levels)", () => { const input = { type: "object", properties: { level1: { properties: { level2: { properties: { level3: { properties: { value: { type: "string" }, }, }, }, }, }, }, }, }; const result = cleanJSONSchemaForAntigravity(input) as Record; const l1 = (result.properties as Record).level1 as Record; const l2 = (l1.properties as Record).level2 as Record; const l3 = (l2.properties as Record).level3 as Record; assert.equal(l1.type, "object", "level1 must have type:object"); assert.equal(l2.type, "object", "level2 must have type:object"); assert.equal(l3.type, "object", "level3 must have type:object"); }); test("#9268 schema already typed is not double-injected", () => { const input = { type: "object", properties: { nested: { type: "object", properties: { x: { type: "string" }, }, }, }, }; const result = cleanJSONSchemaForAntigravity(input) as Record; const nested = (result.properties as Record).nested as Record; assert.equal(nested.type, "object", "already-typed nested must keep its type"); // Ensure properties is not clobbered const nestedProps = nested.properties as Record; assert.ok(nestedProps, "nested properties must be preserved"); assert.ok("x" in nestedProps, "nested property 'x' must exist"); }); test("#9268 node with required but no properties still gets type:object", () => { // Edge case: a node that has `required` but no `type` and no `properties` // should still get type:object injection (Gemini needs it). const input = { type: "object", properties: { ref: { // has required but no type nor properties (e.g. an incomplete $ref stub) required: ["id"], }, }, }; const result = cleanJSONSchemaForAntigravity(input) as Record; const ref = (result.properties as Record).ref as Record; assert.equal(ref.type, "object", "node with required but no type must get type:object"); }); test("#9268 null/undefined fields do not crash the normalizer", () => { const input = { type: "object", properties: { a: null, b: undefined, // @ts-expect-error - testing runtime resilience c: { properties: null }, }, }; assert.doesNotThrow(() => { cleanJSONSchemaForAntigravity(input); }, "null/undefined fields must not crash the normalizer"); });