From 2f732cff86f3acb7ab2f9009c500a45bec4d4967 Mon Sep 17 00:00:00 2001 From: Casey Brooks Date: Wed, 27 May 2026 18:12:52 +0000 Subject: [PATCH 1/2] fix(chat-app): wait for trace run redirect --- .../test/e2e/chat-trace-link.spec.ts | 50 +++++++++++++------ 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/suites/playwright-chat-app/test/e2e/chat-trace-link.spec.ts b/suites/playwright-chat-app/test/e2e/chat-trace-link.spec.ts index 01a46dd..0bbcf9b 100644 --- a/suites/playwright-chat-app/test/e2e/chat-trace-link.spec.ts +++ b/suites/playwright-chat-app/test/e2e/chat-trace-link.spec.ts @@ -17,6 +17,8 @@ const CLAUDE_TEST_LLM_ENDPOINT = process.env.E2E_TEST_LLM_ENDPOINT_CLAUDE ?? 'https://testllm.dev/v1/org/agynio/suite/claude/messages'; const CLAUDE_INIT_IMAGE = process.env.CLAUDE_INIT_IMAGE ?? 'ghcr.io/agynio/agent-init-claude:latest'; const CLAUDE_PROTOCOL = 'PROTOCOL_ANTHROPIC_MESSAGES'; +const MESSAGE_DEEP_LINK_RESOLUTION_TIMEOUT_MS = 180000; +const MESSAGE_DEEP_LINK_POLL_INTERVAL_MS = 5000; function isTimeoutError(error: unknown): error is Error { return error instanceof Error && error.name === 'TimeoutError'; @@ -45,18 +47,36 @@ const TRACE_SCENARIOS: TraceScenario[] = [ async function waitForRunPageFromMessageDeepLink( page: Page, - runUrlPattern: RegExp, - timeoutMs: number, + params: { messageId: string; organizationId: string; runUrlPattern: RegExp; timeoutMs: number }, ): Promise { - const deadline = Date.now() + timeoutMs; + const messageUrlPattern = new RegExp(`/message/${params.messageId}(\\?.*)?$`); + await expect(page).toHaveURL(messageUrlPattern, { timeout: params.timeoutMs }); + + const openedTraceUrl = new URL(page.url()); + expect(openedTraceUrl.searchParams.get('orgId')).toBe(params.organizationId); + + const resolvingMessage = page.getByText('Resolving message...'); + const noRunMessage = page.getByText('No run found for message.'); + const retryButton = page.getByRole('button', { name: 'Retry' }); + + const deadline = Date.now() + params.timeoutMs; while (Date.now() < deadline) { - if (runUrlPattern.test(page.url())) { + if (params.runUrlPattern.test(page.url())) { return; } - const retryButton = page.getByRole('button', { name: 'Retry' }); - if (await retryButton.isVisible({ timeout: 500 })) { + if (!messageUrlPattern.test(page.url())) { + throw new Error(`Trace message deep link navigated to an unexpected URL: ${page.url()}`); + } + + if (await resolvingMessage.isVisible({ timeout: 500 })) { + await expect(resolvingMessage).toBeVisible(); + } + + if (await noRunMessage.isVisible({ timeout: 500 })) { + await expect(noRunMessage).toBeVisible(); + await expect(retryButton).toBeVisible({ timeout: 5000 }); await retryButton.click(); } @@ -65,7 +85,9 @@ async function waitForRunPageFromMessageDeepLink( break; } - await page.waitForURL(runUrlPattern, { timeout: Math.min(5000, remainingMs) }).catch((error) => { + await page.waitForURL(params.runUrlPattern, { + timeout: Math.min(MESSAGE_DEEP_LINK_POLL_INTERVAL_MS, remainingMs), + }).catch((error) => { if (isTimeoutError(error)) { return; } @@ -120,18 +142,18 @@ async function openTraceFromChat( } throw error; }); - const completed = await completeOidcLogin(tracePage, { timeoutMs: 10000 }); + const completed = await completeOidcLogin(tracePage, { timeoutMs: 60000 }); if (completed) { await callbackPromise; } - const messageUrlPattern = new RegExp(`/message/${params.messageId}(\\?.*)?$`); - await expect(tracePage).toHaveURL(messageUrlPattern, { timeout: 120000 }); - const openedTraceUrl = new URL(tracePage.url()); - expect(openedTraceUrl.searchParams.get('orgId')).toBe(params.organizationId); - const runUrlPattern = new RegExp(`/${params.organizationId}/runs/[0-9a-f]{32}(\\?.*)?$`); - await waitForRunPageFromMessageDeepLink(tracePage, runUrlPattern, 180000); + await waitForRunPageFromMessageDeepLink(tracePage, { + messageId: params.messageId, + organizationId: params.organizationId, + runUrlPattern, + timeoutMs: MESSAGE_DEEP_LINK_RESOLUTION_TIMEOUT_MS, + }); await expect(tracePage).toHaveURL(runUrlPattern); await expect(tracePage.getByTestId('run-summary-status')).toContainText(/finished/i, { timeout: 120000 }); From 987c8968779969af0d390d69bf386ab71dee2caf Mon Sep 17 00:00:00 2001 From: Noa Lucent Date: Thu, 28 May 2026 11:32:11 +0000 Subject: [PATCH 2/2] fix(chat-app): allow trace deeplink fast redirect --- .../test/e2e/chat-trace-link.spec.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/suites/playwright-chat-app/test/e2e/chat-trace-link.spec.ts b/suites/playwright-chat-app/test/e2e/chat-trace-link.spec.ts index 0bbcf9b..56aa11d 100644 --- a/suites/playwright-chat-app/test/e2e/chat-trace-link.spec.ts +++ b/suites/playwright-chat-app/test/e2e/chat-trace-link.spec.ts @@ -50,7 +50,21 @@ async function waitForRunPageFromMessageDeepLink( params: { messageId: string; organizationId: string; runUrlPattern: RegExp; timeoutMs: number }, ): Promise { const messageUrlPattern = new RegExp(`/message/${params.messageId}(\\?.*)?$`); - await expect(page).toHaveURL(messageUrlPattern, { timeout: params.timeoutMs }); + + const initialUrl = page.url(); + if (params.runUrlPattern.test(initialUrl)) { + return; + } + + if (!messageUrlPattern.test(initialUrl)) { + await expect(page).toHaveURL((url) => messageUrlPattern.test(url.href) || params.runUrlPattern.test(url.href), { + timeout: params.timeoutMs, + }); + + if (params.runUrlPattern.test(page.url())) { + return; + } + } const openedTraceUrl = new URL(page.url()); expect(openedTraceUrl.searchParams.get('orgId')).toBe(params.organizationId);