test(web): run the subagent-conversation e2e against the locale-aware copy

The ui-subagent catalog and read-only composer copy moved from hardcoded
Chinese to the locale-aware `subagent` namespace, so an en-US headless
browser now renders English. The e2e's selectors and goldens still
asserted the old hardcoded Chinese strings, leaving the scenario unable
to find the catalog trigger.

Convert the selectors to the default (en-US) render and re-record the
catalog goldens (ui, tree, nested) in English. The locale-aware parts of
the remaining goldens were already English (recorded under the en-US
default), so sidebar and fork are untouched.
This commit is contained in:
Tianyi Cui
2026-08-02 13:36:54 +08:00
parent daf9554804
commit 5c98cbd8f6
4 changed files with 30 additions and 30 deletions

View File

@@ -14,5 +14,5 @@
- button "Branch into a new conversation": - button "Branch into a new conversation":
- img - img
- status: - status:
- strong: 此子代理暂时只读 - strong: This subagent is read-only for now
- text: 父会话当前不在线,重新打开父会话后即可继续发送消息。 - text: The parent session is offline; reopen it to continue sending messages.

View File

@@ -1,8 +1,8 @@
- tree "子代理会话": - tree "Subagent sessions":
- treeitem "event-sourcing researcher Explain event sourcing in one · 可继续 · 当前未运行 刚刚" [expanded] [level=1]: - treeitem "event-sourcing researcher Explain event sourcing in one · continuable · not running just now" [expanded] [level=1]:
- button "收起 event-sourcing researcher 的下级子代理": - button "Collapse event-sourcing researcher descendants":
- img - img
- text: event-sourcing researcher Explain event sourcing in one · 可继续 · 当前未运行 刚刚 - text: event-sourcing researcher Explain event sourcing in one · continuable · not running just now
- group: - group:
- treeitem "example editor 可继续 · 当前未运行 刚刚" [level=2] - treeitem "example editor continuable · not running just now" [level=2]
- treeitem "event-sourcing reviewer 一次性 · 当前未运行 刚刚" [level=1] - treeitem "event-sourcing reviewer one-shot · not running just now" [level=1]

View File

@@ -3,8 +3,8 @@
- button "Ask a research subagent to" - button "Ask a research subagent to"
- text: / - text: /
- button "event-sourcing researcher" [disabled] - button "event-sourcing researcher" [disabled]
- button "1 个子代理": - button "1 subagents":
- text: 1 个子代理 - text: 1 subagents
- img - img
- tablist: - tablist:
- tab "Chat" [selected] - tab "Chat" [selected]

View File

