From 51cb8e7e22876d17fb8da4c5f8660bfd1ed76909 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 20 May 2026 07:12:48 +0200 Subject: [PATCH] test(transcription): polish @mention test docstrings and tighten clip assert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Round-4 polish from Sara (#11199) and Felix (#11186): - Replace setTimeout(50) in stale-response race with tick() — matches round-3 pattern Sara verified in the sticky-takeover test. - Add intent comment above the "clear input" wait — it is a negative assertion that must not be optimised away. - Tighten displayName-clip assert from <=100 to ===100 so the test discriminates "clip works" from "clip works AND nothing weakened it". - JSDoc POST_DEBOUNCE_SLACK_MS with the calibration rationale. Co-Authored-By: Claude Opus 4.7 --- .../PersonMentionEditor.svelte.spec.ts | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/shared/discussion/PersonMentionEditor.svelte.spec.ts b/frontend/src/lib/shared/discussion/PersonMentionEditor.svelte.spec.ts index bdbb1b74..3b58a62f 100644 --- a/frontend/src/lib/shared/discussion/PersonMentionEditor.svelte.spec.ts +++ b/frontend/src/lib/shared/discussion/PersonMentionEditor.svelte.spec.ts @@ -8,6 +8,7 @@ import { describe, it, expect, vi, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page, userEvent } from 'vitest/browser'; +import { tick } from 'svelte'; import PersonMentionEditorHost from './PersonMentionEditor.test-fixture.svelte'; import type { components } from '$lib/generated/api'; import { m } from '$lib/paraglide/messages.js'; @@ -18,7 +19,12 @@ import { SEARCH_DEBOUNCE_MS } from './mentionConstants'; type Person = components['schemas']['Person']; type PersonMention = components['schemas']['PersonMention']; -// Slack on top of the debounce to absorb CI jitter (total 500 ms is generous). +/** + * Headroom above SEARCH_DEBOUNCE_MS for the debounce-window wait + * assertions in this file. 350 ms is calibrated against CI-runner jitter + * we observed pre-#629; dropping it below ~200 ms reintroduces flake. + * See PR #629 round-2 review comment #10935 (Sara). + */ const POST_DEBOUNCE_SLACK_MS = 350; const AUGUSTE: Person = { @@ -275,6 +281,9 @@ describe('PersonMentionEditor — AC-2/3: search input drives fetch', () => { await userEvent.clear(page.getByRole('searchbox')); + // Negative assertion: wait past the debounce window to confirm no + // trailing fetch was scheduled. Removing this wait would mask a + // re-introduction of the keystroke-driven items() fetch. await new Promise((r) => setTimeout(r, SEARCH_DEBOUNCE_MS + POST_DEBOUNCE_SLACK_MS)); expect(fetchMock.mock.calls.length).toBe(fetchesBeforeClear); @@ -332,7 +341,10 @@ describe('PersonMentionEditor — stale-response race', () => { // The stale fetch now resolves with persons. The dropdown must stay empty. resolveFetch({ ok: true, json: () => Promise.resolve([AUGUSTE]) }); - await new Promise((r) => setTimeout(r, 50)); + // Flush pending Svelte reactivity so any (non-)update from the stale + // fetch resolution has landed before we assert. expect.element already + // polls, so no fixed-timeout fallback is needed. Sara on PR #629 round 4. + await tick(); await expect.element(page.getByText('Auguste Raddatz')).not.toBeInTheDocument(); }); @@ -528,7 +540,10 @@ describe('PersonMentionEditor — AC-1: typed text as displayName', () => { await vi.waitFor(() => { expect(host.snapshot.mentionedPersons).toHaveLength(1); - expect(host.snapshot.mentionedPersons[0].displayName.length).toBeLessThanOrEqual(100); + // Tight assertion: input is 105 chars, cap is exactly 100. Using + // `toHaveLength(100)` discriminates "clip works" from "clip works + // AND nothing weakened it to e.g. 95". Sara on PR #629 round 4. + expect(host.snapshot.mentionedPersons[0].displayName).toHaveLength(100); }); });