From a110e3e6e6fe891c49378113f2cc28f0769e0be6 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Wed, 20 May 2026 15:39:21 -0700 Subject: [PATCH] test(c-tool-calls): assert on chat-tool-calls + chat-tool-call-card primitives directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tightens the existing tool-call UI assertion from a generic getByRole('button', { name: /lookup_flight|tool/i }) (which would match any unrelated button on the page) to the specific @ngaf/chat custom-element selectors: - visible (proves the wrapper primitive mounted). - visible + contains 'lookup_flight' (proves the per-call card rendered with the right tool name). Same end-to-end coverage; more specific surface area means less false-pass risk if the demo template ever adds an unrelated button on the page. Also switches the final-bubble text assertion from innerText().toLowerCase() to Playwright's built-in toContainText({ ignoreCase: true }) — auto-retries on the locator instead of one-shot. Identified during the post-Task-#4 e2e audit (item #10). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../angular/e2e/c-tool-calls.spec.ts | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/cockpit/chat/tool-calls/angular/e2e/c-tool-calls.spec.ts b/cockpit/chat/tool-calls/angular/e2e/c-tool-calls.spec.ts index 09a12d63..30687010 100644 --- a/cockpit/chat/tool-calls/angular/e2e/c-tool-calls.spec.ts +++ b/cockpit/chat/tool-calls/angular/e2e/c-tool-calls.spec.ts @@ -7,14 +7,20 @@ const PROMPT = "What's the status of UA123?"; test('c-tool-calls: parent dispatches lookup_flight tool, continuation surfaces flight data', async ({ page }) => { const bubble = await submitAndWaitForResponse(page, PROMPT); - // The chat-tool-calls primitive renders a card per tool call. Card label - // includes the tool name. Asserting it's in the DOM proves the parent's - // tool_call routed through the chat-tool-calls UI primitive. - const toolCallChip = page.getByRole('button', { name: /lookup_flight|tool/i }).first(); - await expect(toolCallChip).toBeVisible({ timeout: 30_000 }); + // The chat-tool-calls primitive mounts as the wrapper for tool-call UI. + // Tightened from a generic getByRole('button') (which would match any + // unrelated button on the page) to the specific custom-element selectors + // — proves the parent's tool_call routed through the actual @ngaf/chat + // primitive, not just any DOM button that happens to mention the tool. + await expect(page.locator('chat-tool-calls').first()).toBeVisible({ timeout: 30_000 }); + + // Inside the wrapper, the per-call card is rendered as . + // For a single lookup_flight call (no grouping), there's exactly one card. + const card = page.locator('chat-tool-call-card').first(); + await expect(card).toBeVisible(); + await expect(card).toContainText('lookup_flight'); // The continuation's text mentions a distinctive phrase from the captured // response — proves the tool-result-then-text loop completed end-to-end. - const finalText = await bubble.innerText(); - expect(finalText.toLowerCase()).toContain('ua123'); + await expect(bubble).toContainText('UA123', { ignoreCase: true }); });