From 9772b28bd86c634de9719f7fbf2a26f69f999666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 21 May 2026 18:04:40 +0200 Subject: [PATCH] Restore dedup test and add split-count coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restore the 'does not re-fetch when backend filter params are unchanged' test from #34324 that was accidentally dropped during the rebase. Add a new test verifying that cursor navigation does not re-run the count query (the core split-count behavior). Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Fredrik Adelöw --- .../src/hooks/useEntityListProvider.test.tsx | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx index 02d5ef3960..a1f358d739 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx @@ -299,6 +299,46 @@ describe('', () => { }); }); + it('does not re-fetch when backend filter params are unchanged', async () => { + const deferred = createDeferred(); + mockCatalogApi.getEntities!.mockReturnValueOnce(deferred); + + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + act(() => { + result.current.updateFilters({ + kind: new EntityKindFilter('component', 'component'), + }); + }); + + await waitFor(() => { + expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(1); + }); + + act(() => { + result.current.updateFilters({ + kind: new EntityKindFilter('component', 'Component'), + }); + }); + act(() => { + result.current.updateFilters({ + user: EntityUserFilter.all(), + }); + }); + + await act(async () => { + deferred.resolve({ items: entities }); + }); + + await waitFor(() => { + expect(result.current.backendEntities.length).toBe(2); + }); + + expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(1); + }); + it('returns an error on catalogApi failure', async () => { const { result } = renderHook(() => useEntityList(), { wrapper: createWrapper({ pagination }), @@ -648,6 +688,47 @@ describe('', () => { }); }); + it('fetches count separately and does not re-count on cursor navigation', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + await waitFor(() => { + expect(result.current.backendEntities.length).toBe(2); + }); + + // The count query uses limit: 0 (without totalItems: 'exclude') + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith( + expect.objectContaining({ limit: 0 }), + ); + }); + + const countCallsBefore = ( + mockCatalogApi.queryEntities as jest.Mock + ).mock.calls.filter((c: any) => c[0]?.limit === 0).length; + + // Navigate to next page via cursor — should NOT re-run the count + act(() => { + result.current.pageInfo?.next?.(); + }); + + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith( + expect.objectContaining({ + cursor: expect.any(String), + totalItems: 'exclude', + }), + ); + }); + + const countCallsAfter = ( + mockCatalogApi.queryEntities as jest.Mock + ).mock.calls.filter((c: any) => c[0]?.limit === 0).length; + + expect(countCallsAfter).toBe(countCallsBefore); + }); + it('returns an error on catalogApi failure', async () => { const { result } = renderHook(() => useEntityList(), { wrapper: createWrapper({ pagination }),