feat: publish verified five-bank question dataset
This commit is contained in:
+55
-4
@@ -42,9 +42,12 @@ test('multiple answer plan accepts every explicitly correct occurrence of repeat
|
||||
assert.deepEqual(planAnswer([subset], question, core).labels, ['A', 'D']);
|
||||
});
|
||||
|
||||
test('repeated text still skips partial answers, text-only answers, ID contradictions and duplicate labels', () => {
|
||||
test('repeated text skips partial answers without exact identities, text-only answers, ID contradictions and duplicate labels', () => {
|
||||
const question = repeatedMultiple({ answerStatus: 'missing', correctOptionIds: [], answerTexts: [] });
|
||||
assert.equal(planAnswer([repeatedMultiple({ correctOptionIds: ['b'], answerTexts: ['下降'] })], question, core).status, 'ambiguous');
|
||||
const partial = repeatedMultiple({ correctOptionIds: ['b'], answerTexts: ['下降'] });
|
||||
assert.equal(planAnswer([partial], question, core).status, 'ready');
|
||||
const fresh = { ...question, options: question.options.map(option => ({ ...option, id: `new-${option.id}` })) };
|
||||
assert.equal(planAnswer([partial], fresh, core).status, 'ambiguous');
|
||||
assert.equal(planAnswer([repeatedMultiple({ correctOptionIds: [], answerTexts: ['下降'] })], question, core).status, 'ambiguous');
|
||||
const changed = repeatedMultiple();
|
||||
[changed.options[0].id, changed.options[1].id] = [changed.options[1].id, changed.options[0].id];
|
||||
@@ -52,6 +55,36 @@ test('repeated text still skips partial answers, text-only answers, ID contradic
|
||||
question.options[3].label = 'B';
|
||||
assert.equal(planAnswer([repeatedMultiple()], question, core).status, 'ambiguous');
|
||||
});
|
||||
|
||||
function repeatedSingle(extra = {}) {
|
||||
return single({ options: [{ id: 'a', text: '其他产物甲', label: 'A' }, { id: 'b', text: '其他产物乙', label: 'B' },
|
||||
{ id: 'c', text: '生成Cu和Fe2+', label: 'C' }, { id: 'd', text: '生成Cu和Fe2+', label: 'D' }],
|
||||
correctOptionIds: ['c'], answerTexts: ['生成Cu和Fe2+'], ...extra });
|
||||
}
|
||||
|
||||
test('repeated single-choice text maps by complete exact option IDs after labels reorder', () => {
|
||||
const record = repeatedSingle();
|
||||
const question = repeatedSingle({ answerStatus: 'missing', correctOptionIds: [], answerTexts: [] });
|
||||
assert.deepEqual(planAnswer([record], question, core).labels, ['C']);
|
||||
question.options = [question.options[3], question.options[2], question.options[0], question.options[1]]
|
||||
.map((option, index) => ({ ...option, label: 'ABCD'[index] }));
|
||||
const plan = planAnswer([record], question, core);
|
||||
assert.equal(plan.status, 'ready');
|
||||
assert.deepEqual(plan.labels, ['B']);
|
||||
assert.deepEqual(plan.answerTexts, ['生成Cu和Fe2+']);
|
||||
});
|
||||
|
||||
test('repeated single-choice text remains ambiguous when full ID identity cannot be proved', () => {
|
||||
const record = repeatedSingle();
|
||||
const question = repeatedSingle({ answerStatus: 'missing', correctOptionIds: [], answerTexts: [] });
|
||||
const fresh = { ...question, options: question.options.map(option => ({ ...option, id: `new-${option.id}` })) };
|
||||
assert.equal(planAnswer([record], fresh, core).status, 'ambiguous');
|
||||
const missingID = { ...question, options: question.options.map(option => ({ ...option, id: option.id === 'a' ? '' : option.id })) };
|
||||
assert.equal(planAnswer([record], missingID, core).status, 'ambiguous');
|
||||
const changed = { ...question, options: question.options.map(option => ({ ...option, id: option.id === 'a' ? 'c' : option.id === 'c' ? 'a' : option.id })) };
|
||||
assert.equal(planAnswer([record], changed, core).status, 'ambiguous');
|
||||
assert.equal(planAnswer([repeatedSingle({ correctOptionIds: [] })], question, core).status, 'ambiguous');
|
||||
});
|
||||
test('judgement uses explicit correct and incorrect content, including zero ID', () => {
|
||||
const record = { bankId: 'j', type: 'judge', stem: '这项说法正确吗?', options: [{ id: '1', text: '正确' }, { id: '0', text: '错误' }], correctOptionIds: ['0'], answerStatus: 'confirmed' };
|
||||
const question = { ...record, options: [{ id: '0', text: '错误', label: '错误' }, { id: '1', text: '正确', label: '正确' }] };
|
||||
@@ -79,7 +112,8 @@ test('without bank identity, contradictory cross-bank matches are ambiguous', ()
|
||||
});
|
||||
test('different complete option sets, duplicate option text and wrong option IDs are refused', () => {
|
||||
assert.equal(planAnswer([single()], current({ options: [{ id: 'a', text: '降低温度' }, { id: 'b', text: '提高温度' }] }), core).status, 'missing');
|
||||
assert.equal(planAnswer([single()], current({ options: [{ text: '提高温度' }, { text: '提高温度' }] }), core).status, 'ambiguous');
|
||||
const duplicate = single({ options: [{ id: 'a', text: '提高温度' }, { id: 'b', text: '提高温度' }] });
|
||||
assert.equal(planAnswer([duplicate], current({ options: [{ text: '提高温度' }, { text: '提高温度' }] }), core).status, 'ambiguous');
|
||||
assert.equal(planAnswer([single()], current({ options: [{ id: 'b', text: '保持不变', label: 'A' }, { id: 'a', text: '降低温度', label: 'B' }, { id: 'c', text: '提高温度', label: 'C' }] }), core).status, 'ambiguous');
|
||||
});
|
||||
test('normalization preserves negatives, signs, units and superscripts', () => {
|
||||
@@ -141,13 +175,30 @@ test('automatic selection chooses all correct repeated checkboxes and clears an
|
||||
|
||||
test('automatic selection never clicks an ambiguous repeated-text subset', async () => {
|
||||
const page = checkboxPage({ texts: ['下降', '增加', '下降'] });
|
||||
page.record.correctOptionIds = ['0']; page.record.answerTexts = ['下降'];
|
||||
page.record.options.forEach(option => { option.id = `saved-${option.id}`; });
|
||||
page.record.correctOptionIds = ['saved-0']; page.record.answerTexts = ['下降'];
|
||||
const engine = create({ window: page.win, document: page.doc, core, getRecords: () => [page.record] });
|
||||
const result = await engine.answerCurrent();
|
||||
assert.equal(result.status, 'skipped'); assert.deepEqual(page.clicks, []);
|
||||
engine.destroy();
|
||||
});
|
||||
|
||||
test('single-choice clicks the correct repeated option only with complete exact IDs', async () => {
|
||||
for (const freshIDs of [false, true]) {
|
||||
const page = checkboxPage({ texts: ['其他产物甲', '其他产物乙', '生成Cu和Fe2+', '生成Cu和Fe2+'] });
|
||||
page.inputs.forEach(input => { input.type = 'radio'; });
|
||||
page.record.type = 'single';
|
||||
if (freshIDs) page.record.options.forEach(option => { option.id = `saved-${option.id}`; });
|
||||
page.record.correctOptionIds = [freshIDs ? 'saved-2' : '2']; page.record.answerTexts = ['生成Cu和Fe2+'];
|
||||
const engine = create({ window: page.win, document: page.doc, core, getRecords: () => [page.record] });
|
||||
const result = await engine.answerCurrent();
|
||||
assert.equal(result.status, freshIDs ? 'skipped' : 'answered');
|
||||
assert.deepEqual(page.clicks, freshIDs ? [] : [2]);
|
||||
assert.deepEqual(page.inputs.map(input => input.checked), freshIDs ? [false, false, false, false] : [false, false, true, false]);
|
||||
engine.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
test('automatic selection reads image stems and choices consistently with network records', async () => {
|
||||
const { extractQuestions } = require('../src/adapter.js');
|
||||
for (const richLabels of [false, true]) {
|
||||
|
||||
Reference in New Issue
Block a user