Files
WRNexusJS/packages/syntax/test/apis-block.test.ts
T
ClintchizandClaude Opus 5 0ed8351828 test: restore executed and real-tsc coverage lost when the old api-block tests were deleted
Fix round 1: the deleted api-block-*.test.ts files were not fully superseded
by the apis-* siblings as claimed. Ports back, using apis {} fixtures:
- brace-inside-a-string-literal response-section scanner regression test
- type erasure of response/error bodies before browser emission
- client-side response-error-not-swallowed / transport-failure-fallback,
  executed via dynamic import of a generated browser module
- the full SSR execution suite: response payload binding, error section
  status/message/data binding, {#each} failure propagation, all executed
  via dynamic import + a real load/api call chain (not string checks)
- the four real-tsc enforcement tests (matching/wrong-type/extra-field/
  missing-field), plus the B1 cross-page collision guard and the B6
  export-for-noUnusedLocals guard

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 08:14:16 +05:30

124 lines
3.0 KiB
TypeScript

import { expect, test } from "bun:test";
import { parse } from "../src/index.ts";
const page = (inner: string) => `page Repro {
apis {
${inner}
}
view { <main>x</main> }
}
`;
test("parses a mode-less entry with its sections", () => {
const ast = parse(
page(` searchUsers POST /api/users {
request {
body {
name?: string
}
}
response { return data.users }
error { return [] }
}`),
);
const block = ast.dataApis[0]!;
expect(block.name).toBe("searchUsers");
expect(block.method).toBe("POST");
expect(block.path).toBe("/api/users");
expect(block.mode).toBe("any");
expect(block.sections?.body).toEqual([{ name: "name", optional: true, type: "string" }]);
expect(block.sections?.response.trim()).toBe("return data.users");
expect(block.sections?.error.trim()).toBe("return []");
});
test("parses several entries in one container", () => {
const ast = parse(
page(` a GET /api/a { response { return data } }
b POST /api/b { response { return data } }`),
);
expect(ast.dataApis.map((block) => block.name)).toEqual(["a", "b"]);
});
test("a GET entry declares parameters", () => {
const ast = parse(
page(` listTeams GET /api/teams {
request {
parameters {
team: string
}
}
response { return data.teams }
}`),
);
expect(ast.dataApis[0]!.sections?.parameters).toEqual([
{ name: "team", optional: false, type: "string" },
]);
});
test("duplicate names inside one container are rejected", () => {
expect(() =>
parse(
page(` dup GET /api/a { response { return data } }
dup POST /api/b { response { return data } }`),
),
).toThrow(/duplicate/i);
});
test("a bare body inside apis {} is a parse error naming response", () => {
expect(() => parse(page(` bare GET /api/z { return data }`))).toThrow(/response/i);
});
test("two apis entries of the same name across separate blocks are rejected", () => {
const src = `page Repro {
apis {
foo GET /api/foo { response { return data } }
}
apis {
foo GET /api/foo { response { return data } }
}
view { <main>x</main> }
}
`;
expect(() => parse(src)).toThrow(/duplicate/i);
});
test("an explicit empty response section is accepted, unlike a bare body", () => {
const ast = parse(page(` empty GET /api/e { response { } }`));
const block = ast.dataApis[0]!;
expect(block.name).toBe("empty");
expect(block.sections?.response.trim()).toBe("");
});
test("a brace inside a string literal in the response body does not truncate the section", () => {
const ast = parse(
page(` searchUsers POST /api/users {
request {
body {
name?: string
}
}
response {
return "a } weird string"
}
error {
return []
}
}`),
);
const block = ast.dataApis[0]!;
expect(block.sections?.response.trim()).toBe('return "a } weird string"');
expect(block.sections?.error.trim()).toBe("return []");
});