Skip to content

Commit cec71c7

Browse files
committed
test: 批次入库测试按草稿顺序取错题,修复偶发失败
同一批次的题目并发保存,createdAt 可能相同,按创建时间排序后用下标断言会偶发失败; 改为按草稿题目顺序经任务关联取出错题。
1 parent b8b70ce commit cec71c7

1 file changed

Lines changed: 18 additions & 7 deletions

File tree

‎src/__tests__/integration/import-batches.test.ts‎

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,17 @@ async function getBatch(id: string, image = false) {
100100
return { response, batch: (await response.json()).batch };
101101
}
102102
const start = (id: string, body: Record<string, unknown>) => START(json(body), params(id));
103+
/** 按草稿中的题目顺序取出入库的错题(并发保存时 createdAt 可能相同,不能据此排序) */
104+
async function savedItemsInDraftOrder(batchId: string) {
105+
const batch = await database.importBatch.findUniqueOrThrow({ where: { id: batchId }, select: { draft: true } });
106+
const keys = (JSON.parse(batch.draft ?? '{"items":[]}') as { items: { key: string }[] }).items.map((item) => item.key);
107+
const tasks = await database.importTask.findMany({ where: { batchId }, select: { batchItemKey: true, errorItemId: true } });
108+
const ids = keys
109+
.map((key) => tasks.find((task) => task.batchItemKey === key)?.errorItemId)
110+
.filter((id): id is string => !!id);
111+
const items = await database.errorItem.findMany({ where: { id: { in: ids } } });
112+
return ids.map((id) => items.find((item) => item.id === id)!);
113+
}
103114
const waitSplit = async (id: string) => {
104115
await waitForImportTaskForTest(id);
105116
};
@@ -201,7 +212,7 @@ describe('文字多题批次', () => {
201212
expect(await database.importTask.count({ where: { batchId: batch.id } })).toBe(8);
202213
expect(mocks.reanswerQuestion).toHaveBeenCalledTimes(8);
203214
expect(await database.aiUsage.count({ where: { kind: 'reanswer' } })).toBe(8);
204-
const items = await database.errorItem.findMany({ orderBy: { createdAt: 'asc' } });
215+
const items = await savedItemsInDraftOrder(batch.id);
205216
expect(items).toHaveLength(8);
206217
expect(items.every((item) => item.subjectId === 'math' && item.userId === 'user-1')).toBe(true);
207218
expect(items.map((item) => item.questionText)).toContain(draft.items[0].text);
@@ -737,7 +748,7 @@ describe('AI 只补标签(analysis=tags)', () => {
737748
expect(mocks.analyzeImage).not.toHaveBeenCalled();
738749
expect(await database.aiUsage.count({ where: { kind: 'retag' } })).toBe(2);
739750

740-
const items = await database.errorItem.findMany({ orderBy: { createdAt: 'asc' } });
751+
const items = await savedItemsInDraftOrder(batch.id);
741752
expect(items).toHaveLength(2);
742753
// 草稿答案解析保留
743754
expect(items[0].answerText).toBe('2');
@@ -814,7 +825,7 @@ describe('AI 只补标签(analysis=tags)', () => {
814825
expect(mocks.suggestKnowledgeTags).toHaveBeenCalledTimes(2);
815826
const { batch: current } = await getBatch(batch.id);
816827
expect(current).toMatchObject({ phase: 'done', counts: { saved: 2, failed: 0 } });
817-
const items = await database.errorItem.findMany({ orderBy: { createdAt: 'asc' } });
828+
const items = await savedItemsInDraftOrder(batch.id);
818829
expect(items).toHaveLength(2);
819830
expect(items[0].answerText).toBe('2');
820831
expect(items[1].answerText).toBe('4');
@@ -902,7 +913,7 @@ describe('按原样入库(analysis=none)', () => {
902913
expect(mocks.analyzeImage).not.toHaveBeenCalled();
903914
expect(await database.aiUsage.count()).toBe(0);
904915

905-
const items = await database.errorItem.findMany({ orderBy: { createdAt: 'asc' } });
916+
const items = await savedItemsInDraftOrder(batch.id);
906917
expect(items).toHaveLength(2);
907918
expect(items.every((item) => item.subjectId === 'math' && item.userId === 'user-1')).toBe(true);
908919
expect(items[0].questionText).toContain('计算 1 + 1');
@@ -919,7 +930,7 @@ describe('按原样入库(analysis=none)', () => {
919930
await start(batch.id, { version: batch.version, analysis: 'none' });
920931
await waitForImportBatchTasksForTest(batch.id);
921932

922-
const items = await database.errorItem.findMany({ orderBy: { createdAt: 'asc' } });
933+
const items = await savedItemsInDraftOrder(batch.id);
923934
expect(items).toHaveLength(2);
924935
expect(items[0].questionText).toContain('某商店上午卖出 30 件');
925936
expect(items[0].questionText).toContain('全天卖出多少件');
@@ -1030,7 +1041,7 @@ describe('按原样入库(analysis=none)', () => {
10301041
await start(batch.id, { version: batch.version, analysis: 'none' });
10311042
await waitForImportBatchTasksForTest(batch.id);
10321043

1033-
const items = await database.errorItem.findMany({ orderBy: { createdAt: 'asc' } });
1044+
const items = await savedItemsInDraftOrder(batch.id);
10341045
expect(items).toHaveLength(2);
10351046
// 第一题无答案:占位空格还原为空串
10361047
expect(items[0].answerText).toBe('');
@@ -1056,7 +1067,7 @@ describe('按原样入库(analysis=none)', () => {
10561067
expect(started.status).toBe(202);
10571068
await waitForImportBatchTasksForTest(batch.id);
10581069

1059-
const items = await database.errorItem.findMany({ orderBy: { createdAt: 'asc' } });
1070+
const items = await savedItemsInDraftOrder(batch.id);
10601071
expect(items).toHaveLength(2);
10611072
expect(items[0].originalImageUrl).toBe(imageData);
10621073
expect(items[1].originalImageUrl).toBe('');

0 commit comments

Comments
 (0)