test(web): await action acknowledgements before following controls
This commit is contained in:
1 parent
6c0e258b27
commit
be9d401c33
4 files changed
+38
-6
No files matched your search
@@ -139,9 +139,22 @@ describe.skipIf(MODE === 'record')('web e2e: GitHub ready-for-review', () => {
|
||||
head: { ref: 'fix-session-replay', sha: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' },
|
||||
},
|
||||
}
|
||||
expect((await send(webhookOrigin, 'ready', payload)).status).toBe(202)
|
||||
await vi.waitFor(() => { expect(scaffold.ctx.agents.list()).toHaveLength(before + 1) })
|
||||
await vi.waitFor(() => { expect(adapter.requests).toHaveLength(1) })
|
||||
const completed = Promise.withResolvers<undefined>()
|
||||
let reviewSession: string | undefined
|
||||
const off = scaffold.ctx.on('session/event', (session, event) => {
|
||||
if (event.type === 'user/message' && event.data.source.kind === 'webhook'
|
||||
&& event.data.source.provider === 'github' && event.data.source.source === 'primary-github'
|
||||
&& event.data.source.deliveryId === 'ready' && event.data.source.ruleId === 'review-pr-when-ready') reviewSession = session.id
|
||||
if (event.type === 'turn/end' && session.id === reviewSession) completed.resolve(undefined)
|
||||
})
|
||||
try {
|
||||
expect((await send(webhookOrigin, 'ready', payload)).status).toBe(202)
|
||||
await completed.promise
|
||||
} finally {
|
||||
off()
|
||||
}
|
||||
expect(scaffold.ctx.agents.list()).toHaveLength(before + 1)
|
||||
expect(adapter.requests).toHaveLength(1)
|
||||
|
||||
const agent = scaffold.ctx.agents.list().find(candidate => candidate.session.header.cwd === scaffold.workspaceCwd)
|
||||
expect(agent).toBeDefined()
|
||||
|
||||
@@ -233,6 +233,10 @@ describe('web e2e: message IconActions and clocks on settled history', () => {
|
||||
() => page.locator('[role="treeitem"][aria-selected="true"]').count(),
|
||||
{ timeout: 10_000 },
|
||||
).toBe(1)
|
||||
await expect.poll(
|
||||
() => page.locator('[role="treeitem"][aria-selected="true"]').textContent(),
|
||||
{ timeout: 10_000 },
|
||||
).toContain('Use the read tool twice (1)')
|
||||
// The row action owns a distinct ui-workspace injection from the message
|
||||
// action above, so exercise both through the loaded app before capture.
|
||||
const sourceRow = page.locator('[role="treeitem"][aria-selected="true"]')
|
||||
|
||||
@@ -65,6 +65,16 @@ describe('web e2e: queue row actions', () => {
|
||||
if (failures.length > 1) throw new AggregateError(failures, 'queue-actions teardown failed')
|
||||
})
|
||||
|
||||
/** Wait for the exact queue mutation response before observing its unlocked actions. */
|
||||
async function settleQueueAction(action: () => Promise<void>, remainingText: string): Promise<void> {
|
||||
const response = page.waitForResponse('**/api/session/updateQueue')
|
||||
await action()
|
||||
expect((await response).ok()).toBe(true)
|
||||
const row = page.locator('[data-queue-dock] li', { hasText: remainingText })
|
||||
await expect.poll(() => row.getByRole('button', { name: 'Edit queued message' }).isEnabled()).toBe(true)
|
||||
await expect.poll(() => row.getByRole('button', { name: 'Remove queued message' }).isEnabled()).toBe(true)
|
||||
}
|
||||
|
||||
it.skipIf(MODE === 'record')('edits and removes exact occurrences and preserves Queue across stop', async () => {
|
||||
overrideDir = await mkdtemp(join(tmpdir(), 'dsh-web-queue-actions-'))
|
||||
const readyFile = join(overrideDir, '.hang-ready')
|
||||
@@ -96,6 +106,7 @@ describe('web e2e: queue row actions', () => {
|
||||
await input.press('Enter')
|
||||
await expect.poll(() => existsSync(readyFile), { timeout: 15_000 }).toBe(true)
|
||||
|
||||
const admitted = page.waitForResponse('**/api/session/prompt')
|
||||
const received = Promise.withResolvers<undefined>()
|
||||
const release = Promise.withResolvers<undefined>()
|
||||
await page.route('**/api/session/prompt', async (route) => {
|
||||
@@ -125,6 +136,7 @@ describe('web e2e: queue row actions', () => {
|
||||
} finally {
|
||||
release.resolve(undefined)
|
||||
}
|
||||
expect((await admitted).ok()).toBe(true)
|
||||
await expect.poll(() => page.getByRole('button', { name: 'Remove queued message' }).isEnabled()).toBe(true)
|
||||
expect(await page.locator('[data-queue-dock] [data-submission-echo]').count()).toBe(0)
|
||||
expect(await page.locator('[data-queue-dock]').getByRole('status').count()).toBe(0)
|
||||
@@ -174,11 +186,11 @@ describe('web e2e: queue row actions', () => {
|
||||
await editor.fill(EDITED)
|
||||
const editingSnapshot = await captureStableAria(page, '[class*="centerCol"]', scaffold.workspaceCwd)
|
||||
await compareOrRefreshGolden(EDITING_EXPECTED, editingSnapshot, MODE)
|
||||
await page.getByRole('button', { name: 'Save queued message' }).click()
|
||||
await settleQueueAction(() => page.getByRole('button', { name: 'Save queued message' }).click(), EDITED)
|
||||
await page.getByText(EDITED, { exact: true }).waitFor()
|
||||
|
||||
const removeRow = page.locator('[data-queue-dock] li', { hasText: REMOVE })
|
||||
await removeRow.getByRole('button', { name: 'Remove queued message' }).click()
|
||||
await settleQueueAction(() => removeRow.getByRole('button', { name: 'Remove queued message' }).click(), EDITED)
|
||||
await expect.poll(() => page.getByText(REMOVE, { exact: true }).count()).toBe(0)
|
||||
|
||||
const snapshot = await captureStableAria(page, '[class*="centerCol"]', scaffold.workspaceCwd)
|
||||
|
||||
@@ -57,7 +57,10 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
await dialog.getByRole('button', { name: 'Edit path' }).click()
|
||||
const pathInput = dialog.locator('input[aria-label="Edit path"]')
|
||||
await pathInput.fill(path)
|
||||
await pathInput.press('Enter')
|
||||
// Enter's keydown can retire the editor before keyup; target the focused keyboard, not that retiring node.
|
||||
await page.keyboard.press('Enter')
|
||||
await pathInput.waitFor({ state: 'detached', timeout: 10_000 })
|
||||
await dialog.getByRole('button', { name: 'Edit path', exact: true }).waitFor()
|
||||
return dialog
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user