test(web): verify plugin entry across modes and session states

This commit is contained in:
ZiyaZhang committed 2026-09-28 12:21:45 -07:00
1 parent 6dccc57a5c
commit 66f00a9170
3 files changed
+52 -12

No files matched your search

+41 -6
View File
@@ -412,8 +412,8 @@ describe('web e2e: agent-preset selection', () => {
})
})
it('starts one real Creator composition from Plugins with Coding Tools off and keeps the next task on Standard', async () => {
const scaffold = await launchWebScaffold({ developerTools: false, agentPresets: { default: 'standard' } })
it.each([false, true])('starts Creator from Plugins with Coding Tools=%s without changing drafts or defaults', async (developerTools) => {
const scaffold = await launchWebScaffold({ developerTools, agentPresets: { default: 'standard' } })
let browser: Browser | undefined
try {
browser = await chromium.launch()
@@ -426,6 +426,9 @@ it('starts one real Creator composition from Plugins with Coding Tools off and k
if (creator === undefined) throw new Error('Connecting the workspace did not create a Session')
expect(scaffold.ctx.agentPresets.composedPreset(creator.ctx)).toBe('standard')
await page.getByRole('button', { name: 'Standard mode', exact: true }).waitFor()
const composer = page.locator('[data-composer-input][contenteditable="true"]').last()
const draft = 'Keep this unsent plugin idea.'
await writeComposerDraft(page, composer, draft)
await page.getByRole('navigation', { name: 'Global panels' }).getByRole('button', { name: 'Plugins', exact: true }).click()
await page.getByRole('button', { name: 'Choose how to add a plugin', exact: true }).click()
@@ -435,6 +438,8 @@ it('starts one real Creator composition from Plugins with Coding Tools off and k
])
const picker = page.getByTitle('Choose the agent preset for your new task', { exact: true }).filter({ hasText: 'Creator mode' })
await picker.waitFor()
await composer.filter({ hasText: draft }).waitFor()
expect(await composer.innerText()).toBe(draft)
expect(await picker.getAttribute('aria-haspopup')).toBe('menu')
expect(await page.getByRole('dialog', { name: 'Add plugin', exact: true }).count()).toBe(0)
expect(scaffold.ctx.sessionProjections.stateOf(creator.session, 'agentPreset')).toBe('cordis')
@@ -444,13 +449,13 @@ it('starts one real Creator composition from Plugins with Coding Tools off and k
expect(creator.session.snapshotEvents().some(event => event.type === 'agent-preset/selected'
&& event.data.agentPreset === 'cordis')).toBe(true)
expect(creator.session.snapshotEvents().some(event => event.type === 'user/message' || event.type === 'turn/start')).toBe(false)
expect(scaffold.ctx.settings.describe().find(row => row.ns === 'ui-settings')?.value).toMatchObject({ enabled: false })
expect(scaffold.ctx.settings.describe().find(row => row.ns === 'ui-settings')?.value).toMatchObject({ enabled: developerTools })
expect(scaffold.ctx.agentPresets.defaultId).toBe('standard')
await picker.click()
await page.getByRole('menu').waitFor()
expect(await page.getByRole('menuitem', { name: /^Standard mode|^Creator mode/ }).count()).toBe(2)
expect(await page.getByRole('menuitem', { name: /^PTC mode|^Minimal mode/ }).count()).toBe(0)
expect(await page.getByRole('menuitem', { name: /^PTC mode|^Minimal mode/ }).count()).toBe(developerTools ? 2 : 0)
await page.keyboard.press('Escape')
const newSession = page.getByRole('button', { name: 'New session', exact: true }).filter({ hasText: 'New Session' })
await Promise.all([page.waitForResponse('**/api/session/create'), newSession.click()])
@@ -460,6 +465,7 @@ it('starts one real Creator composition from Plugins with Coding Tools off and k
expect(scaffold.ctx.agentPresets.composedPreset(creator.ctx)).toBe('cordis')
// Close a fixture turn on the real Creator Session without requesting a model.
await writeComposerDraft(page, composer, '')
creator.session.append('turn/start', { turn: 1 })
const user = creator.session.append('user/message', createUserMessage({
content: [{ type: 'text', text: 'Creator fixture completed without a model call.' }], source: { kind: 'user' },
@@ -480,8 +486,37 @@ it('starts one real Creator composition from Plugins with Coding Tools off and k
await openSettings(page, 'en')
const settings = page.getByRole('dialog', { name: 'Settings' })
await settings.getByRole('button', { name: 'General', exact: true }).click()
expect(await settings.getByRole('switch', { name: 'Coding Tools' }).getAttribute('aria-checked')).toBe('false')
expect(scaffold.ctx.settings.describe().find(row => row.ns === 'ui-settings')?.value).toMatchObject({ enabled: false })
expect(await settings.getByRole('switch', { name: 'Coding Tools' }).getAttribute('aria-checked')).toBe(String(developerTools))
expect(scaffold.ctx.settings.describe().find(row => row.ns === 'ui-settings')?.value).toMatchObject({ enabled: developerTools })
expect(scaffold.ctx.agentPresets.defaultId).toBe('standard')
await settings.getByRole('button', { name: 'Close', exact: true }).last().click()
// A completed source stays intact; the entry reuses the workspace's remaining blank task.
await page.getByRole('treeitem').filter({ has: page.getByText('Creator fixture', { exact: true }) }).click()
await page.getByText('Creator fixture completed without a model call.', { exact: true }).waitFor()
const source = scaffold.ctx.agents.get(creator.id)
if (source === undefined) throw new Error('The completed source Session did not reopen')
const sourceEvents = source.session.snapshotEvents()
await page.getByRole('navigation', { name: 'Global panels' }).getByRole('button', { name: 'Plugins', exact: true }).click()
await page.getByRole('button', { name: 'Choose how to add a plugin', exact: true }).click()
await Promise.all([
page.waitForResponse('**/api/agentPresets/select'),
page.getByRole('menuitem', { name: /^Let the agent create a plugin/ }).click(),
])
await picker.waitFor()
const reentered = scaffold.ctx.agents.get(next.id)
if (reentered === undefined) throw new Error('Creator did not reuse the blank Session')
expect(scaffold.ctx.agentPresets.composedPreset(reentered.ctx)).toBe('cordis')
expect(reentered.session.snapshotEvents().some(event => event.type === 'user/message' || event.type === 'turn/start')).toBe(false)
expect(source.session.snapshotEvents()).toEqual(sourceEvents)
await page.reload({ waitUntil: 'load' })
await picker.waitFor()
const resumed = scaffold.ctx.agents.get(next.id)
if (resumed === undefined) throw new Error('Creator did not survive the page reload')
expect(scaffold.ctx.sessionProjections.stateOf(resumed.session, 'agentPreset')).toBe('cordis')
expect(scaffold.ctx.agentPresets.composedPreset(resumed.ctx)).toBe('cordis')
expect(scaffold.ctx.settings.describe().find(row => row.ns === 'ui-settings')?.value).toMatchObject({ enabled: developerTools })
expect(scaffold.ctx.agentPresets.defaultId).toBe('standard')
expect(tripwire.pageErrors).toEqual([])
expect(tripwire.warnings).toEqual([])
+10
View File
@@ -832,6 +832,16 @@ describe('web e2e: plugin manager', () => {
const dialog = page.getByRole('dialog', { name: '添加插件' })
await dialog.waitFor({ timeout: 10_000 })
const field = dialog.getByRole('textbox', { name: '包名或地址' })
expect(await page.getByRole('menu').count()).toBe(0)
await expect.poll(() => field.evaluate(element => document.activeElement === element)).toBe(true)
await dialog.getByRole('button', { name: '关闭', exact: true }).click()
await dialog.waitFor({ state: 'hidden' })
await panel.getByRole('button', { name: '选择添加插件方式', exact: true }).click()
const menu = page.getByRole('menu')
await menu.getByRole('menuitem', { name: /^安装第三方插件/ }).click()
await menu.waitFor({ state: 'hidden' })
await dialog.waitFor({ state: 'visible' })
await expect.poll(() => field.evaluate(element => document.activeElement === element)).toBe(true)
const install = dialog.getByRole('button', { name: '安装', exact: true })
expect(await install.isDisabled()).toBe(true)
expect(await dialog.getByRole('note').textContent()).toContain('请确认插件来源可信')
@@ -80,17 +80,12 @@
.addMenu [role='menuitem'] {
height: 72px;
box-sizing: border-box;
align-items: center;
gap: 10px;
padding: 6px 12px;
}
/* Keep both action icons centred beside the complete text block. */
.addMenu [role='menuitem'] > span:first-child:has(> svg) {
width: 16px;
height: 16px;
}
.addMenu [role='menuitem'] > span:first-child:has(> svg),
.addMenu [role='menuitem'] > span:first-child:has(> svg) > svg {
width: 16px;
height: 16px;