Files
WeReadBoard/tests/goals_frontend.test.cjs
T

72 lines
3.2 KiB
JavaScript

const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const vm = require('node:vm');
function app() {
const nodes = new Map();
const node = selector => {
if (!nodes.has(selector)) nodes.set(selector, {
value: '', textContent: '', innerHTML: '', disabled: false,
classList: { add() {}, remove() {}, toggle() {} },
setAttribute() {}, addEventListener() {}, setCustomValidity() {}, reportValidity() {},
showModal() { this.open = true; }, close() { this.open = false; },
});
return nodes.get(selector);
};
const pending = () => new Promise(() => {});
const context = vm.createContext({
document: { querySelector: node, querySelectorAll: () => [], addEventListener() {}, documentElement: { dataset: {} } },
localStorage: { getItem: () => null },
WeApi: { status: pending, shelf: pending, dashboard: pending, goals: pending },
crypto: { randomUUID: () => 'test-goal' },
setTimeout() {}, clearTimeout() {}, console,
});
vm.runInContext(fs.readFileSync('static/js/app.js', 'utf8'), context);
return { context, node, run: code => vm.runInContext(code, context) };
}
test('目标书籍不在当前书架时仍保留总数,并可打开和编辑', () => {
const { run, node } = app();
run(`loadState.goals = 'ready';
books = [{id:'known',title:'已读书',status:'done'}];
goals = [{id:'g',name:'阅读',start:'2026-09-01',end:'2026-09-30',ids:['known','missing'],sources:[]}];
shelfData = {};`);
assert.equal(run('goalMetrics(goals[0]).total'), 2);
assert.equal(run('goalMetrics(goals[0]).percent'), 50);
run("openGoalDetail('g'); openGoalEditor('g');");
assert.match(node('#goal-picker').innerHTML, /状态待同步/);
assert.equal(run("selectedGoalBooks().includes('missing')"), true);
});
test('数据库保存失败时保留原目标和编辑草稿,允许重试', async () => {
const { context, run, node } = app();
run(`loadState.goals = 'ready';
shelfData = {}; books = [{id:'known',title:'一本书',status:'done'}];
goals = [{id:'g',name:'原名称',start:'2026-09-01',end:'2026-09-30',ids:['known'],sources:[]}];
openGoalEditor('g');`);
node('#goal-name').value = '新名称';
context.WeApi.saveGoal = async () => { throw new Error('数据库暂不可用'); };
await run('saveGoal({preventDefault(){}})');
assert.equal(run('goals[0].name'), '原名称');
assert.equal(node('#goal-editor').open, true);
assert.equal(node('#goal-name').value, '新名称');
assert.match(node('#goal-error').textContent, /数据库暂不可用/);
context.WeApi.saveGoal = async goal => ({ goal });
await run('saveGoal({preventDefault(){}})');
assert.equal(run('goals[0].name'), '新名称');
assert.equal(node('#goal-editor').open, false);
});
test('目标列表未完成加载时不打开编辑器', () => {
const { run, node } = app();
run(`page = 'overview';
loadState.goals = 'loading';
shelfData = {};
books = [{id:'known',title:'一本书',status:'done'}];
openGoalEditor(null, ['known'], []);`);
assert.notEqual(node('#goal-editor').open, true);
assert.equal(run('page'), 'goals');
assert.match(node('#page-content').innerHTML, /正在读取阅读目标/);
});