diff --git a/common/changes/@itwin/imodel-browser-react/hans-fix_imodel_fetch_when_not_yet_loaded_2025-10-10-02-55.json b/common/changes/@itwin/imodel-browser-react/hans-fix_imodel_fetch_when_not_yet_loaded_2025-10-10-02-55.json new file mode 100644 index 00000000..11e82f7c --- /dev/null +++ b/common/changes/@itwin/imodel-browser-react/hans-fix_imodel_fetch_when_not_yet_loaded_2025-10-10-02-55.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/imodel-browser-react", + "comment": "Fixed bug where fetching never happens when access token has not yet loaded", + "type": "patch" + } + ], + "packageName": "@itwin/imodel-browser-react" +} \ No newline at end of file diff --git a/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.test.ts b/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.test.ts index 765a1ac9..1945d179 100644 --- a/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.test.ts +++ b/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.test.ts @@ -353,6 +353,54 @@ describe("useIModelData hook", () => { expect(result.current.fetchMore).toBeUndefined(); expect(watcher).toHaveBeenCalledTimes(2); }); + + it.each([ + { + missing: "accessToken", + initialProps: { accessToken: undefined as any, iTwinId: "iTwinId" }, + supplyProps: { accessToken: "accessToken" }, + }, + { + missing: "iTwinId", + initialProps: { iTwinId: undefined as any, accessToken: "accessToken" }, + supplyProps: { iTwinId: "iTwinId" }, + }, + ])( + "does not skip first page if fetchMore called before $missing becomes available", + async ({ initialProps, supplyProps }) => { + const fetchSpy = jest.spyOn(window, "fetch").mockImplementation( + () => + Promise.resolve({ + ok: true, + json: () => + Promise.resolve({ + iModels: [{ id: "first", displayName: "first" }], + }), + }) as any + ); + + const { result, rerender, waitForNextUpdate } = renderHook( + (props: any) => + useIModelData({ + iTwinId: (props as any).iTwinId, + accessToken: (props as any).accessToken, + }), + { initialProps } + ); + + // Attempt pagination before prerequisite present + act(() => result.current.fetchMore?.()); + + // Provide missing prerequisite + rerender({ ...initialProps, ...supplyProps }); + await waitForNextUpdate(); + + const firstUrl = fetchSpy.mock.calls[0][0] as string; + expect(firstUrl).toContain("$skip=0"); + expect(firstUrl).toContain("$top=100"); + expect(result.current.iModels[0]?.id).toBe("first"); + } + ); }); it("fetches data with searchText", async () => { diff --git a/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.ts b/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.ts index cbed4b74..be017487 100644 --- a/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.ts +++ b/packages/modules/imodel-browser/src/containers/iModelGrid/useIModelData.ts @@ -73,7 +73,13 @@ export const useIModelData = ({ }, []); const fetchMore = React.useCallback(() => { - if (needsUpdate || status === DataStatus.Fetching || !morePagesAvailable) { + if ( + needsUpdate || + status === DataStatus.Fetching || + status === DataStatus.TokenRequired || + status === DataStatus.ContextRequired || + !morePagesAvailable + ) { return; } setPage(page + 1);