From 43c6e663e79a8c9a5cde09f6b2f4d3e32180127a Mon Sep 17 00:00:00 2001 From: codyllord Date: Tue, 22 Sep 2026 23:36:01 +0000 Subject: [PATCH] fix(e2e): poll the live tool count instead of reading it once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "list -> open the MCP server lands on Connect with URL, probe and live count" fails on develop with Expected: 22, Received: 6. The header chip renders as soon as the editor does, showing the count the store can compute before the backend-services fetch has landed — globals and custom tools only. The test read it once, with textContent(), and compared that first paint against the settled model, so it raced the fetch and lost. The Tools tab tests do not hit this because openToolsTab() waits for .mcp-tools-loading to clear first. Read the chip through expect.poll so the assertion retries until the catalog arrives, and assert the model is non-trivial separately rather than inferring it from the racing read. numberFrom() is left alone for the callers that read values which are settled by the time they run. --- e2e/mcp-service.spec.ts | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/e2e/mcp-service.spec.ts b/e2e/mcp-service.spec.ts index a4cc508a..7febbe1e 100644 --- a/e2e/mcp-service.spec.ts +++ b/e2e/mcp-service.spec.ts @@ -91,6 +91,16 @@ function headerToolsLiveChip(page: Page): Locator { return page.locator('.mcp-head').getByRole('button', { name: /tools live/ }); } +/** + * The header chip's current number, or null while it has not rendered one. + * Deliberately assertion-free so it can drive expect.poll. + */ +async function toolsLiveCount(page: Page): Promise { + const text = (await headerToolsLiveChip(page).textContent()) ?? ''; + const m = text.match(/(\d+) tools live/); + return m ? parseInt(m[1], 10) : null; +} + async function numberFrom(locator: Locator, re: RegExp): Promise { const text = (await locator.textContent()) ?? ''; const m = text.match(re); @@ -135,10 +145,14 @@ test.describe('MCP editor — Connect tab', () => { { timeout: 15_000 } ); - // Header carries the live effective count, N > 0 and = model(config). - const n = await numberFrom(headerToolsLiveChip(page), /(\d+) tools live/); - expect(n).toBeGreaterThan(0); - expect(n).toBe(expectedTotal()); + // Header carries the live effective count, = model(config). The chip paints + // as soon as the editor does, before the backend-services fetch lands, so it + // starts at the services-less count and settles once the catalog arrives. + // Read it with a retrying assertion rather than once. + expect(expectedTotal()).toBeGreaterThan(0); + await expect + .poll(() => toolsLiveCount(page), { timeout: 15_000 }) + .toBe(expectedTotal()); }); test('client panels are auth-aware and never leak a real credential', async ({