Files
jiapuapp/tests/family-fixture-runtime-smoke.js
T
2026-07-23 08:24:07 +08:00

147 lines
5.8 KiB
JavaScript

"use strict";
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const loadMockModule = async () => {
const source = fs.readFileSync(path.join(__dirname, "../data/mock.js"), "utf8");
const contractSource = fs.readFileSync(
path.join(__dirname, "../utils/genealogy-contracts.js"),
"utf8",
);
const contractUrl = `data:text/javascript;base64,${Buffer.from(contractSource).toString("base64")}`;
const moduleUrl = `data:text/javascript;base64,${Buffer.from(source.replace("../utils/genealogy-contracts.js", contractUrl)).toString("base64")}`;
return import(moduleUrl);
};
const assertScopedOwner = ({ list, find, ids, nestedField }) => {
assert.deepStrictEqual(list("1001").map((item) => item.id), ids);
assert.deepStrictEqual(list("1002"), [], "另一家谱不得读取 1001 的内容夹具");
assert.strictEqual(find("1002", ids[0]), null, "已知 ID 换谱后必须失败关闭");
assert.strictEqual(find("1001", "unknown"), null, "未知实体不得回退首条记录");
assert.strictEqual(find("", ids[0]), null, "缺少 genealogyId 必须失败关闭");
assert.strictEqual(find("1001", ""), null, "缺少实体 ID 必须失败关闭");
const listed = list("1001");
const original = find("1001", ids[0]);
listed[0].title = "被列表调用方修改";
assert.notStrictEqual(find("1001", ids[0]).title, "被列表调用方修改");
if (nestedField) {
const mutateNested = (item, value) => {
if (item[nestedField][0] && typeof item[nestedField][0] === "object") {
item[nestedField][0].__contractMutation = value;
} else {
item[nestedField][0] = value;
}
};
mutateNested(listed[0], "被列表调用方修改");
assert(!JSON.stringify(find("1001", ids[0])[nestedField]).includes("被列表调用方修改"));
mutateNested(original, "被详情调用方修改");
assert(!JSON.stringify(find("1001", ids[0])[nestedField]).includes("被详情调用方修改"));
}
};
const run = async () => {
const fixtures = await loadMockModule();
const {
listFamilyFeedFixtures,
findFamilyFeedFixture,
listFamilyArticleFixtures,
findFamilyArticleFixture,
listFamilyAlbumFixtures,
findFamilyAlbumFixture,
} = fixtures;
for (const selector of [
listFamilyFeedFixtures,
findFamilyFeedFixture,
listFamilyArticleFixtures,
findFamilyArticleFixture,
listFamilyAlbumFixtures,
findFamilyAlbumFixture,
]) {
assert.strictEqual(typeof selector, "function", "F 系列只读夹具必须由共享查询函数拥有");
}
assertScopedOwner({
list: listFamilyFeedFixtures,
find: findFamilyFeedFixture,
ids: ["1", "2"],
nestedField: "comments",
});
assertScopedOwner({
list: listFamilyArticleFixtures,
find: findFamilyArticleFixture,
ids: ["101", "102", "103"],
nestedField: "paragraphs",
});
assertScopedOwner({
list: listFamilyAlbumFixtures,
find: findFamilyAlbumFixture,
ids: ["201", "202", "203"],
nestedField: "photos",
});
for (const [list, entityName] of [
[listFamilyFeedFixtures, "feed"],
[listFamilyArticleFixtures, "article"],
[listFamilyAlbumFixtures, "album"],
]) {
for (const item of list("1001")) {
assert.strictEqual(typeof item.id, "string", `${entityName}.id 必须保持词法字符串`);
assert.strictEqual(item.genealogyId, "1001", `${entityName} 必须显式持有家谱身份`);
}
}
const firstFeed = findFamilyFeedFixture("1001", "1");
firstFeed.comments[0].content = "被详情调用方修改";
assert.notStrictEqual(
findFamilyFeedFixture("1001", "1").comments[0].content,
"被详情调用方修改",
);
globalThis.__familyFixtureOwner = fixtures;
const apiSource = fs
.readFileSync(path.join(__dirname, "../utils/api.js"), "utf8")
.replace(
/^import \{[\s\S]*?\} from '@\/data\/mock\.js'\r?\n/,
"const { currentUser, genealogies, publicGenealogies, treeMembers, notifications, joinApplications, listFamilyFeedFixtures, listFamilyArticleFixtures, listFamilyAlbumFixtures, listCeremonyFixtures, listGrowthRecordFixtures } = globalThis.__familyFixtureOwner;\n",
)
.replace(
/^import \{ hasRemoteConfig[^\n]+\r?\n/m,
"const hasRemoteConfig = () => false; const resolveRuntimeMode = () => 'mock'; const runtimeConfig = { baseUrl: '', clientId: 'test', tenantId: 'test' };\n",
)
.replace(
/^import \{ AUTH_TAC_SCENE, assertSmsCode \}[^\n]+\r?\n/m,
"const AUTH_TAC_SCENE = {}; const assertSmsCode = (value) => value;\n",
)
.replace(
/^import \{ GENEALOGY_ACCESS_PRESET \}[^\n]+\r?\n/m,
"const GENEALOGY_ACCESS_PRESET = { MEMBER_ONLY: 'MEMBER_ONLY' };\n",
)
.replace(
/^import \{ session \}[^\n]+\r?\n/m,
"const session = { getToken: () => '', saveToken: () => {} };\n",
);
const apiUrl = `data:text/javascript;base64,${Buffer.from(apiSource).toString("base64")}`;
const { appApi } = await import(apiUrl);
assert.deepStrictEqual((await appApi.getFeeds("1001")).map((item) => item.id), ["1", "2"]);
assert.deepStrictEqual((await appApi.getArticles("1001")).map((item) => item.id), ["101", "102", "103"]);
assert.deepStrictEqual((await appApi.getAlbums("1001")).map((item) => item.id), ["201", "202", "203"]);
assert.deepStrictEqual(await appApi.getFeeds("1002"), []);
await assert.rejects(
appApi.createFeed("1001", { feedContent: "不得写入正式夹具" }),
(error) => error?.code === "WRITE_UNAVAILABLE" && /不会保存/.test(error.message),
"mock createFeed 必须明确失败,不能污染只读内容 owner",
);
assert.deepStrictEqual(listFamilyFeedFixtures("1001").map((item) => item.id), ["1", "2"]);
process.stdout.write("FAMILY-FIXTURE-RUNTIME-SMOKE PASS\n");
};
run().catch((error) => {
process.stderr.write(`${error.stack || error.message}\n`);
process.exit(1);
});