@@ -217,13 +217,13 @@ describe('web e2e: persisted subagent conversation and human continuation', () =
const warningStart = tripwire.warnings.length const warningStart = tripwire.warnings.length
await page.reload({ waitUntil: 'load' }) await page.reload({ waitUntil: 'load' })
await page.waitForSelector('[class*="frame"]', { timeout: 30_000 }) await page.waitForSelector('[class*="frame"]', { timeout: 30_000 })
const catalogButton = page.getByRole('button', { name: /个子代理/ }) const catalogButton = page.getByRole('button', { name: /subagents/ })
await catalogButton.waitFor({ timeout: 15_000 }) await catalogButton.waitFor({ timeout: 15_000 })
await catalogButton.click() await catalogButton.click()
const catalogTree = page.getByRole('tree', { name: '子代理会话' }) const catalogTree = page.getByRole('tree', { name: 'Subagent sessions' })
await catalogTree.getByRole('treeitem').nth(1).waitFor({ timeout: 15_000 }) await catalogTree.getByRole('treeitem').nth(1).waitFor({ timeout: 15_000 })
await catalogTree.press('Escape') await catalogTree.press('Escape')
await page.getByRole('button', { name: '3 个子代理' }).waitFor({ timeout: 15_000 }) await page.getByRole('button', { name: '3 subagents' }).waitFor({ timeout: 15_000 })
acknowledgeReloadConnectionLoss(tripwire, warningStart) acknowledgeReloadConnectionLoss(tripwire, warningStart)
}, 120_000) }, 120_000)
@@ -241,26 +241,26 @@ describe('web e2e: persisted subagent conversation and human continuation', () =
it('expands a persisted grandchild progressively without activating either level', async () => { it('expands a persisted grandchild progressively without activating either level', async () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-tree')) onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-tree'))
await page.getByRole('button', { name: '3 个子代理' }).click() await page.getByRole('button', { name: '3 subagents' }).click()
expect(await page.getByRole('button', { expect(await page.getByRole('button', {
name: `展开 ${ONE_SHOT_LABEL} 的下级子代理`, name: `Expand ${ONE_SHOT_LABEL} descendants`,
}).count()).toBe(0) }).count()).toBe(0)
await page.getByRole('button', { name: `展开 ${LABEL} 的下级子代理` }).click() await page.getByRole('button', { name: `Expand ${LABEL} descendants` }).click()
await page.getByRole('treeitem', { name: new RegExp(NESTED_LABEL) }).waitFor({ timeout: 15_000 }) await page.getByRole('treeitem', { name: new RegExp(NESTED_LABEL) }).waitFor({ timeout: 15_000 })
expect(scaffold.ctx.agents.get(childId)).toBeUndefined() expect(scaffold.ctx.agents.get(childId)).toBeUndefined()
expect(scaffold.ctx.agents.get(grandchildId)).toBeUndefined() expect(scaffold.ctx.agents.get(grandchildId)).toBeUndefined()
const snapshot = await captureStableAria( const snapshot = await captureStableAria(
page, page,
'[role="tree"][aria-label="子代理会话"]', '[role="tree"][aria-label="Subagent sessions"]',
scaffold.workspaceCwd, scaffold.workspaceCwd,
) )
await compareOrRefreshGolden(TREE_EXPECTED, snapshot, MODE) await compareOrRefreshGolden(TREE_EXPECTED, snapshot, MODE)
await page.getByRole('tree', { name: '子代理会话' }).press('Escape') await page.getByRole('tree', { name: 'Subagent sessions' }).press('Escape')
}) })
it('opens the completed child from persistence without activating it', async () => { it('opens the completed child from persistence without activating it', async () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-open')) onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-open'))
await page.getByRole('button', { name: '3 个子代理' }).click() await page.getByRole('button', { name: '3 subagents' }).click()
await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click()
await expect.poll( await expect.poll(
() => page.getByText(INITIAL_PROMPT, { exact: true }).count(), () => page.getByText(INITIAL_PROMPT, { exact: true }).count(),
@@ -302,18 +302,18 @@ describe('web e2e: persisted subagent conversation and human continuation', () =
).toBe('running') ).toBe('running')
const hierarchy = page.getByRole('navigation', { name: 'Session hierarchy' }) const hierarchy = page.getByRole('navigation', { name: 'Session hierarchy' })
await hierarchy.getByRole('button').first().click() await hierarchy.getByRole('button').first().click()
const runningTrigger = page.getByRole('button', { name: '3 个子代理,正在运行' }) const runningTrigger = page.getByRole('button', { name: '3 subagents running' })
await runningTrigger.waitFor({ timeout: 10_000 }) await runningTrigger.waitFor({ timeout: 10_000 })
expect(await runningTrigger.locator('[data-state="ongoing"]').count()).toBe(1) expect(await runningTrigger.locator('[data-state="ongoing"]').count()).toBe(1)
await runningTrigger.click() await runningTrigger.click()
await page.getByRole('treeitem', { await page.getByRole('treeitem', {
name: new RegExp(`${LABEL}.*正在运行`), name: new RegExp(`${LABEL}.*running`),
}).waitFor({ timeout: 10_000 }) }).waitFor({ timeout: 10_000 })
await ended await ended
await page.getByRole('treeitem', { await page.getByRole('treeitem', {
name: new RegExp(`${LABEL}.*当前未运行`), name: new RegExp(`${LABEL}.*not running`),
}).waitFor({ timeout: 10_000 }) }).waitFor({ timeout: 10_000 })
expect(await page.getByRole('button', { name: '3 个子代理' }) expect(await page.getByRole('button', { name: '3 subagents' })
.locator('[data-state="ongoing"]').count()).toBe(0) .locator('[data-state="ongoing"]').count()).toBe(0)
await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click()
await expect.poll(() => page.getByText(FOLLOWUP, { exact: true }).count(), { timeout: 10_000 }).toBe(1) await expect.poll(() => page.getByText(FOLLOWUP, { exact: true }).count(), { timeout: 10_000 }).toBe(1)
@@ -331,9 +331,9 @@ describe('web e2e: persisted subagent conversation and human continuation', () =
it('opens an unavailable persisted grandchild after recording the available child', async () => { it('opens an unavailable persisted grandchild after recording the available child', async () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-grandchild')) onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-grandchild'))
await page.getByRole('button', { name: '1 个子代理' }).click() await page.getByRole('button', { name: '1 subagents' }).click()
await page.getByRole('treeitem', { name: new RegExp(NESTED_LABEL) }).click() await page.getByRole('treeitem', { name: new RegExp(NESTED_LABEL) }).click()
await page.getByText('父会话当前不在线,重新打开父会话后即可继续发送消息。').waitFor() await page.getByText('The parent session is offline; reopen it to continue sending messages.').waitFor()
const hierarchy = page.getByRole('navigation', { name: 'Session hierarchy' }) const hierarchy = page.getByRole('navigation', { name: 'Session hierarchy' })
const crumbs = await hierarchy.getByRole('button').allTextContents() const crumbs = await hierarchy.getByRole('button').allTextContents()
expect(crumbs.slice(-2)).toEqual([LABEL, NESTED_LABEL]) expect(crumbs.slice(-2)).toEqual([LABEL, NESTED_LABEL])
@@ -352,9 +352,9 @@ describe('web e2e: persisted subagent conversation and human continuation', () =
.getByRole('treeitem') .getByRole('treeitem')
.last() .last()
await parentSession.click() await parentSession.click()
await page.getByRole('button', { name: '3 个子代理' }).click() await page.getByRole('button', { name: '3 subagents' }).click()
await page.getByRole('treeitem', { name: new RegExp(ONE_SHOT_LABEL) }).click() await page.getByRole('treeitem', { name: new RegExp(ONE_SHOT_LABEL) }).click()
await page.getByText('一次性任务不支持后续消息,可在这里查看完整执行记录。').waitFor() await page.getByText('One-shot tasks do not accept follow-ups; review the full execution record here.').waitFor()
expect(scaffold.ctx.agents.get(oneShotId)).toBeUndefined() expect(scaffold.ctx.agents.get(oneShotId)).toBeUndefined()
}) })
@@ -363,7 +363,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () =
await page.getByRole('tree', { name: 'Sessions' }) await page.getByRole('tree', { name: 'Sessions' })
.getByRole('treeitem', { name: /Ask a research subagent to/ }) .getByRole('treeitem', { name: /Ask a research subagent to/ })
.click() .click()
await page.getByRole('button', { name: '3 个子代理' }).click() await page.getByRole('button', { name: '3 subagents' }).click()
await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click()
await page.getByRole('textbox', { name: 'Message the agent' }).waitFor() await page.getByRole('textbox', { name: 'Message the agent' }).waitFor()
const forkResponse = page.waitForResponse(response => const forkResponse = page.waitForResponse(response =>
@@ -389,7 +389,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () =
onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-post-fork-followup')) onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-post-fork-followup'))
const sessions = page.getByRole('tree', { name: 'Sessions' }) const sessions = page.getByRole('tree', { name: 'Sessions' })
await sessions.getByRole('treeitem', { name: /Ask a research subagent to/ }).click() await sessions.getByRole('treeitem', { name: /Ask a research subagent to/ }).click()
await page.getByRole('button', { name: '3 个子代理' }).click() await page.getByRole('button', { name: '3 subagents' }).click()
await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click()
await page.locator('textarea:enabled').first().waitFor() await page.locator('textarea:enabled').first().waitFor()
expect(scaffold.ctx.agents.get(childId)).toBeUndefined() expect(scaffold.ctx.agents.get(childId)).toBeUndefined()
@@ -406,7 +406,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () =
await expect.poll(() => scaffold.ctx.agents.get(forkId)).not.toBeUndefined() await expect.poll(() => scaffold.ctx.agents.get(forkId)).not.toBeUndefined()
await sessions.getByRole('treeitem', { name: /Ask a research subagent to/ }).click() await sessions.getByRole('treeitem', { name: /Ask a research subagent to/ }).click()
await page.getByRole('button', { name: '3 个子代理' }).click() await page.getByRole('button', { name: '3 subagents' }).click()
await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click()
const input = page.locator('textarea:enabled').first() const input = page.locator('textarea:enabled').first()
await input.waitFor() await input.waitFor()