122 lines
3.4 KiB
TypeScript
122 lines
3.4 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { migrateApisBlock } from "../src/migrations/apis-block.ts";
|
|
|
|
const SOURCE = `page Search {
|
|
client {
|
|
api searchUsers POST /api/users {
|
|
request { body { name?: string } }
|
|
response { return data.users }
|
|
error { return [] }
|
|
}
|
|
}
|
|
|
|
view { <main>x</main> }
|
|
}
|
|
`;
|
|
|
|
test("a client api entry moves into an apis block", () => {
|
|
const result = migrateApisBlock(SOURCE) as { source: string; changed: boolean };
|
|
|
|
expect(result.changed).toBe(true);
|
|
expect(result.source).toContain("apis {");
|
|
expect(result.source).toContain("searchUsers POST /api/users");
|
|
expect(result.source).not.toContain("client {\n api");
|
|
});
|
|
|
|
test("the sections survive unchanged", () => {
|
|
const result = migrateApisBlock(SOURCE) as { source: string };
|
|
|
|
expect(result.source).toContain("return data.users");
|
|
expect(result.source).toContain("return []");
|
|
});
|
|
|
|
test("running it on migrated source changes nothing", () => {
|
|
const once = (migrateApisBlock(SOURCE) as { source: string }).source;
|
|
const twice = migrateApisBlock(once) as { source: string; changed: boolean };
|
|
|
|
expect(twice.changed).toBe(false);
|
|
expect(twice.source).toBe(once);
|
|
});
|
|
|
|
test("a name declared in both modes is skipped with a reason", () => {
|
|
const clash = `page P {
|
|
ssr { api dup GET /api/a { response { return data } } }
|
|
client { api dup GET /api/a { response { return data } } }
|
|
view { <main>x</main> }
|
|
}
|
|
`;
|
|
const result = migrateApisBlock(clash) as { skip: string };
|
|
|
|
expect(result.skip).toContain("dup");
|
|
});
|
|
|
|
test("a page with an existing apis block merges legacy entries instead of producing two apis blocks", () => {
|
|
const source = `page P {
|
|
apis {
|
|
existing GET /api/existing {
|
|
response { return data }
|
|
}
|
|
}
|
|
|
|
client {
|
|
api added POST /api/added {
|
|
response { return data.value }
|
|
}
|
|
}
|
|
|
|
view { <main>x</main> }
|
|
}
|
|
`;
|
|
const result = migrateApisBlock(source) as { source: string; changed: boolean };
|
|
|
|
expect(result.changed).toBe(true);
|
|
const apisCount = (result.source.match(/\bapis\s*\{/g) ?? []).length;
|
|
expect(apisCount).toBe(1);
|
|
expect(result.source).toContain("existing GET /api/existing");
|
|
expect(result.source).toContain("added POST /api/added");
|
|
expect(result.source).not.toContain("client {");
|
|
});
|
|
|
|
test("a mode block mixing api entries with other content is skipped, not partially rewritten", () => {
|
|
// A bare `ssr { … }` block is invalid syntax once api entries are removed
|
|
// (only `state` and hydrate forms survive) -- leftover content such as
|
|
// `functions { }` belongs to the move-mode-functions migration, so this
|
|
// file cannot be completed by this migration alone.
|
|
const source = `page P {
|
|
ssr {
|
|
api foo GET /api/foo {
|
|
response { return data }
|
|
}
|
|
|
|
functions {
|
|
function helper() { return 1 }
|
|
}
|
|
}
|
|
|
|
view { <main>x</main> }
|
|
}
|
|
`;
|
|
const result = migrateApisBlock(source) as { skip: string };
|
|
|
|
expect(result.skip).toContain("ssr");
|
|
expect(result.skip).toContain("functions");
|
|
});
|
|
|
|
test("a brace inside a string literal in a section body does not truncate the entry", () => {
|
|
const source = `page P {
|
|
client {
|
|
api foo GET /api/foo {
|
|
response { return { text: "a } b" } }
|
|
}
|
|
}
|
|
|
|
view { <main>x</main> }
|
|
}
|
|
`;
|
|
const result = migrateApisBlock(source) as { source: string; changed: boolean };
|
|
|
|
expect(result.changed).toBe(true);
|
|
expect(result.source).toContain('text: "a } b"');
|
|
expect(result.source).toContain("apis {");
|
|
});
|