diff --git a/frontend/src/components/SearchView.tsx b/frontend/src/components/SearchView.tsx index 72c108a..8b0e50d 100644 --- a/frontend/src/components/SearchView.tsx +++ b/frontend/src/components/SearchView.tsx @@ -123,6 +123,12 @@ export function SearchView({ inputRef.current?.focus(); }, [prefillRequest]); + useEffect(() => { + return () => { + abortRef.current?.abort(); + }; + }, []); + // Fetch search results useEffect(() => { if (!debouncedQuery) { diff --git a/frontend/src/test/searchView.test.tsx b/frontend/src/test/searchView.test.tsx index b11f345..7ffb239 100644 --- a/frontend/src/test/searchView.test.tsx +++ b/frontend/src/test/searchView.test.tsx @@ -283,4 +283,35 @@ describe('SearchView', () => { expect.any(AbortSignal) ); }); + + it('aborts the load-more request on unmount', async () => { + const pageResults = Array.from({ length: 50 }, (_, i) => + createSearchResult({ id: i + 1, text: `result ${i}` }) + ); + let resolveLoadMore: ((value: Message[]) => void) | null = null; + mockGetMessages.mockResolvedValueOnce(pageResults).mockImplementationOnce( + () => + new Promise((resolve) => { + resolveLoadMore = resolve; + }) + ); + + const { unmount } = render(); + + await typeAndWaitForResults('result'); + fireEvent.click(screen.getByText('Load more results')); + + const loadMoreSignal = mockGetMessages.mock.calls[1]?.[1] as AbortSignal | undefined; + expect(loadMoreSignal).toBeInstanceOf(AbortSignal); + expect(loadMoreSignal?.aborted).toBe(false); + + unmount(); + + expect(loadMoreSignal?.aborted).toBe(true); + + await act(async () => { + resolveLoadMore?.([createSearchResult({ id: 99, text: 'late result' })]); + await Promise.resolve(); + }); + }); });