diff --git a/.size-limits.json b/.size-limits.json
index b13d95f84a8..09bf55362fa 100644
--- a/.size-limits.json
+++ b/.size-limits.json
@@ -1,4 +1,4 @@
{
- "dist/apollo-client.min.cjs": 39605,
+ "dist/apollo-client.min.cjs": 39604,
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32852
}
diff --git a/src/react/hooks/__tests__/useLazyQuery.test.tsx b/src/react/hooks/__tests__/useLazyQuery.test.tsx
index 34981cf9b4e..08f94df5c60 100644
--- a/src/react/hooks/__tests__/useLazyQuery.test.tsx
+++ b/src/react/hooks/__tests__/useLazyQuery.test.tsx
@@ -26,8 +26,6 @@ import { useLazyQuery } from "../useLazyQuery";
import { QueryResult } from "../../types/types";
import { profileHook } from "../../../testing/internal";
-const IS_REACT_18 = React.version.startsWith("18");
-
describe("useLazyQuery Hook", () => {
const helloQuery: TypedDocumentNode<{
hello: string;
@@ -42,7 +40,7 @@ describe("useLazyQuery Hook", () => {
{
request: { query: helloQuery },
result: { data: { hello: "world" } },
- delay: 20,
+ delay: 50,
},
];
const { result } = renderHook(() => useLazyQuery(helloQuery), {
@@ -100,32 +98,34 @@ describe("useLazyQuery Hook", () => {
},
];
- const { result } = renderHook(() => useLazyQuery(helloQuery), {
+ const ProfiledHook = profileHook(() => useLazyQuery(helloQuery));
+
+ render(, {
wrapper: ({ children }) => (
{children}
),
});
- expect(result.current[1].loading).toBe(false);
- expect(result.current[1].called).toBe(false);
- const execute = result.current[0];
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.called).toBe(false);
+ }
+
+ const execute = ProfiledHook.getCurrentSnapshot()[0];
setTimeout(() => execute());
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current[1].called).toBe(true);
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.called).toBe(true);
+ }
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current[1].called).toBe(true);
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.called).toBe(true);
+ }
});
it("should override `skip` if lazy mode execution function is called", async () => {
@@ -137,36 +137,35 @@ describe("useLazyQuery Hook", () => {
},
];
- const { result } = renderHook(
+ const ProfiledHook = profileHook(
// skip isn’t actually an option on the types
- () => useLazyQuery(helloQuery, { skip: true } as any),
- {
- wrapper: ({ children }) => (
- {children}
- ),
- }
+ () => useLazyQuery(helloQuery, { skip: true } as any)
);
+ render(, {
+ wrapper: ({ children }) => (
+ {children}
+ ),
+ });
- expect(result.current[1].loading).toBe(false);
- expect(result.current[1].called).toBe(false);
- const execute = result.current[0];
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.called).toBe(false);
+ }
+ const execute = ProfiledHook.getCurrentSnapshot()[0];
setTimeout(() => execute());
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current[1].called).toBe(true);
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.called).toBe(true);
+ }
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current[1].called).toBe(true);
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.called).toBe(true);
+ }
});
it("should use variables defined in hook options (if any), when running the lazy execution function", async () => {
@@ -184,36 +183,34 @@ describe("useLazyQuery Hook", () => {
},
];
- const { result } = renderHook(
- () =>
- useLazyQuery(query, {
- variables: { id: 1 },
- }),
- {
- wrapper: ({ children }) => (
- {children}
- ),
- }
+ const ProfiledHook = profileHook(() =>
+ useLazyQuery(query, {
+ variables: { id: 1 },
+ })
);
+ render(, {
+ wrapper: ({ children }) => (
+ {children}
+ ),
+ });
- const execute = result.current[0];
- setTimeout(() => execute());
-
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ }
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
+ const execute = ProfiledHook.getCurrentSnapshot()[0];
+ setTimeout(() => execute());
- expect(result.current[1].data).toEqual({ hello: "world 1" });
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ }
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ hello: "world 1" });
+ }
});
it("should use variables passed into lazy execution function, overriding similar variables defined in Hook options", async () => {
@@ -544,7 +541,8 @@ describe("useLazyQuery Hook", () => {
];
const cache = new InMemoryCache();
- const { result } = renderHook(() => useLazyQuery(query1), {
+ const ProfiledHook = profileHook(() => useLazyQuery(query1));
+ render(, {
wrapper: ({ children }) => (
{children}
@@ -552,43 +550,37 @@ describe("useLazyQuery Hook", () => {
),
});
- expect(result.current[1].loading).toBe(false);
- expect(result.current[1].data).toBe(undefined);
- const execute = result.current[0];
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toBe(undefined);
+ }
+ const execute = ProfiledHook.getCurrentSnapshot()[0];
setTimeout(() => execute());
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
-
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toEqual({ hello: "world" });
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ }
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ hello: "world" });
+ }
setTimeout(() => execute({ query: query2 }));
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ }
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toEqual({ name: "changed" });
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ name: "changed" });
+ }
});
it('should fetch data each time the execution function is called, when using a "network-only" fetch policy', async () => {
@@ -605,54 +597,48 @@ describe("useLazyQuery Hook", () => {
},
];
- const { result } = renderHook(
- () =>
- useLazyQuery(helloQuery, {
- fetchPolicy: "network-only",
- }),
- {
- wrapper: ({ children }) => (
- {children}
- ),
- }
+ const ProfiledHook = profileHook(() =>
+ useLazyQuery(helloQuery, {
+ fetchPolicy: "network-only",
+ })
);
- expect(result.current[1].loading).toBe(false);
- const execute = result.current[0];
+ render(, {
+ wrapper: ({ children }) => (
+ {children}
+ ),
+ });
+
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ }
+ const execute = ProfiledHook.getCurrentSnapshot()[0];
setTimeout(() => execute());
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ }
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toEqual({ hello: "world 1" });
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ hello: "world 1" });
+ }
setTimeout(() => execute());
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toEqual({ hello: "world 1" });
-
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toEqual({ hello: "world 2" });
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toEqual({ hello: "world 1" });
+ }
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ hello: "world 2" });
+ }
});
it("should persist previous data when a query is re-run", async () => {
@@ -669,62 +655,55 @@ describe("useLazyQuery Hook", () => {
},
];
- const { result } = renderHook(
- () =>
- useLazyQuery(helloQuery, {
- notifyOnNetworkStatusChange: true,
- }),
- {
- wrapper: ({ children }) => (
- {children}
- ),
- }
+ const ProfiledHook = profileHook(() =>
+ useLazyQuery(helloQuery, {
+ notifyOnNetworkStatusChange: true,
+ })
);
- expect(result.current[1].loading).toBe(false);
- expect(result.current[1].data).toBe(undefined);
- expect(result.current[1].previousData).toBe(undefined);
- const execute = result.current[0];
+ render(, {
+ wrapper: ({ children }) => (
+ {children}
+ ),
+ });
+
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toBe(undefined);
+ expect(result.previousData).toBe(undefined);
+ }
+ const execute = ProfiledHook.getCurrentSnapshot()[0];
setTimeout(() => execute());
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toBe(undefined);
- expect(result.current[1].previousData).toBe(undefined);
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ expect(result.previousData).toBe(undefined);
+ }
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toEqual({ hello: "world 1" });
- expect(result.current[1].previousData).toBe(undefined);
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ hello: "world 1" });
+ expect(result.previousData).toBe(undefined);
+ }
- const refetch = result.current[1].refetch;
+ const refetch = ProfiledHook.getCurrentSnapshot()[1].refetch;
setTimeout(() => refetch!());
-
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toEqual({ hello: "world 1" });
- expect(result.current[1].previousData).toEqual({ hello: "world 1" });
-
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toEqual({ hello: "world 2" });
- expect(result.current[1].previousData).toEqual({ hello: "world 1" });
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toEqual({ hello: "world 1" });
+ expect(result.previousData).toEqual({ hello: "world 1" });
+ }
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ hello: "world 2" });
+ expect(result.previousData).toEqual({ hello: "world 1" });
+ }
});
it("should allow for the query to start with polling", async () => {
@@ -828,55 +807,49 @@ describe("useLazyQuery Hook", () => {
},
];
- const { result } = renderHook(() => useLazyQuery(CAR_QUERY_BY_ID), {
+ const ProfiledHook = profileHook(() => useLazyQuery(CAR_QUERY_BY_ID));
+ render(, {
wrapper: ({ children }) => (
{children}
),
});
- expect(result.current[1].loading).toBe(false);
- expect(result.current[1].data).toBe(undefined);
- expect(result.current[1].previousData).toBe(undefined);
- const execute = result.current[0];
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toBe(undefined);
+ expect(result.previousData).toBe(undefined);
+ }
+ const execute = ProfiledHook.getCurrentSnapshot()[0];
setTimeout(() => execute({ variables: { id: 1 } }));
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toBe(undefined);
- expect(result.current[1].previousData).toBe(undefined);
-
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toEqual(data1);
- expect(result.current[1].previousData).toBe(undefined);
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ expect(result.previousData).toBe(undefined);
+ }
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual(data1);
+ expect(result.previousData).toBe(undefined);
+ }
setTimeout(() => execute({ variables: { id: 2 } }));
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toBe(undefined);
- expect(result.current[1].previousData).toEqual(data1);
-
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current[1].data).toEqual(data2);
- expect(result.current[1].previousData).toEqual(data1);
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ expect(result.previousData).toEqual(data1);
+ }
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual(data2);
+ expect(result.previousData).toEqual(data1);
+ }
});
it("should work with cache-and-network fetch policy", async () => {
@@ -1769,72 +1742,39 @@ describe("useLazyQuery Hook", () => {
),
});
- const { result } = renderHook(
- () =>
- useLazyQuery(helloQuery, {
- errorPolicy,
- }),
- {
- wrapper: ({ children }) => (
- {children}
- ),
- }
+ const ProfiledHook = profileHook(() =>
+ useLazyQuery(helloQuery, {
+ errorPolicy,
+ })
);
+ render(, {
+ wrapper: ({ children }) => (
+ {children}
+ ),
+ });
- const execute = result.current[0];
- expect(result.current[1].loading).toBe(false);
- expect(result.current[1].networkStatus).toBe(NetworkStatus.ready);
- expect(result.current[1].data).toBeUndefined();
-
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.networkStatus).toBe(NetworkStatus.ready);
+ expect(result.data).toBeUndefined();
+ }
+ const execute = ProfiledHook.getCurrentSnapshot()[0];
setTimeout(execute);
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- if (IS_REACT_18) {
- expect(result.current[1].networkStatus).toBe(NetworkStatus.loading);
- } else {
- expect(result.current[1].networkStatus).toBe(NetworkStatus.error);
- }
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- expect(result.current[1].data).toBeUndefined();
- },
- { interval: 1 }
- );
-
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- expect(result.current[1].networkStatus).toBe(NetworkStatus.error);
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- expect(result.current[1].data).toBeUndefined();
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- expect(result.current[1].error!.message).toBe("from the network");
- },
- { interval: 1 }
- );
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.networkStatus).toBe(NetworkStatus.loading);
+ expect(result.data).toBeUndefined();
+ }
+ {
+ const [, result] = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.networkStatus).toBe(NetworkStatus.error);
+ expect(result.data).toBeUndefined();
+ expect(result.error!.message).toBe("from the network");
+ }
}
// For errorPolicy:"none", we expect result.error to be defined and
diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx
index f900f61bbda..bfcd534c7e3 100644
--- a/src/react/hooks/__tests__/useQuery.test.tsx
+++ b/src/react/hooks/__tests__/useQuery.test.tsx
@@ -23,18 +23,21 @@ import {
mockSingleLink,
tick,
wait,
+ MockedResponse,
} from "../../../testing";
import { QueryResult } from "../../types/types";
import { useQuery } from "../useQuery";
import { useMutation } from "../useMutation";
import {
createProfiler,
+ disableActWarnings,
profileHook,
spyOnConsole,
} from "../../../testing/internal";
import { useApolloClient } from "../useApolloClient";
import { useLazyQuery } from "../useLazyQuery";
+const IS_REACT_17 = React.version.startsWith("17");
const IS_REACT_19 = React.version.startsWith("19");
describe("useQuery Hook", () => {
@@ -769,6 +772,7 @@ describe("useQuery Hook", () => {
{
request: { query: query1 },
result: { data: allPeopleData },
+ delay: 3,
},
{
request: { query: query2 },
@@ -781,76 +785,49 @@ describe("useQuery Hook", () => {
link,
cache: new InMemoryCache(),
});
+ const ProfiledHook = profileHook(() => [
+ useQuery(query1, { fetchPolicy: "no-cache" }),
+ useQuery(query2),
+ ]);
+ const { rerender } = render(, {
+ wrapper: ({ children }) => (
+ {children}
+ ),
+ });
- const { result, rerender } = renderHook(
- () => [useQuery(query1, { fetchPolicy: "no-cache" }), useQuery(query2)],
- {
- wrapper: ({ children }) => (
- {children}
- ),
- }
- );
-
- expect(result.current[0].loading).toBe(true);
- expect(result.current[0].data).toBe(undefined);
- expect(result.current[1].loading).toBe(true);
- expect(result.current[1].data).toBe(undefined);
+ {
+ const [result0, result1] = await ProfiledHook.takeSnapshot();
+ expect(result0.loading).toBe(true);
+ expect(result0.data).toStrictEqual(undefined);
+ expect(result1.loading).toBe(true);
+ expect(result1.data).toStrictEqual(undefined);
+ }
- await waitFor(
- () => {
- expect(result.current[0].loading).toBe(false);
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- expect(result.current[0].data).toEqual(allPeopleData);
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(true);
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- expect(result.current[1].data).toBe(undefined);
- },
- { interval: 1 }
- );
+ {
+ const [result0, result1] = await ProfiledHook.takeSnapshot();
+ expect(result0.loading).toBe(false);
+ expect(result0.data).toStrictEqual(allPeopleData);
+ expect(result1.loading).toBe(true);
+ expect(result1.data).toStrictEqual(undefined);
+ }
- await waitFor(
- () => {
- expect(result.current[0].loading).toBe(false);
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- expect(result.current[0].data).toEqual(allPeopleData);
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- expect(result.current[1].loading).toBe(false);
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- expect(result.current[1].data).toEqual(allThingsData);
- },
- { interval: 1 }
- );
+ {
+ const [result0, result1] = await ProfiledHook.takeSnapshot();
+ expect(result0.loading).toBe(false);
+ expect(result0.data).toStrictEqual(allPeopleData);
+ expect(result1.loading).toBe(false);
+ expect(result1.data).toStrictEqual(allThingsData);
+ }
- rerender();
- expect(result.current[0].loading).toBe(false);
- expect(result.current[0].data).toEqual(allPeopleData);
- expect(result.current[1].loading).toBe(false);
- expect(result.current[1].data).toEqual(allThingsData);
+ rerender();
+ {
+ const [result0, result1] = await ProfiledHook.takeSnapshot();
+ expect(result0.loading).toBe(false);
+ expect(result0.data).toStrictEqual(allPeopleData);
+ expect(result1.loading).toBe(false);
+ expect(result1.data).toStrictEqual(allThingsData);
+ }
+ await expect(ProfiledHook).not.toRerender();
});
it("changing queries", async () => {
@@ -1840,18 +1817,21 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
hello
}
`;
- const mocks = [
+ const mocks: MockedResponse[] = [
{
request: { query },
result: { data: { hello: "world 1" } },
+ delay: 10,
},
{
request: { query },
result: { data: { hello: "world 2" } },
+ delay: 10,
},
{
request: { query },
result: { data: { hello: "world 3" } },
+ delay: 10,
},
];
@@ -1867,30 +1847,24 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
);
- const { result, unmount } = renderHook(
- () => useQuery(query, { pollInterval: 10 }),
- { wrapper }
+ const ProfiledHook = profileHook(() =>
+ useQuery(query, { pollInterval: 20 })
);
- expect(result.current.loading).toBe(true);
- expect(result.current.data).toBe(undefined);
+ const { unmount } = render(, { wrapper });
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- await waitFor(
- () => {
- expect(result.current.data).toEqual({ hello: "world 1" });
- },
- { interval: 1 }
- );
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ }
- await waitFor(() => {
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ hello: "world 1" });
expect(requestSpy).toHaveBeenCalled();
- });
+ }
const requestCount = requestSpy.mock.calls.length;
expect(requestCount).toBeGreaterThan(0);
@@ -1905,7 +1879,7 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
const newRequestCount = requestSpy.mock.calls.length;
expect(newRequestCount).toBeGreaterThan(requestCount);
},
- { interval: 1, timeout: 20 }
+ { interval: 1, timeout: 40 }
)
).rejects.toThrow();
@@ -1925,18 +1899,21 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
}
`;
- const mocks = [
+ const mocks: MockedResponse[] = [
{
request: { query },
result: { data: { hello: "world 1" } },
+ delay: 3,
},
{
request: { query },
result: { data: { hello: "world 2" } },
+ delay: 3,
},
{
request: { query },
result: { data: { hello: "world 3" } },
+ delay: 3,
},
];
@@ -1992,6 +1969,7 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
await expect(ProfiledHook).not.toRerender({ timeout: 50 });
+ // TODO rarely seeing 3 here (also old `useQuery` implementation)
expect(requestSpy).toHaveBeenCalledTimes(2);
expect(onErrorFn).toHaveBeenCalledTimes(0);
});
@@ -2078,18 +2056,21 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
}
`;
- const mocks = [
+ const mocks: MockedResponse[] = [
{
request: { query },
result: { data: { hello: "world 1" } },
+ delay: 3,
},
{
request: { query },
result: { data: { hello: "world 2" } },
+ delay: 3,
},
{
request: { query },
result: { data: { hello: "world 3" } },
+ delay: 3,
},
];
@@ -2142,7 +2123,7 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
unmount();
await expect(ProfiledHook).not.toRerender({ timeout: 50 });
-
+ // TODO rarely seeing 3 here investigate further
expect(requestSpy).toHaveBeenCalledTimes(2);
expect(onErrorFn).toHaveBeenCalledTimes(0);
});
@@ -3581,47 +3562,42 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
);
- const { result } = renderHook(
- () => useQuery(query, { notifyOnNetworkStatusChange: true }),
- { wrapper }
+ const ProfiledHook = profileHook(() =>
+ useQuery(query, { notifyOnNetworkStatusChange: true })
);
+ render(, { wrapper });
- expect(result.current.loading).toBe(true);
- expect(result.current.data).toBe(undefined);
- expect(result.current.error).toBe(undefined);
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ expect(result.error).toBe(undefined);
+ }
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.data).toBe(undefined);
- expect(result.current.error).toBeInstanceOf(ApolloError);
- expect(result.current.error!.message).toBe("error 1");
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toBe(undefined);
+ expect(result.error).toBeInstanceOf(ApolloError);
+ expect(result.error!.message).toBe("error 1");
+ }
const catchFn = jest.fn();
+ ProfiledHook.getCurrentSnapshot().refetch().catch(catchFn);
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ expect(result.error).toBe(undefined);
+ }
- result.current.refetch().catch(catchFn);
- await waitFor(
- () => {
- expect(result.current.loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current.data).toBe(undefined);
- expect(result.current.error).toBe(undefined);
-
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.data).toBe(undefined);
- expect(result.current.error).toBeInstanceOf(ApolloError);
- expect(result.current.error!.message).toBe("error 2");
-
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toBe(undefined);
+ expect(result.error).toBeInstanceOf(ApolloError);
+ expect(result.error!.message).toBe("error 2");
+ }
expect(catchFn.mock.calls.length).toBe(1);
expect(catchFn.mock.calls[0].length).toBe(1);
expect(catchFn.mock.calls[0][0]).toBeInstanceOf(ApolloError);
@@ -3729,68 +3705,55 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
);
- const { result } = renderHook(
- () => useQuery(query, { notifyOnNetworkStatusChange: true }),
- { wrapper }
- );
-
- expect(result.current.loading).toBe(true);
- expect(result.current.data).toBe(undefined);
- expect(result.current.error).toBe(undefined);
-
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
-
- expect(result.current.data).toBe(undefined);
- expect(result.current.error).toBeInstanceOf(ApolloError);
- expect(result.current.error!.message).toBe("same error");
-
- result.current.refetch();
-
- await waitFor(
- () => {
- expect(result.current.loading).toBe(true);
- },
- { interval: 1 }
+ const ProfiledHook = profileHook(() =>
+ useQuery(query, { notifyOnNetworkStatusChange: true })
);
- expect(result.current.data).toBe(undefined);
- expect(result.current.error).toBe(undefined);
+ render(, { wrapper });
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.data).toEqual({ hello: "world" });
- expect(result.current.error).toBe(undefined);
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ expect(result.error).toBe(undefined);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toBe(undefined);
+ expect(result.error).toBeInstanceOf(ApolloError);
+ expect(result.error!.message).toBe("same error");
+ }
+ ProfiledHook.getCurrentSnapshot().refetch();
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ expect(result.error).toBe(undefined);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ hello: "world" });
+ expect(result.error).toBe(undefined);
+ }
const catchFn = jest.fn();
- result.current.refetch().catch(catchFn);
-
- await waitFor(
- () => {
- expect(result.current.loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current.data).toEqual({ hello: "world" });
- expect(result.current.error).toBe(undefined);
+ ProfiledHook.getCurrentSnapshot().refetch().catch(catchFn);
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- // TODO: Is this correct behavior here?
- expect(result.current.data).toEqual({ hello: "world" });
- expect(result.current.error).toBeInstanceOf(ApolloError);
- expect(result.current.error!.message).toBe("same error");
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toEqual({ hello: "world" });
+ expect(result.error).toBe(undefined);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ // TODO: Is this correct behavior here?
+ expect(result.data).toEqual({ hello: "world" });
+ expect(result.error).toBeInstanceOf(ApolloError);
+ expect(result.error!.message).toBe("same error");
+ }
expect(catchFn.mock.calls.length).toBe(1);
expect(catchFn.mock.calls[0].length).toBe(1);
@@ -5222,42 +5185,35 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
);
- const { result } = renderHook(
- () =>
- useQuery(query, {
- variables: { id: 1 },
- notifyOnNetworkStatusChange: true,
- }),
- { wrapper }
+ const ProfiledHook = profileHook(() =>
+ useQuery(query, {
+ variables: { id: 1 },
+ notifyOnNetworkStatusChange: true,
+ })
);
- expect(result.current.loading).toBe(true);
- expect(result.current.data).toBe(undefined);
-
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.data).toEqual({ hello: "world 1" });
-
- result.current.refetch({ id: 2 });
- await waitFor(
- () => {
- expect(result.current.loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current.data).toBe(undefined);
-
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.data).toEqual({ hello: "world 2" });
+ render(, { wrapper });
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ hello: "world 1" });
+ }
+ ProfiledHook.getCurrentSnapshot().refetch({ id: 2 });
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ hello: "world 2" });
+ }
});
it("refetching after an error", async () => {
@@ -5285,69 +5241,60 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
const cache = new InMemoryCache();
- const { result } = renderHook(
- () =>
- useQuery(query, {
- notifyOnNetworkStatusChange: true,
- }),
- {
- wrapper: ({ children }) => (
-
- {children}
-
- ),
- }
+ const ProfiledHook = profileHook(() =>
+ useQuery(query, {
+ notifyOnNetworkStatusChange: true,
+ })
);
- expect(result.current.loading).toBe(true);
- expect(result.current.data).toBe(undefined);
-
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.error).toBe(undefined);
- expect(result.current.data).toEqual({ hello: "world 1" });
+ render(, {
+ wrapper: ({ children }) => (
+
+ {children}
+
+ ),
+ });
- result.current.refetch();
- await waitFor(
- () => {
- expect(result.current.loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current.error).toBe(undefined);
- expect(result.current.data).toEqual({ hello: "world 1" });
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.error).toBe(undefined);
+ expect(result.data).toEqual({ hello: "world 1" });
+ }
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.error).toBeInstanceOf(ApolloError);
- expect(result.current.data).toEqual({ hello: "world 1" });
+ ProfiledHook.getCurrentSnapshot().refetch();
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.error).toBe(undefined);
+ expect(result.data).toEqual({ hello: "world 1" });
+ }
- result.current.refetch();
- await waitFor(
- () => {
- expect(result.current.loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current.error).toBe(undefined);
- expect(result.current.data).toEqual({ hello: "world 1" });
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.error).toBeInstanceOf(ApolloError);
+ expect(result.data).toEqual({ hello: "world 1" });
+ }
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.error).toBe(undefined);
- expect(result.current.data).toEqual({ hello: "world 2" });
+ ProfiledHook.getCurrentSnapshot().refetch();
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.error).toBe(undefined);
+ expect(result.data).toEqual({ hello: "world 1" });
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.error).toBe(undefined);
+ expect(result.data).toEqual({ hello: "world 2" });
+ }
});
describe("refetchWritePolicy", () => {
@@ -5603,73 +5550,67 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
{children}
);
-
- const { result } = renderHook(
- () =>
- useQuery(query, {
- variables: { min: 0, max: 12 },
- notifyOnNetworkStatusChange: true,
- // Intentionally not passing refetchWritePolicy.
- }),
- { wrapper }
+ const ProfiledHook = profileHook(() =>
+ useQuery(query, {
+ variables: { min: 0, max: 12 },
+ notifyOnNetworkStatusChange: true,
+ // Intentionally not passing refetchWritePolicy.
+ })
);
- expect(result.current.loading).toBe(true);
- expect(result.current.error).toBe(undefined);
- expect(result.current.data).toBe(undefined);
- expect(typeof result.current.refetch).toBe("function");
+ render(, { wrapper });
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.error).toBeUndefined();
- expect(result.current.data).toEqual({ primes: [2, 3, 5, 7, 11] });
- expect(mergeParams).toEqual([[void 0, [2, 3, 5, 7, 11]]]);
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.error).toBe(undefined);
+ expect(result.data).toBe(undefined);
+ expect(typeof result.refetch).toBe("function");
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.error).toBeUndefined();
+ expect(result.data).toEqual({ primes: [2, 3, 5, 7, 11] });
+ expect(mergeParams.shift()).toEqual([void 0, [2, 3, 5, 7, 11]]);
+ }
const thenFn = jest.fn();
- result.current.refetch({ min: 12, max: 30 }).then(thenFn);
+ ProfiledHook.getCurrentSnapshot()
+ .refetch({ min: 12, max: 30 })
+ .then(thenFn);
- await waitFor(
- () => {
- expect(result.current.loading).toBe(true);
- },
- { interval: 1 }
- );
- expect(result.current.error).toBe(undefined);
- expect(result.current.data).toEqual({
- // We get the stale data because we configured keyArgs: false.
- primes: [2, 3, 5, 7, 11],
- });
-
- // This networkStatus is setVariables instead of refetch because we
- // called refetch with new variables.
- expect(result.current.networkStatus).toBe(NetworkStatus.setVariables);
-
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.error).toBe(undefined);
+ expect(result.data).toEqual({
+ // We get the stale data because we configured keyArgs: false.
+ primes: [2, 3, 5, 7, 11],
+ });
+ // This networkStatus is setVariables instead of refetch because we
+ // called refetch with new variables.
+ expect(result.networkStatus).toBe(NetworkStatus.setVariables);
+ }
- expect(result.current.error).toBe(undefined);
- expect(result.current.data).toEqual({ primes: [13, 17, 19, 23, 29] });
- expect(mergeParams).toEqual([
- [undefined, [2, 3, 5, 7, 11]],
- // Without refetchWritePolicy: "overwrite", this array will be
- // all 10 primes (2 through 29) together.
- [undefined, [13, 17, 19, 23, 29]],
- ]);
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.error).toBe(undefined);
+ expect(result.data).toEqual({ primes: [13, 17, 19, 23, 29] });
+ expect(mergeParams.shift()).toEqual(
+ // Without refetchWritePolicy: "overwrite", this array will be
+ // all 10 primes (2 through 29) together.
+ [undefined, [13, 17, 19, 23, 29]]
+ );
- expect(thenFn).toHaveBeenCalledTimes(1);
- expect(thenFn).toHaveBeenCalledWith({
- loading: false,
- networkStatus: NetworkStatus.ready,
- data: { primes: [13, 17, 19, 23, 29] },
- });
+ expect(thenFn).toHaveBeenCalledTimes(1);
+ expect(thenFn).toHaveBeenCalledWith({
+ loading: false,
+ networkStatus: NetworkStatus.ready,
+ data: { primes: [13, 17, 19, 23, 29] },
+ });
+ }
});
});
@@ -6095,63 +6036,72 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
{
request: { query },
result: { data: { hello: "world 1" } },
+ delay: 3,
},
{
request: { query },
result: { data: { hello: "world 2" } },
+ delay: 3,
},
{
request: { query },
result: { data: { hello: "world 3" } },
+ delay: 3,
},
];
const cache = new InMemoryCache();
const onCompleted = jest.fn();
- const { result } = renderHook(
- () =>
- useQuery(query, {
- onCompleted,
- notifyOnNetworkStatusChange: true,
- pollInterval: 10,
- }),
- {
- wrapper: ({ children }) => (
-
- {children}
-
- ),
- }
- );
-
- expect(result.current.loading).toBe(true);
-
- await waitFor(
- () => {
- expect(result.current.data).toEqual({ hello: "world 1" });
- },
- { interval: 1 }
- );
- expect(result.current.loading).toBe(false);
- expect(onCompleted).toHaveBeenCalledTimes(1);
-
- await waitFor(
- () => {
- expect(result.current.data).toEqual({ hello: "world 2" });
- },
- { interval: 1 }
+ const ProfiledHook = profileHook(() =>
+ useQuery(query, {
+ onCompleted,
+ notifyOnNetworkStatusChange: true,
+ pollInterval: 110,
+ })
);
- expect(result.current.loading).toBe(false);
- expect(onCompleted).toHaveBeenCalledTimes(2);
+ render(, {
+ wrapper: ({ children }) => (
+
+ {children}
+
+ ),
+ });
- await waitFor(
- () => {
- expect(result.current.data).toEqual({ hello: "world 3" });
- },
- { interval: 1 }
- );
- expect(result.current.loading).toBe(false);
- expect(onCompleted).toHaveBeenCalledTimes(3);
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.data).toEqual(undefined);
+ expect(result.loading).toBe(true);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.data).toEqual({ hello: "world 1" });
+ expect(result.loading).toBe(false);
+ expect(onCompleted).toHaveBeenCalledTimes(1);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.data).toEqual({ hello: "world 1" });
+ expect(result.loading).toBe(true);
+ expect(onCompleted).toHaveBeenCalledTimes(1);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.data).toEqual({ hello: "world 2" });
+ expect(result.loading).toBe(false);
+ expect(onCompleted).toHaveBeenCalledTimes(2);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.data).toEqual({ hello: "world 2" });
+ expect(result.loading).toBe(true);
+ expect(onCompleted).toHaveBeenCalledTimes(2);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.data).toEqual({ hello: "world 3" });
+ expect(result.loading).toBe(false);
+ expect(onCompleted).toHaveBeenCalledTimes(3);
+ }
});
// This test was added for issue https://github.com/apollographql/apollo-client/issues/9794
@@ -6396,83 +6346,92 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
);
const onError = jest.fn();
- const { result } = renderHook(
- () => ({
- mutation: useMutation(mutation, {
- optimisticResponse: { addCar: carData },
- update(cache, { data }) {
- cache.modify({
- fields: {
- cars(existing, { readField }) {
- const newCarRef = cache.writeFragment({
- data: data!.addCar,
- fragment: gql`
- fragment NewCar on Car {
- id
- make
- model
- }
- `,
- });
-
- if (
- existing.some(
- (ref: Reference) =>
- readField("id", ref) === data!.addCar.id
- )
- ) {
- return existing;
- }
-
- return [...existing, newCarRef];
- },
+ const ProfiledHook = profileHook(() => ({
+ mutation: useMutation(mutation, {
+ optimisticResponse: { addCar: carData },
+ update(cache, { data }) {
+ cache.modify({
+ fields: {
+ cars(existing, { readField }) {
+ const newCarRef = cache.writeFragment({
+ data: data!.addCar,
+ fragment: gql`
+ fragment NewCar on Car {
+ id
+ make
+ model
+ }
+ `,
+ });
+
+ if (
+ existing.some(
+ (ref: Reference) =>
+ readField("id", ref) === data!.addCar.id
+ )
+ ) {
+ return existing;
+ }
+
+ return [...existing, newCarRef];
},
- });
- },
- onError,
- }),
- query: useQuery(query),
+ },
+ });
+ },
+ onError,
}),
- { wrapper }
- );
-
- expect(result.current.query.loading).toBe(true);
- const mutate = result.current.mutation[0];
+ query: useQuery(query),
+ }));
+ render(, { wrapper });
- await waitFor(
- () => {
- expect(result.current.query.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.query.loading).toBe(false);
- expect(result.current.query.data).toEqual(carsData);
+ {
+ const { query } = await ProfiledHook.takeSnapshot();
+ expect(query.loading).toBe(true);
+ }
+ const mutate = ProfiledHook.getCurrentSnapshot().mutation[0];
+ {
+ const { query } = await ProfiledHook.takeSnapshot();
+ expect(query.loading).toBe(false);
+ expect(query.loading).toBe(false);
+ expect(query.data).toEqual(carsData);
+ }
act(() => void mutate());
- // The mutation ran and is loading the result. The query stays at not
- // loading as nothing has changed for the query, but optimistic data is
- // rendered.
- expect(result.current.mutation[1].loading).toBe(true);
- expect(result.current.query.loading).toBe(false);
- expect(result.current.query.data).toEqual(allCarsData);
+ {
+ // The mutation ran and is loading the result. The query stays at not
+ // loading as nothing has changed for the query, but optimistic data is
+ // rendered.
+ let { query, mutation } = await ProfiledHook.takeSnapshot();
+
+ while (!mutation[1].loading) {
+ // useMutation seems to sometimes have an extra render
+ // before it enters `loading` state - this test doesn't test
+ // that part of that hook so we just work around it
+ ({ query, mutation } = await ProfiledHook.takeSnapshot());
+ }
+ expect(mutation[1].loading).toBe(true);
+ expect(query.loading).toBe(false);
+ expect(query.data).toEqual(allCarsData);
+ }
expect(onError).toHaveBeenCalledTimes(0);
- await tick();
- // The mutation ran and is loading the result. The query stays at
- // not loading as nothing has changed for the query.
- expect(result.current.mutation[1].loading).toBe(true);
- expect(result.current.query.loading).toBe(false);
-
- await waitFor(() => {
- expect(result.current.mutation[1].loading).toBe(false);
- });
+ {
+ const { query, mutation } = await ProfiledHook.takeSnapshot();
+ // The mutation ran and is loading the result. The query stays at
+ // not loading as nothing has changed for the query.
+ expect(mutation[1].loading).toBe(true);
+ expect(query.loading).toBe(false);
+ }
- // The mutation has completely finished, leaving the query with access to
- // the original cache data.
- expect(result.current.mutation[1].loading).toBe(false);
- expect(result.current.query.loading).toBe(false);
- expect(result.current.query.data).toEqual(carsData);
+ {
+ const { query, mutation } = await ProfiledHook.takeSnapshot();
+ // The mutation has completely finished, leaving the query with access to
+ // the original cache data.
+ expect(mutation[1].loading).toBe(false);
+ expect(query.loading).toBe(false);
+ expect(query.data).toEqual(carsData);
+ }
expect(onError).toHaveBeenCalledTimes(1);
expect(onError.mock.calls[0][0].message).toBe("Oh no!");
@@ -6618,6 +6577,7 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
});
it("should attempt a refetch when data is missing, partialRefetch is true and addTypename is false for the cache", async () => {
+ using _disabledActWarnings = disableActWarnings();
using consoleSpy = spyOnConsole("error");
const query = gql`
{
@@ -6648,43 +6608,45 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
{children}
);
- const { result } = renderHook(
- () =>
- useQuery(query, {
- partialRefetch: true,
- notifyOnNetworkStatusChange: true,
- }),
- { wrapper }
+ const ProfiledHook = profileHook(() =>
+ useQuery(query, {
+ partialRefetch: true,
+ notifyOnNetworkStatusChange: true,
+ })
);
- expect(result.current.loading).toBe(true);
- expect(result.current.data).toBe(undefined);
- expect(result.current.error).toBe(undefined);
- expect(result.current.networkStatus).toBe(NetworkStatus.loading);
+ render(, { wrapper });
- await waitFor(
- () => {
- expect(result.current.networkStatus).toBe(NetworkStatus.refetch);
- },
- { interval: 1 }
- );
- expect(result.current.loading).toBe(true);
- expect(result.current.error).toBe(undefined);
- expect(result.current.data).toBe(undefined);
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.data).toBe(undefined);
+ expect(result.error).toBe(undefined);
+ expect(result.networkStatus).toBe(NetworkStatus.loading);
+ }
- expect(consoleSpy.error).toHaveBeenCalledTimes(1);
- expect(consoleSpy.error.mock.calls[0][0]).toMatch("Missing field");
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.networkStatus).toBe(NetworkStatus.refetch);
+ expect(result.loading).toBe(true);
+ expect(result.error).toBe(undefined);
+ expect(result.data).toBe(undefined);
+ }
- await waitFor(
- () => {
- expect(result.current.networkStatus).toBe(NetworkStatus.ready);
- },
- { interval: 1 }
- );
+ const calls = consoleSpy.error.mock.calls;
+ if (!IS_REACT_17) {
+ // React 17 doesn't know `IS_REACT_ACT_ENVIRONMENT` yet, so it will log a warning that we don't care about.
+ expect(calls.length).toBe(1);
+ }
+ expect(calls[0][0]).toMatch("Missing field");
- expect(result.current.loading).toBe(false);
- expect(result.current.data).toEqual({ hello: "world" });
- expect(result.current.error).toBe(undefined);
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.networkStatus).toBe(NetworkStatus.ready);
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual({ hello: "world" });
+ expect(result.error).toBe(undefined);
+ }
});
});
@@ -7948,66 +7910,67 @@ This is pure coincidence though, and the useQuery rewrite that doesn't break the
);
- const { result, rerender } = renderHook(
- ({ gender }) =>
- useQuery(query, {
- variables: { gender },
- fetchPolicy: "network-only",
- }),
- { wrapper, initialProps: { gender: "all" } }
+ const ProfiledHook = profileHook(({ gender }: { gender: string }) =>
+ useQuery(query, {
+ variables: { gender },
+ fetchPolicy: "network-only",
+ })
);
+ const { rerender } = render(, { wrapper });
- expect(result.current.loading).toBe(true);
- expect(result.current.networkStatus).toBe(NetworkStatus.loading);
- expect(result.current.data).toBe(undefined);
-
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.networkStatus).toBe(NetworkStatus.loading);
+ expect(result.data).toBe(undefined);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.networkStatus).toBe(NetworkStatus.ready);
+ expect(result.data).toEqual({
+ people: peopleData.map(({ gender, ...person }) => person),
+ });
+ }
- expect(result.current.networkStatus).toBe(NetworkStatus.ready);
- expect(result.current.data).toEqual({
- people: peopleData.map(({ gender, ...person }) => person),
- });
+ rerender();
- rerender({ gender: "female" });
- expect(result.current.loading).toBe(true);
- expect(result.current.networkStatus).toBe(NetworkStatus.setVariables);
- expect(result.current.data).toBe(undefined);
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.networkStatus).toBe(NetworkStatus.setVariables);
+ expect(result.data).toBe(undefined);
+ }
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.networkStatus).toBe(NetworkStatus.ready);
- expect(result.current.data).toEqual({
- people: peopleData
- .filter((person) => person.gender === "female")
- .map(({ gender, ...person }) => person),
- });
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.networkStatus).toBe(NetworkStatus.ready);
+ expect(result.data).toEqual({
+ people: peopleData
+ .filter((person) => person.gender === "female")
+ .map(({ gender, ...person }) => person),
+ });
+ }
- rerender({ gender: "nonbinary" });
- expect(result.current.loading).toBe(true);
- expect(result.current.networkStatus).toBe(NetworkStatus.setVariables);
- expect(result.current.data).toBe(undefined);
+ rerender();
- await waitFor(
- () => {
- expect(result.current.loading).toBe(false);
- },
- { interval: 1 }
- );
- expect(result.current.networkStatus).toBe(NetworkStatus.ready);
- expect(result.current.data).toEqual({
- people: peopleData
- .filter((person) => person.gender === "nonbinary")
- .map(({ gender, ...person }) => person),
- });
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(true);
+ expect(result.networkStatus).toBe(NetworkStatus.setVariables);
+ expect(result.data).toBe(undefined);
+ }
+ {
+ const result = await ProfiledHook.takeSnapshot();
+ expect(result.loading).toBe(false);
+ expect(result.networkStatus).toBe(NetworkStatus.ready);
+ expect(result.data).toEqual({
+ people: peopleData
+ .filter((person) => person.gender === "nonbinary")
+ .map(({ gender, ...person }) => person),
+ });
+ }
});
});