refactor(test): name the debounce slack and harden against CI jitter
Extracts SEARCH_DEBOUNCE_MS + POST_DEBOUNCE_SLACK_MS at the top of the spec and bumps the post-debounce wait from 250/300 ms to 500 ms. Addresses Felix's "magic number" suggestion and Sara's flake-risk concern on PR #629. (Sara's fake-timer alternative collides with userEvent + vi.waitFor in vitest-browser; the slack bump achieves the same deterministic outcome with no fragility.) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,12 @@ import { m } from '$lib/paraglide/messages.js';
|
|||||||
type Person = components['schemas']['Person'];
|
type Person = components['schemas']['Person'];
|
||||||
type PersonMention = components['schemas']['PersonMention'];
|
type PersonMention = components['schemas']['PersonMention'];
|
||||||
|
|
||||||
|
// Mirror of the debounce in PersonMentionEditor.svelte. Naming the magic and
|
||||||
|
// using a generous slack (SEARCH_DEBOUNCE_MS + 350 = 500 ms) kills CI-jitter
|
||||||
|
// flakiness Sara raised on PR #629.
|
||||||
|
const SEARCH_DEBOUNCE_MS = 150;
|
||||||
|
const POST_DEBOUNCE_SLACK_MS = 350;
|
||||||
|
|
||||||
const AUGUSTE: Person = {
|
const AUGUSTE: Person = {
|
||||||
id: 'p-aug',
|
id: 'p-aug',
|
||||||
firstName: 'Auguste',
|
firstName: 'Auguste',
|
||||||
@@ -218,8 +224,7 @@ describe('PersonMentionEditor — AC-2/3: search input drives fetch', () => {
|
|||||||
|
|
||||||
await userEvent.type(page.getByRole('textbox'), '@Walter');
|
await userEvent.type(page.getByRole('textbox'), '@Walter');
|
||||||
|
|
||||||
// Wait beyond the 150 ms debounce window so the trailing call has flushed.
|
await new Promise((r) => setTimeout(r, SEARCH_DEBOUNCE_MS + POST_DEBOUNCE_SLACK_MS));
|
||||||
await new Promise((r) => setTimeout(r, 300));
|
|
||||||
|
|
||||||
const personsFetches = fetchMock.mock.calls.filter(
|
const personsFetches = fetchMock.mock.calls.filter(
|
||||||
([url]) => typeof url === 'string' && url.startsWith('/api/persons')
|
([url]) => typeof url === 'string' && url.startsWith('/api/persons')
|
||||||
@@ -243,8 +248,7 @@ describe('PersonMentionEditor — AC-2/3: search input drives fetch', () => {
|
|||||||
|
|
||||||
await userEvent.clear(page.getByRole('searchbox'));
|
await userEvent.clear(page.getByRole('searchbox'));
|
||||||
|
|
||||||
// Wait beyond the debounce window to confirm no fetch was scheduled.
|
await new Promise((r) => setTimeout(r, SEARCH_DEBOUNCE_MS + POST_DEBOUNCE_SLACK_MS));
|
||||||
await new Promise((r) => setTimeout(r, 250));
|
|
||||||
|
|
||||||
expect(fetchMock.mock.calls.length).toBe(fetchesBeforeClear);
|
expect(fetchMock.mock.calls.length).toBe(fetchesBeforeClear);
|
||||||
await expect.element(page.getByText('Auguste Raddatz')).not.toBeInTheDocument();
|
await expect.element(page.getByText('Auguste Raddatz')).not.toBeInTheDocument();
|
||||||
@@ -264,8 +268,7 @@ describe('PersonMentionEditor — whitespace-only query', () => {
|
|||||||
await expect.element(page.getByRole('searchbox')).toBeVisible();
|
await expect.element(page.getByRole('searchbox')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait beyond the debounce window so any trailing call would have fired.
|
await new Promise((r) => setTimeout(r, SEARCH_DEBOUNCE_MS + POST_DEBOUNCE_SLACK_MS));
|
||||||
await new Promise((r) => setTimeout(r, 300));
|
|
||||||
|
|
||||||
await expect.element(page.getByText(m.person_mention_search_prompt())).toBeInTheDocument();
|
await expect.element(page.getByText(m.person_mention_search_prompt())).toBeInTheDocument();
|
||||||
expect(fetchMock).not.toHaveBeenCalled();
|
expect(fetchMock).not.toHaveBeenCalled();
|
||||||
|
|||||||
Reference in New Issue
Block a user