From 020712dfbdd1f1fa577f48841679a24c5dac4bb1 Mon Sep 17 00:00:00 2001 From: weichen Date: Sun, 13 Sep 2026 14:07:41 +0000 Subject: [PATCH] fix(e2e): UI-11 send upload to register freeform doc-free Chip assert after setInputFiles, wait POST /freeform-documents 2xx on send, then pin doc-free pane id and drain this-turn assistant before leaving UI-11. Co-authored-by: Cursor --- web/e2e/document-revision-runtime.spec.ts | 41 ++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/web/e2e/document-revision-runtime.spec.ts b/web/e2e/document-revision-runtime.spec.ts index bece3cbc..2271cbb9 100644 --- a/web/e2e/document-revision-runtime.spec.ts +++ b/web/e2e/document-revision-runtime.spec.ts @@ -870,27 +870,60 @@ test.describe.serial('document-revision-runtime UI acceptance', () => { const { v, r } = await readVersionBadge(page); states.push(`${target.title}:${v}/${r}`); } - // Page upload attachment — assert registered doc-free id on pane (ignore any chat assistant side effects). + // Page upload: chip draft → send → POST /api/v1/freeform-documents → doc-free pane. const fileInput = page.locator('input[type="file"]'); if ((await fileInput.count()) === 0) fail('no file input for page upload'); const tmp = path.join(ASSETS, `upload-${suffix}.txt`); + const uploadName = `upload-${suffix}.txt`; fs.writeFileSync(tmp, `attachment ${suffix}\n`, 'utf-8'); await fileInput.first().setInputFiles(tmp); + await expect( + page.getByText(uploadName, { exact: false }).or(page.getByText(`upload-${suffix}`, { exact: false })), + ).toBeVisible({ timeout: 15_000 }); + + const archivePrompt = '请将此附件归档为我的私密参考文档。'; + const freeformWait = page.waitForResponse( + (r) => { + const pathOnly = sanitizeUrl(r.url()); + return ( + r.request().method() === 'POST' && + pathOnly.includes('/api/v1/freeform-documents') && + !pathOnly.includes('/from-message') + ); + }, + { timeout: 60_000 }, + ); + const box = page.getByPlaceholder(/向项目助手提问/); + await expect(box).toBeVisible({ timeout: 15_000 }); + // 附件允许空文本;填归档句以便本轮 assistant 可定位并收口终态。 + await box.fill(archivePrompt); + await page.getByRole('button', { name: /发送/ }).click(); + + const freeformRes = await freeformWait; + const freeformStatus = freeformRes.status(); + if (freeformStatus < 200 || freeformStatus >= 300) { + fail(`UI-11 POST /api/v1/freeform-documents must be 2xx, got HTTP ${freeformStatus}`); + } + const pane = page.getByTestId('active-document-pane'); await expect(pane).toHaveAttribute('data-doc-id', /^doc-free-/, { timeout: 45_000 }); uploadedDocId = (await pane.getAttribute('data-doc-id')) || ''; if (!uploadedDocId.startsWith('doc-free-')) { fail(`UI-11 upload must activate doc-free-* pane, got ${uploadedDocId}`); } - if (uploadedDocId.startsWith('doc-upload')) { + if (uploadedDocId.includes('doc-upload')) { fail(`UI-11 must not leave doc-upload orphan active: ${uploadedDocId}`); } + + // 发送会拉起普通 assistant:离开 UI-11 前等本轮终态,避免污染 UI-12+。 + await waitForSquadCompletion(page, '请将此附件归档', 180_000); + await shot(page, 'UI-11-multi-doc.png'); recordPass({ id: 'UI-11', name: 'multi doc + upload', - input: 'chat second doc; upload file', - actual: `${states.join('; ')}; uploadedDocId=${uploadedDocId}`, + input: 'chat second doc; upload file + send for freeform register', + actual: `${states.join('; ')}; freeform HTTP ${freeformStatus}; uploadedDocId=${uploadedDocId}`, networkLogs: logs, durationMs: Date.now() - t0, verdict: 'PASS',