88 lines
3.4 KiB
JavaScript
88 lines
3.4 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const Module = require('node:module');
|
|
const ts = require('typescript');
|
|
|
|
const pagePath = path.join(__dirname, '../src/pages/creator/competitors/index.tsx');
|
|
|
|
function createPage() {
|
|
let filters = {};
|
|
const gallery = 'WorksGallery';
|
|
const element = (type, props) => ({ type, props });
|
|
const mocks = {
|
|
react: {
|
|
useMemo: (factory) => factory(),
|
|
useState: () => [filters, (update) => { filters = update(filters); }],
|
|
},
|
|
'react/jsx-runtime': { jsx: element, jsxs: element },
|
|
antd: {
|
|
Card: 'Card', DatePicker: 'DatePicker', Flex: 'Flex', InputNumber: 'InputNumber',
|
|
Select: 'Select', Space: 'Space', Typography: { Text: 'Text' },
|
|
},
|
|
'@/components/creator/WorksGallery': { __esModule: true, default: gallery },
|
|
};
|
|
const compiled = ts.transpileModule(fs.readFileSync(pagePath, 'utf8'), {
|
|
fileName: pagePath,
|
|
compilerOptions: {
|
|
module: ts.ModuleKind.CommonJS, jsx: ts.JsxEmit.ReactJSX, esModuleInterop: true,
|
|
inlineSourceMap: true, inlineSources: true,
|
|
},
|
|
}).outputText;
|
|
const loaded = new Module(pagePath, module);
|
|
loaded.filename = pagePath;
|
|
loaded.paths = Module._nodeModulePaths(path.dirname(pagePath));
|
|
loaded.require = (name) => Object.hasOwn(mocks, name) ? mocks[name] : module.require(name);
|
|
loaded._compile(compiled, pagePath);
|
|
|
|
function descendants(node) {
|
|
if (!node || typeof node !== 'object') return [];
|
|
return [node, ...[node.props?.children].flat(Infinity).flatMap(descendants)];
|
|
}
|
|
return () => {
|
|
const nodes = descendants(loaded.exports.default());
|
|
return {
|
|
gallery: nodes.find((node) => node.type === gallery).props,
|
|
controls: nodes.filter((node) => node.props.onChange),
|
|
};
|
|
};
|
|
}
|
|
|
|
function assertCompetitorOnly(props) {
|
|
assert.equal(props.sourceType, 'competitor', '竞品分析必须排除自有账号作品');
|
|
assert.equal(props.sourceId, undefined, '竞品分析应包含所有监测账号,而非限定某个账号');
|
|
}
|
|
|
|
test('竞品分析首次加载只查询监测账号作品', () => {
|
|
const render = createPage();
|
|
assertCompetitorOnly(render().gallery);
|
|
});
|
|
|
|
test('调整及清空各项筛选后仍只查询监测账号作品', () => {
|
|
const render = createPage();
|
|
const date = { format: (pattern) => {
|
|
assert.equal(pattern, 'YYYY-MM-DD');
|
|
return '2026-05-18';
|
|
} };
|
|
const cases = [
|
|
['最低点赞', 'min_likes', 12, 12],
|
|
['最低评论', 'min_comments', 3, 3],
|
|
['最低转发', 'min_shares', 5, 5],
|
|
['全部状态', 'published_at_status', 'verified', 'verified'],
|
|
['发布开始日期', 'published_after', date, '2026-05-18T00:00:00Z'],
|
|
['发布结束日期', 'published_before', date, '2026-05-18T23:59:59Z'],
|
|
];
|
|
for (const [placeholder, key, value, expected] of cases) {
|
|
render().controls.find((control) => control.props.placeholder === placeholder).props.onChange(value);
|
|
assertCompetitorOnly(render().gallery);
|
|
assert.equal(render().gallery.extraFilters[key], expected);
|
|
}
|
|
for (const [placeholder, key] of cases) {
|
|
const clearValue = key === 'published_at_status' ? undefined : null;
|
|
render().controls.find((control) => control.props.placeholder === placeholder).props.onChange(clearValue);
|
|
assertCompetitorOnly(render().gallery);
|
|
assert.equal(render().gallery.extraFilters[key], undefined);
|
|
}
|
|
});
|