diff --git a/frontend/src/test/appSearchJump.test.tsx b/frontend/src/test/appSearchJump.test.tsx index bb0daef..9345005 100644 --- a/frontend/src/test/appSearchJump.test.tsx +++ b/frontend/src/test/appSearchJump.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; import { beforeEach, describe, expect, it, vi } from 'vitest'; const PUBLIC_CHANNEL_KEY = '8B3387E9C5CDEA6AC9E5EDBAA115CD72'; @@ -236,7 +236,9 @@ describe('App search jump target handling', () => { }); it('clears jump target when user selects a non-search conversation', async () => { - render(); + await act(async () => { + render(); + }); await waitFor(() => { expect(screen.getAllByText('Open Search').length).toBeGreaterThan(0); @@ -267,7 +269,9 @@ describe('App search jump target handling', () => { }); it('opens search with a prefilled query from the contact pane', async () => { - render(); + await act(async () => { + render(); + }); await waitFor(() => { expect(screen.getByText('Search Contact By Key')).toBeInTheDocument(); diff --git a/frontend/src/test/appStartupHash.test.tsx b/frontend/src/test/appStartupHash.test.tsx index 9096afd..9288273 100644 --- a/frontend/src/test/appStartupHash.test.tsx +++ b/frontend/src/test/appStartupHash.test.tsx @@ -181,7 +181,10 @@ describe('App startup hash resolution', () => { }); afterEach(() => { - window.location.hash = ''; + // window.location.hash is intentionally NOT reset here: setting it fires a hashchange + // event while the component is still mounted (RTL cleanup runs after this describe-level + // hook), which queues a stale state update that races the next test's setup. beforeEach + // sets a known hash before each render, so this reset is redundant. localStorage.clear(); }); @@ -443,6 +446,12 @@ describe('App startup hash resolution', () => { } }); + // Flush any pending React work (contacts render + its effects) so that + // contactsRef.current is populated before the popstate handler reads it. + // waitFor may resolve after the channels render commits but before the + // contacts render commits, leaving contactsRef.current=[]. + await act(async () => {}); + act(() => { window.location.hash = `#contact/${aliceContact.public_key}/Alice`; window.dispatchEvent(new PopStateEvent('popstate', { state: null }));