test(web): align unavailable model and cold session expectations
This commit is contained in:
1 parent
71f0713b86
commit
9a9948bc83
5 files changed
+20
-30
No files matched your search
@@ -90,8 +90,11 @@ describe.skipIf(webSnapshotMode() === 'record')('web e2e: DeepSeek Messages sett
|
||||
await scaffold.ctx.agentDefaultModel.saveSelection({ provider: 'deepseek-official', model: 'deepseek-v4-flash' })
|
||||
await page.reload({ waitUntil: 'load' })
|
||||
const input = page.locator('[data-composer-input]').first()
|
||||
await expect.poll(() => input.getAttribute('contenteditable')).toBe('false')
|
||||
await page.getByRole('button', { name: '请选择模型', exact: true }).click()
|
||||
const trigger = page.getByRole('button', { name: /^选择模型.*deepseek-official\/deepseek-v4-flash/ })
|
||||
await trigger.waitFor()
|
||||
await expect.poll(() => input.getAttribute('contenteditable')).toBe('true')
|
||||
await trigger.click()
|
||||
await page.getByRole('menuitem', { name: /模型/ }).click()
|
||||
await page.getByRole('menuitemradio', { name: 'Messages Flash', exact: true }).click()
|
||||
await expect.poll(() => input.getAttribute('contenteditable')).toBe('true')
|
||||
await expect.poll(() => scaffold.ctx.agentDefaultModel.currentSelection().provider).toBe('deepseek-official')
|
||||
|
||||
@@ -127,7 +127,7 @@ describe('web e2e: the composer model switch is the default for later sessions',
|
||||
expect(tripwire.pageErrors).toEqual([])
|
||||
}, 60_000)
|
||||
|
||||
it('goes inert when the route the default names stops being served', async () => {
|
||||
it('retains the saved route and editable composer when its provider is removed', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-default-model-blocked'))
|
||||
const box = page.locator('[data-composer-input]').first()
|
||||
await expect.poll(async () => box.isEnabled(), { timeout: 10_000 }).toBe(true)
|
||||
@@ -139,28 +139,14 @@ describe('web e2e: the composer model switch is the default for later sessions',
|
||||
baseURL: 'https://gateway.origin.example/v1', models: [{ id: START_MODEL, name: 'Origin Large' }] },
|
||||
} })
|
||||
|
||||
await expect.poll(async () => box.isEnabled(), { timeout: 15_000 }).toBe(false)
|
||||
const unset = page.getByRole('button', { name: '请选择模型', exact: true })
|
||||
await unset.waitFor()
|
||||
expect(await unset.evaluate(element => getComputedStyle(element).fontWeight)).toBe('400')
|
||||
expect(await page.getByRole('button', { name: '发送消息', exact: true }).isEnabled()).toBe(false)
|
||||
const seat = page.getByRole('button', { name: new RegExp(`^选择模型.*${ROUTE}/${MODEL}`) })
|
||||
await seat.waitFor()
|
||||
expect(await box.isEnabled()).toBe(true)
|
||||
expect(scaffold.ctx.agentDefaultModel.currentSelection()).toMatchObject({ provider: ROUTE, model: MODEL })
|
||||
const aria = await captureStableAria(page, '[data-composer-card]', scaffold.workspaceCwd)
|
||||
await compareOrRefreshGolden(fileURLToPath(new URL('./expected/default-model/unselected.expected.md', import.meta.url)), aria, webSnapshotMode())
|
||||
|
||||
// The block is an affordance; the refusal is the Host's. A client that
|
||||
// never disabled anything still cannot start a turn on a dead route.
|
||||
await expect(scaffold.ctx.sessionController.prompt({
|
||||
requestId: 'default-model-refused' as never,
|
||||
sessionId: SessionId(await createSession('default-model-refusal')),
|
||||
mode: 'queue',
|
||||
content: [{ type: 'text', text: 'hi' }],
|
||||
}, new AbortController().signal)).rejects.toMatchObject({ code: 'session/model-unavailable' })
|
||||
|
||||
// The way out stays open. Locking the model seat with everything else
|
||||
// would leave the composer asking for the one thing it prevents.
|
||||
const seat = page.getByRole('button', { name: '请选择模型', exact: true })
|
||||
expect(await seat.isEnabled()).toBe(true)
|
||||
await seat.click()
|
||||
await page.getByRole('menuitem', { name: /模型/ }).click()
|
||||
await page.getByRole('menuitemradio').first().click()
|
||||
await expect.poll(async () => box.isEnabled(), { timeout: 15_000 }).toBe(true)
|
||||
expect(tripwire.pageErrors).toEqual([])
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
- textbox "描述你想要构建的内容, / 调用指令, @ 文件或对话" [disabled]
|
||||
- button "添加文件或调用指令" [disabled]
|
||||
- button "访问模式,当前:工作区内修改" [disabled]: 工作区内修改
|
||||
- button "请选择模型"
|
||||
- textbox "描述你想要构建的内容, / 调用指令, @ 文件或对话"
|
||||
- button "添加文件或调用指令"
|
||||
- button "访问模式,当前:工作区内修改": 工作区内修改
|
||||
- button "选择模型,当前 acme-gateway/acme-large": acme-gateway/acme-large
|
||||
- button "发送消息" [disabled]
|
||||
@@ -275,9 +275,10 @@ describe.skipIf(MODE === 'record')('web e2e: first-run DeepSeek credential setup
|
||||
// trigger — on the page; the scaffold boots without one.
|
||||
await connectFreshWorkspaceZh(page, scaffold.workspaceCwd, 'model-fallback-e2e', false)
|
||||
|
||||
const modelTrigger = page.getByRole('button', { name: '请选择模型', exact: true })
|
||||
const modelTrigger = page.getByRole('button', { name: /^选择模型.*deepseek-official\// })
|
||||
await modelTrigger.waitFor({ timeout: 10_000 })
|
||||
await modelTrigger.click()
|
||||
await page.getByRole('menuitem', { name: /模型/ }).click()
|
||||
expect(await page.getByText('Configured Flash', { exact: true }).count()).toBe(0)
|
||||
await page.getByRole('menuitemradio', { name: 'Private Preview' }).waitFor({ timeout: 10_000 })
|
||||
expect(tripwire.warnings).toEqual([])
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
compareOrRefreshGolden,
|
||||
launchWebScaffold,
|
||||
seedSession,
|
||||
readPersistedEvents,
|
||||
watchConsole,
|
||||
webSnapshotMode,
|
||||
type WebScaffold,
|
||||
@@ -403,9 +404,8 @@ describe.skipIf(MODE === 'record')('web e2e: file and session references through
|
||||
await target.waitFor({ timeout: 15_000 })
|
||||
await target.click()
|
||||
await page.locator('[data-chat-flow-kind="user"]').filter({ hasText: 'Research notes' }).waitFor({ timeout: 15_000 })
|
||||
const session = scaffold.ctx.sessions.get(SessionId(TARGET_SESSION_ID))
|
||||
if (session === undefined) throw new Error('reference target session is unavailable')
|
||||
const inputs = session.snapshotEvents().filter(event => event.type === 'user/message')
|
||||
const events = await readPersistedEvents(scaffold, SessionId(TARGET_SESSION_ID))
|
||||
const inputs = events.filter(event => event.type === 'user/message')
|
||||
expect(inputs.map(event => event.data.source.kind)).toEqual(['user', 'session-reference'])
|
||||
expect(inputs[0]?.seq).toBeLessThan(inputs[1]!.seq)
|
||||
expect(JSON.stringify(inputs[1]?.data)).toContain('<referenced-sessions>snapshot</referenced-sessions>')
|
||||
|
||||
Reference in new issue
Block a user