Files
creator-hub/web/tests/comment-work-cover.test.cjs
T

133 lines
3.4 KiB
JavaScript

const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const test = require("node:test");
const ts = require("../node_modules/typescript");
const filename = path.resolve(
__dirname,
"../src/components/creator/WorksGallery.tsx",
);
const file = ts.createSourceFile(
filename,
fs.readFileSync(filename, "utf8"),
ts.ScriptTarget.Latest,
true,
ts.ScriptKind.TSX,
);
const cover = file.statements.find(
(node) => ts.isFunctionDeclaration(node) && node.name?.text === "WorkCover",
);
const compiled = ts.transpileModule(cover.getText(file), {
compilerOptions: { module: ts.ModuleKind.CommonJS, jsx: ts.JsxEmit.React },
}).outputText;
function harness(fetch) {
const state = [];
const effects = [];
const calls = [];
const revoked = [];
let cursor = 0;
let effect;
const react = {
createElement: (type, props, ...children) => ({
type,
props: { ...props, children },
}),
};
const useState = (initial) => {
const index = cursor++;
if (!(index in state)) state[index] = initial;
return [
state[index],
(value) => {
state[index] = value;
},
];
};
const useEffect = (fn, deps) => {
const index = cursor++;
if (!effects[index]) {
effect = fn;
effects[index] = { deps };
}
};
const url = {
createObjectURL: () => "blob:local-cover",
revokeObjectURL: (value) => revoked.push(value),
};
const Component = new Function(
"exports",
"React",
"useState",
"useEffect",
"fetchCreatorBinary",
"Flex",
"Typography",
"URL",
compiled + "\nreturn exports.WorkCover;",
)(
{},
react,
useState,
useEffect,
(endpoint) => {
calls.push(endpoint);
return fetch();
},
"Flex",
{ Text: "Text" },
url,
);
return {
calls,
revoked,
render(props) {
cursor = 0;
const tree = Component(props);
if (effect) {
effects[2].cleanup = effect();
effect = null;
}
return tree;
},
cleanup() {
effects[2]?.cleanup?.();
},
};
}
const tick = async () => {
for (let i = 0; i < 6; i++) await Promise.resolve();
};
test("comment thumbnails load only the cached local cover and release its image URL", async () => {
const h = harness(async () => ({ cover: true }));
const props = { workID: "work/id", title: "作品标题" };
const loading = h.render(props);
assert.equal(loading.type, "Flex");
assert.equal(loading.props.children[0].props.children[0], "封面加载中");
await tick();
const image = h.render(props);
assert.equal(image.type, "img");
assert.equal(image.props.src, "blob:local-cover");
assert.equal(image.props.alt, "作品标题");
assert.deepEqual(h.calls, ["/creator/works/work%2Fid/cover"]);
h.cleanup();
assert.deepEqual(h.revoked, ["blob:local-cover"]);
});
test("missing cached cover is explicit and never replaced by a remote image", async () => {
const h = harness(async () => {
throw new Error("作品封面尚未缓存");
});
const props = { workID: "missing-cover", title: "作品封面" };
h.render(props);
await tick();
const missing = h.render(props);
assert.equal(missing.type, "Flex");
assert.equal(missing.props.children[0].props.children[0], "封面未缓存");
assert.deepEqual(h.calls, ["/creator/works/missing-cover/cover"]);
h.cleanup();
assert.deepEqual(h.revoked, []);
});