Align document render workspace with real RDM server payloads

Why: Independent review of a81e94a..85428b4 found five contract mismatches
against the RDM server: profile sources document-type/project-default were
dropped, the refusal object {code,message} was ignored, submit receipts were
read as `id` instead of `submissionId`, diagnostics were expected inside
preview/export receipts (they live in a separate diagnostics delivery blob),
and rdm.inspect.tree was treated as recursive although it returns one level.

Evidence: New tests use the server JSON shapes (RenderProfileOptions,
RenderDeliveryReceipt, DocSubmissionRec, rdmRenderDownload, InspectTree); 26
of them fail against the previous implementation. npx vitest run: 35 files,
359 tests passed; npm run build: ok; scripts/check-knip.mjs: unused exports
43 <= 43; git diff --cached --check: clean.

Impact: Rules panel lists all five sources with Chinese labels and keeps the
server's selected default; refusals render readably; a new submission is
auto-selected; diagnostics are fetched via rdm.render.download kind=diagnostics
under a sequence/epoch guard with readable failures and a Chinese receipt
state label; the document tree is walked breadth-first (depth 12, 2000 nodes,
concurrency 4) with a truncation notice. Playwright spec asserts per-node
diagnostic anchors after preview (authored, not run).

Refs: unified renderer plan Task 11 review findings
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
weichen
2026-10-16 01:29:13 +00:00
co-authored by Cursor
parent 85428b4633
commit de65026238
4 changed files with 505 additions and 71 deletions
+29 -9
View File
@@ -101,11 +101,11 @@ test.describe.serial('统一渲染 Task 11 文档阅读与交付', () => {
.toBeVisible({ timeout: 10_000 })
await expectReadableFailures(page)
for (const option of await rules.locator('.drw-profile').all()) {
await expect(option.locator('.drw-profile-source')).toHaveText(/文档规则|项目规则|模板规则|公司默认规则/)
await expect(option.locator('.drw-profile-source')).toHaveText(/^(文档规则|文档类型规则|模板规则|项目默认规则|公司默认规则)$/)
await expect(option.locator('.drw-profile-ver')).toHaveText(/^v.+/)
if (await option.locator('input[disabled]').count()) await expect(option.locator('.drw-profile-reason')).not.toBeEmpty()
}
if (await rules.locator('.drw-notice').count()) await expect(rules.locator('.drw-notice')).toContainText('不会回退到公司默认规则')
if (await rules.locator('.drw-notice').count()) await expect(rules.locator('.drw-notice')).toContainText('不会回退到项目或公司默认规则')
})
test('生成预览:状态与诊断可见,点击诊断选中对应节点', async ({ page }) => {
@@ -116,18 +116,38 @@ test.describe.serial('统一渲染 Task 11 文档阅读与交付', () => {
test.skip(await generate.isDisabled(), '无可预览规则')
await generate.click()
const preview = panel(page, '预览与提交')
await expect(preview.locator('.drw-receipt').or(preview.locator('.drw-failure')).first()).toBeVisible({ timeout: 30_000 })
await expect(preview.locator('.drw-receipt').or(preview.locator('.drw-op .drw-failure')).first()).toBeVisible({ timeout: 30_000 })
await expectReadableFailures(page)
if (await preview.locator('.drw-failure').count()) {
if (await preview.locator('.drw-op .drw-failure').count()) {
await expect(preview.getByRole('button', { name: '重试' })).toBeVisible()
return
}
const located = preview.locator('button.drw-diag-node').first()
if (await located.count()) {
const title = await located.getAttribute('title')
const receipt = preview.locator('.drw-receipt')
await expect(receipt.locator('.ui-chip').first()).toHaveText(/^(已生成|生成中|排队中|生成失败|已取消|状态未知)$/)
// 诊断不在生成回执里:必须另行下载 diagnostics 后才出现(读取中 → 列表 / 无问题 / 可读失败)。
await expect(receipt.getByText('诊断读取中')).toHaveCount(0, { timeout: 30_000 })
await expect(receipt.locator('.drw-diags').or(receipt.getByText('没有诊断问题')).or(receipt.locator('.drw-failure')).first()).toBeVisible()
await expectReadableFailures(page)
// 错误/警告定位到节点:每个锚点都对应画布上带计数徽标的同名节点(提示级不计徽标)。
const counted = receipt.locator('.drw-diag.sev-error button.drw-diag-node, .drw-diag.sev-warning button.drw-diag-node')
const countedTotal = await counted.count()
for (let i = 0; i < Math.min(countedTotal, 5); i++) {
const title = (await counted.nth(i).getAttribute('title')) ?? ''
expect(title).not.toBe('')
await expect(page.locator(`.drw-canvas-node[title="${title.replace(/"/g, '\\"')}"] .drw-badge`).first()).toBeVisible()
}
const anchors = receipt.locator('button.drw-diag-node')
if (await anchors.count()) {
const located = countedTotal ? counted.first() : anchors.first()
const title = (await located.getAttribute('title')) ?? ''
await located.click()
await expect(page.locator('.drw-canvas-node[aria-selected="true"], .drw-reader-title[aria-current="true"]').first())
.toContainText(title ?? '')
await expect(page.locator('.drw-canvas-node[aria-selected="true"]')).toHaveAttribute('title', title)
await page.getByRole('tab', { name: '阅读视图' }).click()
const section = page.locator('section.drw-reader-node.sel')
await expect(section).toHaveAttribute('id', /^drw-node-/)
await expect(section.locator('.drw-reader-title')).toHaveText(title)
if (countedTotal) await expect(section.locator('.drw-badge').first()).toBeVisible()
await expect(section.locator('a.drw-anchor')).toHaveAttribute('href', `#${await section.getAttribute('id')}`)
}
await expect(page.locator('.drw-delivery').first()).toBeVisible({ timeout: 15_000 })
})