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 }));