fix: deduplicate practice snapshots and compact white panel
This commit is contained in:
+94
-3
@@ -183,7 +183,7 @@ function bankPage(fetchImpl) {
|
||||
page.win.addEventListener = events.addEventListener.bind(events);
|
||||
page.win.removeEventListener = events.removeEventListener.bind(events);
|
||||
page.win.dispatchEvent = events.dispatchEvent.bind(events);
|
||||
const state = { sidebar: '判断题库1', player: '判断题库1', exam: '判断题库1', taskId: 'task-a', containerTask: 'task-a', stem: '升温时应选择?', form: true };
|
||||
const state = { sidebar: '判断题库1', player: '判断题库1', exam: '判断题库1', taskId: 'task-a', containerTask: 'task-a', stem: '升温时应选择?', form: true, questionNumber: 1, progress: '' };
|
||||
page.win.location.href = 'https://www.shhuayi-elearning.cn/o2o/#/playinfo?taskId=task-a';
|
||||
page.doc.title = '不会随切换更新的旧标题';
|
||||
const item = { getAttribute: key => key === 'data-task-id' ? state.taskId : null };
|
||||
@@ -201,7 +201,7 @@ function bankPage(fetchImpl) {
|
||||
get textContent() { return state.stem + options.map(option => option.textContent).join(''); },
|
||||
closest: selector => selector === ROOT_SELECTOR_FOR_TEST ? main : null,
|
||||
getAttribute: () => null, style: {},
|
||||
querySelector: selector => selector === '.yxtulcdsdk-form__content' ? { children: [stem] } : null,
|
||||
querySelector: selector => selector === '.yxtulcdsdk-form__content' ? { children: [stem] } : selector === '.yxtulcdsdk-form__sub' ? { textContent: `${state.questionNumber}.` } : null,
|
||||
querySelectorAll: () => options
|
||||
};
|
||||
page.doc.querySelector = selector => {
|
||||
@@ -209,6 +209,7 @@ function bankPage(fetchImpl) {
|
||||
if (selector === 'header.o2oPlayFrame-right .title .yxtf-tooltip') return state.player ? player : null;
|
||||
if (selector === '.yxtulcdsdk-exam-header .yxtf-tooltip') return state.exam ? exam : null;
|
||||
if (selector === '.yxtulcdsdk-exam-container[task-id]') return container;
|
||||
if (selector === '.yxtulcdsdk-answer-card__top') return state.progress ? { textContent: state.progress } : null;
|
||||
return null;
|
||||
};
|
||||
page.doc.querySelectorAll = selector => selector === '.yxtulcdsdk-pc-marking-main .yxtulcdsdk-form' && state.form ? [form] : [];
|
||||
@@ -343,7 +344,7 @@ test('ordinary pages do not observe requests, capture questions or intercept cop
|
||||
assert.equal(adapter.isSupportedPage(), false);
|
||||
assert.equal(adapter.getCurrentQuestion(), null);
|
||||
assert.equal(adapter.captureCurrent(), null);
|
||||
assert.deepEqual(adapter.getCurrentBank(), { bankId: '', bankName: '', taskId: '', loading: false });
|
||||
assert.deepEqual(adapter.getCurrentBank(), { bankId: '', bankName: '', taskId: '', loading: false, questionCount: null });
|
||||
await page.win.fetch('/upm/start?praId=not-a-bank');
|
||||
const xhr = new page.win.XMLHttpRequest();
|
||||
xhr.open('GET', '/upm/start?praId=not-a-bank'); xhr.send(); xhr.respond({ listQues: [single()] });
|
||||
@@ -408,3 +409,93 @@ test('a lookalike hostname is not treated as the supported learning platform', (
|
||||
assert.equal(adapter.getCurrentQuestion(), null);
|
||||
adapter.stop();
|
||||
});
|
||||
|
||||
test('complete snapshots retain repeated content positions and share one batch timestamp', () => {
|
||||
const raw = { praId: 'p1', listQues: [single(), { ...single(), id: 'q2' }, { id: 'j1', quesType: 2, content: '判断示例', judgeAnswer: 0 }] };
|
||||
const records = extractQuestions(raw, { batchId: 'batch-a', observedAt: '2026-10-29T09:52:46.000Z' });
|
||||
assert.equal(records.length, 3, '同批次的两道相同题干是合法两题,不能按内容折成一题');
|
||||
assert.deepEqual(records.map(q => q.questionIndex), [0, 1, 2]);
|
||||
assert.deepEqual(records.map(q => q.contentOccurrence), [0, 1, 0]);
|
||||
assert.equal(new Set(records.map(q => q.source.observedAt)).size, 1);
|
||||
assert.equal(new Set(records.map(q => q.source.batchId)).size, 1);
|
||||
});
|
||||
|
||||
test('listQues uses the ID submitted by the real practice client, not wrapper identities', () => {
|
||||
const [record] = extractQuestions({ id: 'list-wrapper', quesType: 2, content: '容器说明', listQues: [{ ...single(), id: 'practice-row-id', quesId: 'bank-item-id', questionId: 'other-wrapper-id' }] });
|
||||
assert.equal(record.questionId, 'practice-row-id');
|
||||
assert.equal(record.stem, '升温时应选择?');
|
||||
});
|
||||
|
||||
test('single answer receipts inherit request identity and snapshot occurrence metadata', () => {
|
||||
const [known] = extractQuestions({ praId: 'p1', listQues: [single()] }, { batchId: 'first-snapshot', observedAt: '2026-10-29T09:52:46.000Z' });
|
||||
const [answer] = extractQuestions({ id: 'answer-receipt-uuid', answers: ['a2'], explainText: '标准解析' }, {
|
||||
answerResponse: true, questionId: 'q1', bankId: 'p1', knownQuestions: [known], batchId: 'answer-response'
|
||||
});
|
||||
assert.equal(answer.questionId, 'q1');
|
||||
assert.equal(answer.questionIndex, 0);
|
||||
assert.equal(answer.contentOccurrence, 0);
|
||||
assert.equal(answer.source.batchId, 'first-snapshot');
|
||||
assert.equal(answer.answerStatus, 'confirmed');
|
||||
assert.deepEqual(extractQuestions({ id: 'receipt', quesType: 0, content: '完全不同的题干', choiceItems: single().choiceItems }, {
|
||||
answerResponse: true, questionId: 'q1', bankId: 'p1', knownQuestions: [known]
|
||||
}), [], '不能将另一题正文拼到请求中的题目ID');
|
||||
});
|
||||
|
||||
test('the displayed progress total is available and never carried through a bank transition', () => {
|
||||
const page = bankPage();
|
||||
page.state.progress = '进度27/232';
|
||||
assert.equal(page.adapter.getCurrentBank().questionCount, 232);
|
||||
page.navigate('单选题库1', 'task-b');
|
||||
assert.equal(page.adapter.getCurrentBank().questionCount, null, '切库途中旧卡片232不能归入新库');
|
||||
page.state.player = page.state.exam = '单选题库1'; page.state.containerTask = 'task-b'; page.state.stem = '新题?'; page.state.progress = '进度0/500';
|
||||
assert.equal(page.adapter.getCurrentBank().questionCount, 500);
|
||||
page.state.progress = '';
|
||||
assert.equal(page.adapter.getCurrentBank().questionCount, null);
|
||||
page.state.progress = '进度233/232';
|
||||
assert.equal(page.adapter.getCurrentBank().questionCount, null, '畸形进度不作为总题数');
|
||||
});
|
||||
|
||||
test('network snapshots know 232 questions, and late old-bank totals cannot replace the current count', async () => {
|
||||
const pending = new Map();
|
||||
const page = bankPage(url => new Promise(resolve => pending.set(url, resolve)));
|
||||
page.adapter.start();
|
||||
const first = page.win.fetch('/upm/start?praId=bank-a');
|
||||
page.navigate('单选题库1', 'task-b');
|
||||
page.state.player = page.state.exam = '单选题库1'; page.state.containerTask = 'task-b'; page.state.stem = '新题?';
|
||||
const second = page.win.fetch('/upm/start?praId=bank-b');
|
||||
const response = (size, prefix) => new Response(JSON.stringify({ listQues: Array.from({ length: size }, (_, i) => ({ ...single(), id: `${prefix}-${i}`, content: `合成题目${i}` })) }), { headers: { 'content-type': 'application/json' } });
|
||||
pending.get('/upm/start?praId=bank-b')(response(232, 'new'));
|
||||
await second; await flush(); await flush();
|
||||
assert.equal(page.adapter.getCurrentBank().questionCount, 232);
|
||||
pending.get('/upm/start?praId=bank-a')(response(500, 'old'));
|
||||
await first; await flush(); await flush();
|
||||
assert.equal(page.adapter.getCurrentBank().questionCount, 232);
|
||||
const batch = page.received.filter(q => q.bankId === 'bank-b');
|
||||
assert.equal(batch.length, 232);
|
||||
assert.equal(new Set(batch.map(q => q.source.batchId)).size, 1);
|
||||
assert.equal(new Set(batch.map(q => q.source.observedAt)).size, 1);
|
||||
page.adapter.stop();
|
||||
});
|
||||
|
||||
test('DOM question number distinguishes legitimate identical items in the latest snapshot', async () => {
|
||||
let prefix = 'old';
|
||||
const page = bankPage(async () => new Response(JSON.stringify({ listQues: [
|
||||
{ ...single(), id: `${prefix}-first` }, { ...single(), id: `${prefix}-second` }
|
||||
] }), { headers: { 'content-type': 'application/json' } }));
|
||||
page.adapter.start();
|
||||
await page.win.fetch('/upm/start?praId=bank-a'); await flush(); await flush();
|
||||
page.state.questionNumber = 2;
|
||||
const first = page.adapter.getCurrentQuestion();
|
||||
assert.equal(first.questionId, 'old-second');
|
||||
assert.equal(first.questionIndex, 1);
|
||||
assert.equal(first.contentOccurrence, 1);
|
||||
prefix = 'new';
|
||||
await page.win.fetch('/upm/start?praId=bank-a'); await flush(); await flush();
|
||||
const second = page.adapter.getCurrentQuestion();
|
||||
assert.equal(second.questionId, 'new-second', '刷新完整列表后不再与旧批次的UUID混合匹配');
|
||||
assert.equal(second.contentOccurrence, 1);
|
||||
assert.notEqual(second.source.batchId, first.source.batchId);
|
||||
page.state.questionNumber = 3;
|
||||
assert.equal(page.adapter.getCurrentQuestion(), null, '题号与已加载完整列表不一致时应等待页面同步');
|
||||
page.adapter.stop();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user