Files
pikasTech-HWLAB/web/hwlab-cloud-web/scripts/r6-architecture-parity.test.ts
T

72 lines
3.6 KiB
TypeScript

import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import test from "node:test";
import { fileURLToPath } from "node:url";
import { messageFromError } from "../src/composables/useForm.ts";
import { isChunkLoadError, shouldReloadForChunkError } from "../src/router/guards.ts";
import { resolveDocumentTitle } from "../src/router/title.ts";
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
test("R6 route meta title and chunk recovery match Sub2API navigation pattern", () => {
assert.equal(resolveDocumentTitle("Gate"), "Gate - HWLAB Cloud Web");
assert.equal(resolveDocumentTitle(" "), "平台控制台 - HWLAB Cloud Web");
assert.equal(isChunkLoadError(new Error("Failed to fetch dynamically imported module")), true);
assert.equal(isChunkLoadError(new Error("Loading CSS chunk 42 failed")), true);
assert.equal(isChunkLoadError(new Error("ordinary route guard failure")), false);
const memory = new Map<string, string>();
const storage = {
getItem: (key: string) => memory.get(key) ?? null,
setItem: (key: string, value: string) => { memory.set(key, value); }
};
assert.equal(shouldReloadForChunkError(100_000, storage), true);
assert.equal(shouldReloadForChunkError(105_000, storage), false);
assert.equal(shouldReloadForChunkError(111_000, storage), true);
});
test("R6 useForm normalizes nested API errors for toast/error surfaces", () => {
assert.equal(messageFromError(new Error("plain failure")), "plain failure");
assert.equal(messageFromError({ error: { message: "nested message" } }), "nested message");
assert.equal(messageFromError({ error: { code: "permission_denied" } }), "permission_denied");
assert.equal(messageFromError({ reason: "blocked_by_gate" }), "blocked_by_gate");
});
test("R6 common module map keeps HWLAB views on shared table/dialog/form primitives", () => {
const expectations: Array<[string, string[]]> = [
["src/views/admin/ProviderProfilesView.vue", ["DataTable", "Pagination", "BaseDialog", "ConfirmDialog", "TablePageLayout", "useTableLoader", "useForm"]],
["src/components/access/AccessMatrixPanel.vue", ["DataTable", "TablePageLayout"]],
["src/views/GateView.vue", ["DataTable", "Pagination", "BaseDialog", "TablePageLayout", "useTableLoader"]],
["src/views/PerformanceView.vue", ["DataTable", "TablePageLayout", "useTableLoader"]],
["src/views/SkillsView.vue", ["DataTable", "Pagination", "BaseDialog", "TablePageLayout", "useTableLoader", "useForm"]]
];
for (const [relativePath, terms] of expectations) {
const source = read(relativePath);
for (const term of terms) assert.match(source, new RegExp(`\\b${term}\\b`, "u"), `${relativePath} should use ${term}`);
assert.doesNotMatch(source, /<table\s/u, `${relativePath} should not regress to local raw table markup`);
}
});
test("R6 Sub2API source comparison is recorded in parent/child issue scope", () => {
const issueBody = readIssueBodyFixture();
assert.match(issueBody, /Wei-Shaw\/sub2api@v0\.1\.136=a2f76e4/u);
assert.match(issueBody, /router\/index\.ts/u);
assert.match(issueBody, /components\/common/u);
assert.match(issueBody, /useTableLoader\.ts/u);
assert.match(issueBody, /useForm\.ts/u);
});
function read(relativePath: string): string {
return fs.readFileSync(path.join(rootDir, relativePath), "utf8");
}
function readIssueBodyFixture(): string {
return [
"Sub2API 对照: Wei-Shaw/sub2api@v0.1.136=a2f76e4",
"router/index.ts api/client.ts components/common/* composables/useTableLoader.ts useForm.ts admin/user CRUD views"
].join("\n");
}