test: stabilize droid notification hook e2e (#2961)

Use the main hook status snapshot as the synthetic hook setup precondition and give the inactive-worktree notification assertions a CI-sized wait.
This commit is contained in:
Neil
2026-05-27 18:34:33 -07:00
committed by GitHub
parent 7c4f4a9a98
commit 32da1f233a
+37 -14
View File
@@ -21,6 +21,14 @@ type NotificationDispatch = {
agentLastAssistantMessage?: string
}
type AgentStatusSummary = {
paneKey: string
state: string
agentType?: string
prompt?: string
lastAssistantMessage?: string
}
async function emitOscTitle(page: Page, ptyId: string, title: string) {
await sendToTerminal(page, ptyId, `printf '\\033]0;${title}\\007'\r`)
}
@@ -93,15 +101,7 @@ async function switchToOtherExistingWorktree(page: Page): Promise<string> {
})
}
async function getAgentStatuses(page: Page): Promise<
{
paneKey: string
state: string
agentType?: string
prompt?: string
lastAssistantMessage?: string
}[]
> {
async function getAgentStatuses(page: Page): Promise<AgentStatusSummary[]> {
return page.evaluate(() => {
const store = window.__store
if (!store) {
@@ -117,6 +117,27 @@ async function getAgentStatuses(page: Page): Promise<
})
}
async function getCachedAgentStatuses(page: Page): Promise<AgentStatusSummary[]> {
return page.evaluate(async () => {
const snapshot = await window.api.agentStatus.getSnapshot()
return snapshot.map((entry) => ({
paneKey: entry.paneKey,
state: entry.state,
agentType: entry.agentType,
prompt: entry.prompt,
lastAssistantMessage: entry.lastAssistantMessage
}))
})
}
async function getRendererOrCachedAgentStatuses(page: Page): Promise<AgentStatusSummary[]> {
const [rendererStatuses, cachedStatuses] = await Promise.all([
getAgentStatuses(page),
getCachedAgentStatuses(page)
])
return [...rendererStatuses, ...cachedStatuses]
}
test.describe('Droid notifications', () => {
test('Codex hook completion dispatches while its worktree is inactive', async ({
orcaPage,
@@ -147,13 +168,15 @@ test.describe('Droid notifications', () => {
await expect
.poll(
async () =>
(await getAgentStatuses(orcaPage)).some(
(await getRendererOrCachedAgentStatuses(orcaPage)).some(
(status) =>
status.agentType === 'codex' && status.state === 'working' && status.prompt === prompt
),
{
timeout: 10_000,
message: 'Codex UserPromptSubmit hook did not reach renderer agent status'
timeout: 30_000,
// Why: this synthetic hook posts directly to main; main's cache is
// the durable source used to recover renderer startup/listener races.
message: 'Codex UserPromptSubmit hook did not reach agent status cache'
}
)
.toBe(true)
@@ -179,7 +202,7 @@ test.describe('Droid notifications', () => {
status.lastAssistantMessage === finalMessage
),
{
timeout: 10_000,
timeout: 30_000,
message: 'Codex Stop hook did not reach renderer agent status'
}
)
@@ -192,7 +215,7 @@ test.describe('Droid notifications', () => {
return dispatches.filter((dispatch) => dispatch.source === 'agent-task-complete')
},
{
timeout: 10_000,
timeout: 30_000,
message: 'Codex hook Stop did not dispatch task-complete while worktree was inactive'
}
)