diff --git a/src/App.test.tsx b/src/App.test.tsx index 42e83c92..8abc5fa6 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -257,13 +257,20 @@ function getHeaderForNoteList(noteListContainer: HTMLElement) { return within(noteListContainer.parentElement as HTMLElement).getByRole('heading', { level: 3 }) } -async function enterNeighborhood(noteListContainer: HTMLElement, title: string) { +async function clickNoteListItem(noteListContainer: HTMLElement, title: string, options?: MouseEventInit) { + await waitFor(() => { + expect(within(noteListContainer).getByText(title)).toBeInTheDocument() + }) await act(async () => { - fireEvent.click(within(noteListContainer).getByText(title), { metaKey: true }) + fireEvent.click(within(noteListContainer).getByText(title), options) await Promise.resolve() }) } +async function enterNeighborhood(noteListContainer: HTMLElement, title: string) { + await clickNoteListItem(noteListContainer, title, { metaKey: true }) +} + async function pressEscape() { await act(async () => { fireEvent.keyDown(window, { key: 'Escape' }) @@ -438,6 +445,7 @@ import { streamAiAgent } from './utils/streamAiAgent' const AI_AGENTS_ONBOARDING_DISMISSED_KEY = 'tolaria:ai-agents-onboarding-dismissed' const CLAUDE_CODE_ONBOARDING_DISMISSED_KEY = 'tolaria:claude-code-onboarding-dismissed' +const SLOW_APP_READY_TIMEOUT_MS = 10_000 function createMockUpdaterResult( checkForUpdates: () => Promise<{ kind: 'up-to-date' } | { kind: 'available'; version: string; displayVersion: string } | { kind: 'error'; message: string }> = async () => ({ kind: 'up-to-date' }), @@ -662,7 +670,7 @@ describe('App', () => { await waitFor(() => { expect(screen.getByText('AI agents ready')).toBeInTheDocument() - }) + }, { timeout: SLOW_APP_READY_TIMEOUT_MS }) await waitFor(() => { expect(typeof window.__laputaTest?.dispatchBrowserMenuCommand).toBe('function') @@ -931,7 +939,7 @@ describe('App', () => { await waitFor(() => { expect(screen.getByTestId('welcome-screen')).toBeInTheDocument() - }) + }, { timeout: SLOW_APP_READY_TIMEOUT_MS }) fireEvent.click(screen.getByTestId('welcome-open-folder')) @@ -1128,10 +1136,7 @@ describe('App', () => { expect(getHeaderForNoteList(noteListContainer)).toHaveTextContent('Inbox') }) - await act(async () => { - fireEvent.click(within(noteListContainer).getByText('Alpha')) - await Promise.resolve() - }) + await clickNoteListItem(noteListContainer, 'Alpha') await waitFor(() => { expect(screen.getByRole('button', { name: 'Set note as organized' })).toBeInTheDocument() @@ -1145,7 +1150,7 @@ describe('App', () => { await waitFor(() => { expect(window.__laputaTest?.activeTabPath).toBe('/vault/beta.md') }) - }) + }, 10_000) it('keeps the manually selected note after organizing finishes later', async () => { configureNeighborhoodVault() @@ -1172,10 +1177,7 @@ describe('App', () => { expect(getHeaderForNoteList(noteListContainer)).toHaveTextContent('Inbox') }) - await act(async () => { - fireEvent.click(within(noteListContainer).getByText('Alpha')) - await Promise.resolve() - }) + await clickNoteListItem(noteListContainer, 'Alpha') await waitFor(() => { expect(screen.getByRole('button', { name: 'Set note as organized' })).toBeInTheDocument() @@ -1202,7 +1204,7 @@ describe('App', () => { }) expect(window.__laputaTest?.activeTabPath).toBe('/vault/gamma.md') - }) + }, 10_000) it('renders status bar', async () => { render() diff --git a/src/components/TypeSelector.test.tsx b/src/components/TypeSelector.test.tsx index 5cefa3c0..c78001e4 100644 --- a/src/components/TypeSelector.test.tsx +++ b/src/components/TypeSelector.test.tsx @@ -1,5 +1,5 @@ import type { ComponentProps } from 'react' -import { fireEvent, render, screen, waitFor } from '@testing-library/react' +import { act, fireEvent, render, screen, waitFor } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' import { TypeSelector } from './TypeSelector' @@ -31,12 +31,17 @@ describe('TypeSelector', () => { const trigger = screen.getByRole('combobox') trigger.focus() - fireEvent.keyDown(trigger, { key: 'Enter' }) + await act(async () => { + fireEvent.keyDown(trigger, { key: 'Enter' }) + await new Promise((resolve) => { + requestAnimationFrame(() => resolve()) + }) + }) - const searchInput = screen.getByTestId('type-selector-search-input') - await waitFor(() => expect(searchInput).toHaveFocus()) + const searchInput = await screen.findByTestId('type-selector-search-input', {}, { timeout: 5_000 }) + await waitFor(() => expect(searchInput).toHaveFocus(), { timeout: 5_000 }) expect(screen.getByRole('option', { name: 'Project' })).toHaveAttribute('aria-selected', 'true') - }) + }, 10_000) it('filters available types as the user types', () => { renderTypeSelector()