From 127fff223073de7c9d271ce24eedc1c4539f68cd Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 14:46:50 -0700 Subject: [PATCH 01/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 91 ++++++++++++--------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 769a89ae265..69d73b1c40e 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -2330,51 +2330,68 @@ describe("useQuery Hook", () => { ); - const { result } = renderHook( - () => useQuery(query, { pollInterval: 10 }), - { wrapper } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => useQuery(query, { pollInterval: 10 }), + { wrapper } + ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 1" }); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.loading).toBe(false); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 2" }); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: { hello: "world 1" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.loading).toBe(false); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 3" }); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); + } - expect(result.current.loading).toBe(false); + { + const result = await takeSnapshot(); - const { data: previousData } = result.current; - result.current.stopPolling(); - await expect( - waitFor( - () => { - expect(result.current.data).not.toEqual(previousData); - }, - { interval: 1, timeout: 20 } - ) - ).rejects.toThrow(); + expect(result).toEqualQueryResult({ + data: { hello: "world 3" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 2" }, + variables: {}, + }); + } + + getCurrentSnapshot().stopPolling(); + + await expect(takeSnapshot).not.toRerender(); }); it("should start polling when skip goes from true to false", async () => { From c7afbd3aa4733f0a70a979b8b3dd96ab21ca1de5 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 14:52:39 -0700 Subject: [PATCH 02/33] Rewrite test with toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 76 +++++++++++++++++---- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 69d73b1c40e..6c56c6d728a 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -2429,43 +2429,93 @@ describe("useQuery Hook", () => { ), } ); + { const result = await takeSnapshot(); - expect(result.loading).toBe(true); - expect(result.data).toBe(undefined); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); } + { const result = await takeSnapshot(); - expect(result.loading).toBe(false); - expect(result.data).toEqual({ hello: "world 1" }); + + expect(result).toEqualQueryResult({ + data: { hello: "world 1" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); } await rerender({ skip: true }); + { - const snapshot = await takeSnapshot(); - expect(snapshot.loading).toBe(false); - expect(snapshot.data).toEqual(undefined); + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + // TODO: wut? + data: undefined, + // TODO: wut? + called: false, + // TODO: wut? + error: undefined, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); } await expect(takeSnapshot).not.toRerender({ timeout: 100 }); await rerender({ skip: false }); + { const result = await takeSnapshot(); - expect(result.loading).toBe(false); - expect(result.data).toEqual({ hello: "world 1" }); + + expect(result).toEqualQueryResult({ + data: { hello: "world 1" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); } { const result = await takeSnapshot(); - expect(result.loading).toBe(false); - expect(result.data).toEqual({ hello: "world 2" }); + + expect(result).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); } { const result = await takeSnapshot(); - expect(result.loading).toBe(false); - expect(result.data).toEqual({ hello: "world 3" }); + + expect(result).toEqualQueryResult({ + data: { hello: "world 3" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 2" }, + variables: {}, + }); } }); From dceb9e47349ca4a9c33153374fb80e55c2a97844 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 14:52:50 -0700 Subject: [PATCH 03/33] Add TODO comment with suggestion for refactoring --- src/react/hooks/__tests__/useQuery.test.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 6c56c6d728a..1c81286fa8a 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -2394,6 +2394,9 @@ describe("useQuery Hook", () => { await expect(takeSnapshot).not.toRerender(); }); + // TODO: Refactor the initial state of this test. This test states that + // `skip` goes from `true` -> `false`, but it starts out unskipped before + // enabling it. it("should start polling when skip goes from true to false", async () => { const query = gql` { From 839fa441f211fcfe93458d4b037fcb94ca6b56e7 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 14:56:45 -0700 Subject: [PATCH 04/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 41 ++++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 1c81286fa8a..b1cb7fe33e3 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -2552,18 +2552,39 @@ describe("useQuery Hook", () => { ); - const { result } = renderHook(() => useQuery(query), { wrapper }); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( + () => useQuery(query), + { wrapper } + ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); - expect(result.current.data).toEqual(data); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } + + await expect(takeSnapshot).not.toRerender(); }); it("should stop polling when component unmounts", async () => { From 94e0087b0d46d6e01483399f02d4492b191f56f2 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 14:56:50 -0700 Subject: [PATCH 05/33] Add TODO comment with suggestion for refactoring --- src/react/hooks/__tests__/useQuery.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index b1cb7fe33e3..baaa9f9df3d 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -2522,6 +2522,7 @@ describe("useQuery Hook", () => { } }); + // TODO: Move out of "polling" query tests since this doesn't test polling it("should return data from network when clients default fetch policy set to network-only", async () => { const query = gql` { From ed82bcc22d60830dec90ecb9e82e7ec76bc7af53 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 14:59:13 -0700 Subject: [PATCH 06/33] Rewrite test with toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 22 +++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index baaa9f9df3d..fe99bd9e2dc 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -2632,14 +2632,28 @@ describe("useQuery Hook", () => { { const result = await takeSnapshot(); - expect(result.loading).toBe(true); - expect(result.data).toBe(undefined); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); } { const result = await takeSnapshot(); - expect(result.loading).toBe(false); - expect(result.data).toEqual({ hello: "world 1" }); + + expect(result).toEqualQueryResult({ + data: { hello: "world 1" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); expect(requestSpy).toHaveBeenCalled(); } From 5ea574d9bebeb2ed6b872d9b26f0217e0efb598a Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 15:01:35 -0700 Subject: [PATCH 07/33] Rewrite test with toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 36 +++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index fe99bd9e2dc..e188dabea7e 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -2736,27 +2736,45 @@ describe("useQuery Hook", () => { ); { - const snapshot = await takeSnapshot(); + const result = await takeSnapshot(); - expect(snapshot.loading).toBe(true); - expect(snapshot.data).toBeUndefined(); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); } { - const snapshot = await takeSnapshot(); + const result = await takeSnapshot(); - expect(snapshot.loading).toBe(false); - expect(snapshot.data).toEqual({ hello: "world 1" }); + expect(result).toEqualQueryResult({ + data: { hello: "world 1" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); expect(requestSpy).toHaveBeenCalledTimes(1); } await wait(10); { - const snapshot = await takeSnapshot(); + const result = await takeSnapshot(); - expect(snapshot.loading).toBe(false); - expect(snapshot.data).toEqual({ hello: "world 2" }); + expect(result).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); expect(requestSpy).toHaveBeenCalledTimes(2); } From 63cc1f551b81b1d59864168c087f43dc974d077d Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 15:03:05 -0700 Subject: [PATCH 08/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 36 +++++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index e188dabea7e..9f74ac6a597 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -2824,21 +2824,37 @@ describe("useQuery Hook", () => { ); - const { result, unmount } = renderHook( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, unmount } = await renderHookToSnapshotStream( () => useQuery(query, { pollInterval: 10 }), { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); - expect(result.current.data).toEqual({ hello: "world 1" }); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: { hello: "world 1" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } const requestSpyCallCount = requestSpy.mock.calls.length; expect(requestSpy).toHaveBeenCalledTimes(requestSpyCallCount); From fa089f4862c05ce21b92c4998969b5bf92d889b9 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 15:04:40 -0700 Subject: [PATCH 09/33] Rewrite test with toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 36 +++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 9f74ac6a597..49366fe4a99 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -2929,27 +2929,45 @@ describe("useQuery Hook", () => { ); { - const snapshot = await takeSnapshot(); + const result = await takeSnapshot(); - expect(snapshot.loading).toBe(true); - expect(snapshot.data).toBeUndefined(); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); } { - const snapshot = await takeSnapshot(); + const result = await takeSnapshot(); - expect(snapshot.loading).toBe(false); - expect(snapshot.data).toEqual({ hello: "world 1" }); + expect(result).toEqualQueryResult({ + data: { hello: "world 1" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); expect(requestSpy).toHaveBeenCalledTimes(1); } await wait(10); { - const snapshot = await takeSnapshot(); + const result = await takeSnapshot(); - expect(snapshot.loading).toBe(false); - expect(snapshot.data).toEqual({ hello: "world 2" }); + expect(result).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); expect(requestSpy).toHaveBeenCalledTimes(2); } From 60dd6a077577f18214440b97ffcc02154e27a29e Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 15:09:29 -0700 Subject: [PATCH 10/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 115 ++++++++++++-------- 1 file changed, 71 insertions(+), 44 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 49366fe4a99..2c9b131b4ac 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3017,60 +3017,87 @@ describe("useQuery Hook", () => { ); - const { result } = renderHook( - () => useQuery(query, { pollInterval: 20 }), - { wrapper } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => useQuery(query, { pollInterval: 20 }), + { wrapper } + ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 1" }); - }, - { interval: 1 } - ); - expect(result.current.loading).toBe(false); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - await waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 2" }); - }, - { interval: 1 } - ); - expect(result.current.loading).toBe(false); + { + const result = await takeSnapshot(); - result.current.stopPolling(); + expect(result).toEqualQueryResult({ + data: { hello: "world 1" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } - await expect( - waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 3" }); - }, - { interval: 1, timeout: 20 } - ) - ).rejects.toThrow(); - result.current.startPolling(20); + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); + } + + getCurrentSnapshot().stopPolling(); + + await expect(takeSnapshot).not.toRerender({ timeout: 50 }); + + getCurrentSnapshot().startPolling(20); expect(requestSpy).toHaveBeenCalledTimes(2); expect(onErrorFn).toHaveBeenCalledTimes(0); - await waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 3" }); - }, - { interval: 1 } - ); - expect(result.current.loading).toBe(false); + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: { hello: "world 3" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 2" }, + variables: {}, + }); + } + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: { hello: "world 4" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 3" }, + variables: {}, + }); + } - await waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 4" }); - }, - { interval: 1 } - ); - expect(result.current.loading).toBe(false); expect(requestSpy).toHaveBeenCalledTimes(4); expect(onErrorFn).toHaveBeenCalledTimes(0); requestSpy.mockRestore(); From a32c8bed9b38bd6059792cf72547233793da06fe Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 15:11:38 -0700 Subject: [PATCH 11/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 46 +++++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 2c9b131b4ac..5a42926472b 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3103,6 +3103,10 @@ describe("useQuery Hook", () => { requestSpy.mockRestore(); }); + // TODO: This test does not really check for an error so we should probably + // do something different. That said, there are several other tests that + // call stopPolling on its own so we should either move this up in the test + // suite, or delete it as its tested from other tests. it("should not throw an error if stopPolling is called manually", async () => { const query = gql` { @@ -3125,24 +3129,40 @@ describe("useQuery Hook", () => { ); - const { result, unmount } = renderHook(() => useQuery(query), { - wrapper, - }); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot, unmount } = + await renderHookToSnapshotStream(() => useQuery(query), { + wrapper, + }); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.data).toEqual({ hello: "world" }); + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: { hello: "world" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } unmount(); - result.current.stopPolling(); + getCurrentSnapshot().stopPolling(); }); describe("should prevent fetches when `skipPollAttempt` returns `false`", () => { From b3685d39ed24514d780c75b13a1cb4adaf500367 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 15:56:33 -0700 Subject: [PATCH 12/33] Rewrite test with toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 95 +++++++++++++-------- 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 5a42926472b..3c3d3771c40 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3217,55 +3217,82 @@ describe("useQuery Hook", () => { { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + expect(result.current).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); await waitFor( () => { - expect(result.current.data).toEqual({ hello: "world 1" }); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 1" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); }, { interval: 1 } ); - expect(result.current.loading).toBe(false); - - await waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 2" }); - }, - { interval: 1 } - ); + await jest.advanceTimersByTimeAsync(12); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); skipPollAttempt.mockImplementation(() => true); - expect(result.current.loading).toBe(false); - await jest.advanceTimersByTime(12); - await waitFor( - () => expect(result.current.data).toEqual({ hello: "world 2" }), - { interval: 1 } - ); + await jest.advanceTimersByTimeAsync(12); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); - await jest.advanceTimersByTime(12); - await waitFor( - () => expect(result.current.data).toEqual({ hello: "world 2" }), - { interval: 1 } - ); + await jest.advanceTimersByTimeAsync(12); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); - await jest.advanceTimersByTime(12); - await waitFor( - () => expect(result.current.data).toEqual({ hello: "world 2" }), - { interval: 1 } - ); + await jest.advanceTimersByTimeAsync(12); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); skipPollAttempt.mockImplementation(() => false); - expect(result.current.loading).toBe(false); - await waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 3" }); - }, - { interval: 1 } - ); + await jest.advanceTimersByTimeAsync(12); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 3" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 2" }, + variables: {}, + }); }); it("when defined for a single query", async () => { From d3d94931418432ee88dad9deb83f5081e52f787c Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:00:22 -0700 Subject: [PATCH 13/33] Rewrite test with toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 95 +++++++++++++-------- 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 3c3d3771c40..b26aa446436 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3334,55 +3334,82 @@ describe("useQuery Hook", () => { { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + expect(result.current).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); await waitFor( () => { - expect(result.current.data).toEqual({ hello: "world 1" }); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 1" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); }, { interval: 1 } ); - expect(result.current.loading).toBe(false); - - await waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 2" }); - }, - { interval: 1 } - ); + await jest.advanceTimersByTimeAsync(12); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); skipPollAttempt.mockImplementation(() => true); - expect(result.current.loading).toBe(false); - await jest.advanceTimersByTime(12); - await waitFor( - () => expect(result.current.data).toEqual({ hello: "world 2" }), - { interval: 1 } - ); + await jest.advanceTimersByTimeAsync(12); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); - await jest.advanceTimersByTime(12); - await waitFor( - () => expect(result.current.data).toEqual({ hello: "world 2" }), - { interval: 1 } - ); + await jest.advanceTimersByTimeAsync(12); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); - await jest.advanceTimersByTime(12); - await waitFor( - () => expect(result.current.data).toEqual({ hello: "world 2" }), - { interval: 1 } - ); + await jest.advanceTimersByTimeAsync(12); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 1" }, + variables: {}, + }); skipPollAttempt.mockImplementation(() => false); - expect(result.current.loading).toBe(false); - await waitFor( - () => { - expect(result.current.data).toEqual({ hello: "world 3" }); - }, - { interval: 1 } - ); + await jest.advanceTimersByTimeAsync(12); + expect(result.current).toEqualQueryResult({ + data: { hello: "world 3" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 2" }, + variables: {}, + }); }); }); }); From 689ba12fd7cb4140b19e7ab9831f4e0ca262d07e Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:03:20 -0700 Subject: [PATCH 14/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 42 +++++++++++++++------ 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index b26aa446436..db555d9067f 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3440,18 +3440,38 @@ describe("useQuery Hook", () => { ); - const { result } = renderHook(() => useQuery(query), { wrapper }); - - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( + () => useQuery(query), + { wrapper } ); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("error"); + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ graphQLErrors: [{ message: "error" }] }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } }); it("calls `onError` when a GraphQL error is returned", async () => { From bca257c85d582c1c0c0b969628099b4e654308a0 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:05:29 -0700 Subject: [PATCH 15/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 57 +++++++++++++-------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index db555d9067f..13af7577220 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3497,32 +3497,45 @@ describe("useQuery Hook", () => { ); const onError = jest.fn(); - const { result } = renderHook(() => useQuery(query, { onError }), { - wrapper, - }); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( + () => useQuery(query, { onError }), + { wrapper } + ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.data).toBeUndefined(); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("error"); + { + const result = await takeSnapshot(); - await waitFor(() => { - expect(onError).toHaveBeenCalledTimes(1); - }); - await waitFor(() => { - expect(onError).toHaveBeenCalledWith( - new ApolloError({ graphQLErrors: [new GraphQLError("error")] }) - ); - }); + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ graphQLErrors: [{ message: "error" }] }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } + + expect(onError).toHaveBeenCalledTimes(1); + expect(onError).toHaveBeenCalledWith( + new ApolloError({ graphQLErrors: [{ message: "error" }] }) + ); + + await expect(takeSnapshot).not.toRerender(); }); it("calls `onError` when a network error has occurred", async () => { From eba7f2d8289054036ebbf1b06453289dce6c79fd Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:09:59 -0700 Subject: [PATCH 16/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 61 ++++++++++++--------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 13af7577220..143c14a6f59 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3559,36 +3559,47 @@ describe("useQuery Hook", () => { ); const onError = jest.fn(); - const { result } = renderHook(() => useQuery(query, { onError }), { - wrapper, - }); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( + () => useQuery(query, { onError }), + { wrapper } + ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.data).toBeUndefined(); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("Could not fetch"); - expect(result.current.error!.networkError).toEqual( - new Error("Could not fetch") + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ + networkError: new Error("Could not fetch"), + }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } + + expect(onError).toHaveBeenCalledTimes(1); + expect(onError).toHaveBeenCalledWith( + new ApolloError({ networkError: new Error("Could not fetch") }) ); - await waitFor(() => { - expect(onError).toHaveBeenCalledTimes(1); - }); - await waitFor(() => { - expect(onError).toHaveBeenCalledWith( - new ApolloError({ networkError: new Error("Could not fetch") }) - ); - }); + await expect(takeSnapshot).not.toRerender(); }); it("removes partial data from result when response has errors", async () => { From 173020bf64e36e550ba1ef00bbcd5ed5cac48b6b Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:10:15 -0700 Subject: [PATCH 17/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 51 +++++++++++++-------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 143c14a6f59..dcbb7cf1cf3 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3626,27 +3626,42 @@ describe("useQuery Hook", () => { ); const onError = jest.fn(); - const { result } = renderHook(() => useQuery(query, { onError }), { - wrapper, - }); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( + () => useQuery(query, { onError }), + { wrapper } + ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.data).toBeUndefined(); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe('Could not fetch "hello"'); - expect(result.current.error!.graphQLErrors).toEqual([ - new GraphQLError('Could not fetch "hello"'), - ]); + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ + graphQLErrors: [{ message: 'Could not fetch "hello"' }], + }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } + + await expect(takeSnapshot).not.toRerender(); }); it('does not call `onError` when returning GraphQL errors while using an `errorPolicy` set to "ignore"', async () => { From 59a4d3da0dc3253b71c176dff8230ae49cad1c30 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:12:04 -0700 Subject: [PATCH 18/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 39 ++++++++++++++------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index dcbb7cf1cf3..fc4a13b2281 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3687,28 +3687,43 @@ describe("useQuery Hook", () => { ); const onError = jest.fn(); - const { result } = renderHook( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( () => useQuery(query, { onError, errorPolicy: "ignore" }), { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.data).toBeUndefined(); - expect(result.current.error).toBeUndefined(); + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } await tick(); expect(onError).not.toHaveBeenCalled(); + + await expect(takeSnapshot).not.toRerender(); }); it('calls `onError` when a network error has occurred while using an `errorPolicy` set to "ignore"', async () => { From ac36a544c15a8a680f1c3563abd7ddda0877b322 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:13:30 -0700 Subject: [PATCH 19/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 56 ++++++++++++--------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index fc4a13b2281..7b7085f6279 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3747,37 +3747,47 @@ describe("useQuery Hook", () => { ); const onError = jest.fn(); - const { result } = renderHook( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( () => useQuery(query, { onError, errorPolicy: "ignore" }), { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.data).toBeUndefined(); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("Could not fetch"); - expect(result.current.error!.networkError).toEqual( - new Error("Could not fetch") + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ + networkError: new Error("Could not fetch"), + }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } + + expect(onError).toHaveBeenCalledTimes(1); + expect(onError).toHaveBeenCalledWith( + new ApolloError({ networkError: new Error("Could not fetch") }) ); - await waitFor(() => { - expect(onError).toHaveBeenCalledTimes(1); - }); - await waitFor(() => { - expect(onError).toHaveBeenCalledWith( - new ApolloError({ networkError: new Error("Could not fetch") }) - ); - }); + await expect(takeSnapshot).not.toRerender(); }); it('returns partial data and discards GraphQL errors when using an `errorPolicy` set to "ignore"', async () => { From 9231eae48e56bd8d7b49079ee0e9314196642e2e Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:15:30 -0700 Subject: [PATCH 20/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 38 +++++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 7b7085f6279..6e2f31ea51e 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3813,23 +3813,39 @@ describe("useQuery Hook", () => { ); - const { result } = renderHook( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( () => useQuery(query, { errorPolicy: "ignore" }), { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.data).toEqual({ hello: null }); - expect(result.current.error).toBeUndefined(); + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: { hello: null }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } + + await expect(takeSnapshot).not.toRerender(); }); it('calls `onCompleted` with partial data but avoids calling `onError` when using an `errorPolicy` set to "ignore"', async () => { From bcb4fd32af19f6ac526ecf733920d7d3637d58c0 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:17:44 -0700 Subject: [PATCH 21/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 50 ++++++++++++--------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 6e2f31ea51e..eabc8618f1c 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3873,33 +3873,43 @@ describe("useQuery Hook", () => { const onError = jest.fn(); const onCompleted = jest.fn(); - const { result } = renderHook( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( () => useQuery(query, { onError, onCompleted, errorPolicy: "ignore" }), { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.data).toEqual({ hello: null }); - expect(result.current.error).toBeUndefined(); + { + const result = await takeSnapshot(); - await waitFor(() => { - expect(onCompleted).toHaveBeenCalledTimes(1); - }); - await waitFor(() => { - expect(onCompleted).toHaveBeenCalledWith({ hello: null }); - }); - await waitFor(() => { - expect(onError).not.toHaveBeenCalled(); - }); + expect(result).toEqualQueryResult({ + data: { hello: null }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } + + expect(onCompleted).toHaveBeenCalledTimes(1); + expect(onCompleted).toHaveBeenCalledWith({ hello: null }); + expect(onError).not.toHaveBeenCalled(); + + await expect(takeSnapshot).not.toRerender(); }); it('calls `onError` when returning GraphQL errors while using an `errorPolicy` set to "all"', async () => { From 8962f951d2781f186d2e6fae419376c993a8dd54 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:20:23 -0700 Subject: [PATCH 22/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 57 ++++++++++++--------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index eabc8618f1c..a889ac824d5 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -3935,36 +3935,47 @@ describe("useQuery Hook", () => { ); const onError = jest.fn(); - const { result } = renderHook( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( () => useQuery(query, { onError, errorPolicy: "all" }), { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.data).toBeUndefined(); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("error"); - expect(result.current.error!.graphQLErrors).toEqual([ - new GraphQLError("error"), - ]); + { + const result = await takeSnapshot(); - await waitFor(() => { - expect(onError).toHaveBeenCalledTimes(1); - }); - await waitFor(() => { - expect(onError).toHaveBeenCalledWith( - new ApolloError({ graphQLErrors: [new GraphQLError("error")] }) - ); - }); + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ graphQLErrors: [{ message: "error" }] }), + // TODO: Why does this only populate when errorPolicy is "all"? + errors: [{ message: "error" }], + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } + + expect(onError).toHaveBeenCalledTimes(1); + expect(onError).toHaveBeenCalledWith( + new ApolloError({ graphQLErrors: [new GraphQLError("error")] }) + ); + + await expect(takeSnapshot).not.toRerender(); }); it('returns partial data when returning GraphQL errors while using an `errorPolicy` set to "all"', async () => { From 5fc0b20193ca722240b5eafc3c00f461852413a2 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:22:49 -0700 Subject: [PATCH 23/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 46 ++++++++++++++------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index a889ac824d5..9f514c7a5d7 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -4002,27 +4002,43 @@ describe("useQuery Hook", () => { ); const onError = jest.fn(); - const { result } = renderHook( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( () => useQuery(query, { onError, errorPolicy: "all" }), { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.data).toEqual({ hello: null }); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe('Could not fetch "hello"'); - expect(result.current.error!.graphQLErrors).toEqual([ - new GraphQLError('Could not fetch "hello"'), - ]); + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: { hello: null }, + error: new ApolloError({ + graphQLErrors: [{ message: 'Could not fetch "hello"' }], + }), + errors: [{ message: 'Could not fetch "hello"' }], + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } + + await expect(takeSnapshot).not.toRerender(); }); it('calls `onError` but not `onCompleted` when returning partial data with GraphQL errors while using an `errorPolicy` set to "all"', async () => { From 0f816b8754226fc8c90d395b30627c6017dff3e2 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:25:13 -0700 Subject: [PATCH 24/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 66 ++++++++++++--------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 9f514c7a5d7..1b8e4e4f87f 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -4066,41 +4066,51 @@ describe("useQuery Hook", () => { const onError = jest.fn(); const onCompleted = jest.fn(); - const { result } = renderHook( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot } = await renderHookToSnapshotStream( () => useQuery(query, { onError, onCompleted, errorPolicy: "all" }), { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.data).toEqual({ hello: null }); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe('Could not fetch "hello"'); - expect(result.current.error!.graphQLErrors).toEqual([ - new GraphQLError('Could not fetch "hello"'), - ]); + { + const result = await takeSnapshot(); - await waitFor(() => { - expect(onError).toHaveBeenCalledTimes(1); - }); - await waitFor(() => { - expect(onError).toHaveBeenCalledWith( - new ApolloError({ - graphQLErrors: [new GraphQLError('Could not fetch "hello"')], - }) - ); - }); - await waitFor(() => { - expect(onCompleted).not.toHaveBeenCalled(); - }); + expect(result).toEqualQueryResult({ + data: { hello: null }, + error: new ApolloError({ + graphQLErrors: [{ message: 'Could not fetch "hello"' }], + }), + errors: [{ message: 'Could not fetch "hello"' }], + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } + + expect(onError).toHaveBeenCalledTimes(1); + expect(onError).toHaveBeenCalledWith( + new ApolloError({ + graphQLErrors: [new GraphQLError('Could not fetch "hello"')], + }) + ); + expect(onCompleted).not.toHaveBeenCalled(); + + await expect(takeSnapshot).not.toRerender(); }); it("calls `onError` a single time when refetching returns a successful result", async () => { From 0a7e80c90461168dff1b0ecf39e9a847675e5054 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:27:26 -0700 Subject: [PATCH 25/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 97 +++++++++++++-------- 1 file changed, 63 insertions(+), 34 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 1b8e4e4f87f..5886f29f1f3 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -4143,48 +4143,77 @@ describe("useQuery Hook", () => { ); const onError = jest.fn(); - const { result } = renderHook( - () => - useQuery(query, { - onError, - notifyOnNetworkStatusChange: true, - }), - { wrapper } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => + useQuery(query, { + onError, + notifyOnNetworkStatusChange: true, + }), + { wrapper } + ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("error"); + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ graphQLErrors: [{ message: "error" }] }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } - await new Promise((resolve) => setTimeout(resolve)); expect(onError).toHaveBeenCalledTimes(1); - await act(async () => void result.current.refetch()); - await waitFor( - () => { - expect(result.current.loading).toBe(true); - }, - { interval: 1 } - ); - expect(result.current.error).toBe(undefined); + void getCurrentSnapshot().refetch(); + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.refetch, + previousData: undefined, + variables: {}, + }); + } + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: { hello: "world" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); + } - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); - expect(result.current.data).toEqual({ hello: "world" }); expect(onError).toHaveBeenCalledTimes(1); + + await expect(takeSnapshot).not.toRerender(); }); it("should persist errors on re-render if they are still valid", async () => { From 73ce74fe70eebd2b76f656104c14d55b9bf1c632 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:29:27 -0700 Subject: [PATCH 26/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 72 ++++++++++++--------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 5886f29f1f3..51a1ed96094 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -4239,44 +4239,56 @@ describe("useQuery Hook", () => { ); - let updates = 0; - const { result, rerender } = renderHook( - () => (updates++, useQuery(query)), + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, rerender } = await renderHookToSnapshotStream( + () => useQuery(query), { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.loading).toBe(false); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("error"); + { + const result = await takeSnapshot(); - rerender(); + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ graphQLErrors: [{ message: "error" }] }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.loading).toBe(false); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("error"); + await rerender(undefined); - let previousUpdates = updates; - await expect( - waitFor( - () => { - expect(updates).not.toEqual(previousUpdates); - }, - { interval: 1, timeout: 20 } - ) - ).rejects.toThrow(); + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ graphQLErrors: [{ message: "error" }] }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } + + await expect(takeSnapshot).not.toRerender(); }); it("should not return partial data from cache on refetch with errorPolicy: none (default) and notifyOnNetworkStatusChange: true", async () => { From 8268028bff6d34d79572b407e71c6cbc3f8d427a Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:30:55 -0700 Subject: [PATCH 27/33] Add todo comment to refactor test --- src/react/hooks/__tests__/useQuery.test.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 51a1ed96094..b3581feb3e4 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -4291,6 +4291,7 @@ describe("useQuery Hook", () => { await expect(takeSnapshot).not.toRerender(); }); + // TODO: Rewrite this test using renderHookToSnapshotStream it("should not return partial data from cache on refetch with errorPolicy: none (default) and notifyOnNetworkStatusChange: true", async () => { const query = gql` { @@ -4434,6 +4435,7 @@ describe("useQuery Hook", () => { expect(screen.queryByText(/partial data rendered/i)).toBeNull(); }); + // TODO: Rewrite this test using renderHookToSnapshotStream it("should return partial data from cache on refetch", async () => { const GET_DOG_DETAILS = gql` query dog($breed: String!) { From f4a9469dd904243d1b5737f128e288c9886abfa5 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:33:32 -0700 Subject: [PATCH 28/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 76 ++++++++++++--------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index b3581feb3e4..581fa86c946 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -4540,48 +4540,58 @@ describe("useQuery Hook", () => { ); - let updates = 0; - const { result, rerender } = renderHook( - () => ( - updates++, - useQuery(query, { onError: () => {}, onCompleted: () => {} }) - ), + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, rerender } = await renderHookToSnapshotStream( + () => useQuery(query, { onError: () => {}, onCompleted: () => {} }), { wrapper } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.loading).toBe(false); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("error"); + { + const result = await takeSnapshot(); - rerender(); + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ graphQLErrors: [{ message: "error" }] }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.loading).toBe(false); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("error"); + await rerender(undefined); + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ graphQLErrors: [{ message: "error" }] }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } expect(onErrorFn).toHaveBeenCalledTimes(0); - let previousUpdates = updates; - await expect( - waitFor( - () => { - expect(updates).not.toEqual(previousUpdates); - }, - { interval: 1, timeout: 20 } - ) - ).rejects.toThrow(); + + await expect(takeSnapshot).not.toRerender(); }); it("should not persist errors when variables change", async () => { From 4090ceff7f16cf10f204175f659e8c1b50ba2e34 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:36:19 -0700 Subject: [PATCH 29/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 117 +++++++++++++------- 1 file changed, 80 insertions(+), 37 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 581fa86c946..6aa2a4bfac2 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -4631,7 +4631,8 @@ describe("useQuery Hook", () => { }, ]; - const { result, rerender } = renderHook( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, rerender } = await renderHookToSnapshotStream( ({ id }) => useQuery(query, { variables: { id } }), { wrapper: ({ children }) => ( @@ -4641,48 +4642,90 @@ describe("useQuery Hook", () => { } ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: { id: 1 }, + }); + } - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("error"); + { + const result = await takeSnapshot(); - rerender({ id: 2 }); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ graphQLErrors: [{ message: "error" }] }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: { id: 1 }, + }); + } - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); - expect(result.current.data).toEqual({ hello: "world 2" }); - expect(result.current.error).toBe(undefined); + await rerender({ id: 2 }); - rerender({ id: 1 }); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); - expect(result.current.data).toEqual({ hello: "world 1" }); - expect(result.current.error).toBe(undefined); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.setVariables, + previousData: undefined, + variables: { id: 2 }, + }); + } + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: { hello: "world 2" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: { id: 2 }, + }); + } + + await rerender({ id: 1 }); + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.setVariables, + previousData: { hello: "world 2" }, + variables: { id: 1 }, + }); + } + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: { hello: "world 1" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: { hello: "world 2" }, + variables: { id: 1 }, + }); + } + + await expect(takeSnapshot).not.toRerender(); }); it("should render multiple errors when refetching", async () => { From c8b57fb19bfe9a4ea2694334d818d9d63087972b Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:41:39 -0700 Subject: [PATCH 30/33] Rewrite test with toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 64 ++++++++++++++------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 6aa2a4bfac2..92302c643d1 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -4766,39 +4766,63 @@ describe("useQuery Hook", () => { { const result = await takeSnapshot(); - expect(result.loading).toBe(true); - expect(result.data).toBe(undefined); - expect(result.error).toBe(undefined); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); } { const result = await takeSnapshot(); - expect(result.loading).toBe(false); - expect(result.data).toBe(undefined); - expect(result.error).toBeInstanceOf(ApolloError); - expect(result.error!.message).toBe("error 1"); + + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ graphQLErrors: [{ message: "error 1" }] }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); } - const catchFn = jest.fn(); - getCurrentSnapshot().refetch().catch(catchFn); + await expect(getCurrentSnapshot().refetch()).rejects.toEqual( + new ApolloError({ graphQLErrors: [{ message: "error 2" }] }) + ); + { const result = await takeSnapshot(); - expect(result.loading).toBe(true); - expect(result.data).toBe(undefined); - expect(result.error).toBe(undefined); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.refetch, + previousData: undefined, + variables: {}, + }); } { const result = await takeSnapshot(); - expect(result.loading).toBe(false); - expect(result.data).toBe(undefined); - expect(result.error).toBeInstanceOf(ApolloError); - expect(result.error!.message).toBe("error 2"); + + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ graphQLErrors: [{ message: "error 2" }] }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); } - expect(catchFn.mock.calls.length).toBe(1); - expect(catchFn.mock.calls[0].length).toBe(1); - expect(catchFn.mock.calls[0][0]).toBeInstanceOf(ApolloError); - expect(catchFn.mock.calls[0][0].message).toBe("error 2"); + + await expect(takeSnapshot).not.toRerender(); }); it("should render the same error on refetch", async () => { From 6fe235e95c2803784472045047df9372882df697 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:44:43 -0700 Subject: [PATCH 31/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 90 ++++++++++++++------- 1 file changed, 63 insertions(+), 27 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 92302c643d1..01a5b0fa49b 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -4854,40 +4854,76 @@ describe("useQuery Hook", () => { ); - const { result } = renderHook( - () => useQuery(query, { notifyOnNetworkStatusChange: true }), - { wrapper } - ); + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, getCurrentSnapshot } = + await renderHookToSnapshotStream( + () => useQuery(query, { notifyOnNetworkStatusChange: true }), + { wrapper } + ); - expect(result.current.loading).toBe(true); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); + { + const result = await takeSnapshot(); - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); + } + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ + graphQLErrors: [{ message: "same error" }], + }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } + + await expect(getCurrentSnapshot().refetch()).rejects.toEqual( + new ApolloError({ graphQLErrors: [{ message: "same error" }] }) ); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("same error"); + { + const result = await takeSnapshot(); - const catchFn = jest.fn(); - await act(async () => { - await result.current.refetch().catch(catchFn); - }); + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.refetch, + previousData: undefined, + variables: {}, + }); + } - expect(result.current.loading).toBe(false); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBeInstanceOf(ApolloError); - expect(result.current.error!.message).toBe("same error"); + { + const result = await takeSnapshot(); - expect(catchFn.mock.calls.length).toBe(1); - expect(catchFn.mock.calls[0].length).toBe(1); - expect(catchFn.mock.calls[0][0]).toBeInstanceOf(ApolloError); - expect(catchFn.mock.calls[0][0].message).toBe("same error"); + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ + graphQLErrors: [{ message: "same error" }], + }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); + } + + await expect(takeSnapshot).not.toRerender(); }); it("should render data and errors with refetch", async () => { From f2747ae21916e73e73adff887eddbd602899507a Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:48:10 -0700 Subject: [PATCH 32/33] Rewrite test with toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 93 ++++++++++++++------- 1 file changed, 65 insertions(+), 28 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 01a5b0fa49b..30e265f269d 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -4971,53 +4971,90 @@ describe("useQuery Hook", () => { { const result = await takeSnapshot(); - expect(result.loading).toBe(true); - expect(result.data).toBe(undefined); - expect(result.error).toBe(undefined); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: {}, + }); } { const result = await takeSnapshot(); - expect(result.loading).toBe(false); - expect(result.data).toBe(undefined); - expect(result.error).toBeInstanceOf(ApolloError); - expect(result.error!.message).toBe("same error"); + + expect(result).toEqualQueryResult({ + data: undefined, + error: new ApolloError({ + graphQLErrors: [{ message: "same error" }], + }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: undefined, + variables: {}, + }); } + await getCurrentSnapshot().refetch(); { const result = await takeSnapshot(); - expect(result.loading).toBe(true); - expect(result.data).toBe(undefined); - expect(result.error).toBe(undefined); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.refetch, + previousData: undefined, + variables: {}, + }); } { const result = await takeSnapshot(); - expect(result.loading).toBe(false); - expect(result.data).toEqual({ hello: "world" }); - expect(result.error).toBe(undefined); + + expect(result).toEqualQueryResult({ + data: { hello: "world" }, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: {}, + }); } - const catchFn = jest.fn(); - getCurrentSnapshot().refetch().catch(catchFn); + + await expect(getCurrentSnapshot().refetch()).rejects.toEqual( + new ApolloError({ graphQLErrors: [{ message: "same error" }] }) + ); { const result = await takeSnapshot(); - expect(result.loading).toBe(true); - expect(result.data).toEqual({ hello: "world" }); - expect(result.error).toBe(undefined); + expect(result).toEqualQueryResult({ + data: { hello: "world" }, + called: true, + loading: true, + networkStatus: NetworkStatus.refetch, + previousData: { hello: "world" }, + variables: {}, + }); } { const result = await 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); - expect(catchFn.mock.calls[0][0]).toBeInstanceOf(ApolloError); - expect(catchFn.mock.calls[0][0].message).toBe("same error"); + expect(result).toEqualQueryResult({ + // TODO: Is this correct behavior here? + data: { hello: "world" }, + error: new ApolloError({ + graphQLErrors: [{ message: "same error" }], + }), + called: true, + loading: false, + networkStatus: NetworkStatus.error, + previousData: { hello: "world" }, + variables: {}, + }); + } }); it("should call onCompleted when variables change", async () => { From ece38b531aa9fede52225bc7c176410299441ac7 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Tue, 14 Jan 2025 16:50:58 -0700 Subject: [PATCH 33/33] Rewrite test with renderHookToSnapshotStream and toEqualQueryResult --- src/react/hooks/__tests__/useQuery.test.tsx | 98 +++++++++++++++------ 1 file changed, 71 insertions(+), 27 deletions(-) diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 30e265f269d..2501a16919f 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -5083,7 +5083,8 @@ describe("useQuery Hook", () => { const onCompleted = jest.fn(); - const { result, rerender } = renderHook( + using _disabledAct = disableActEnvironment(); + const { takeSnapshot, rerender } = await renderHookToSnapshotStream( ({ variables }) => useQuery(query, { variables, onCompleted }), { wrapper: ({ children }) => ( @@ -5095,40 +5096,83 @@ describe("useQuery Hook", () => { } ); - expect(result.current.loading).toBe(true); + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.loading, + previousData: undefined, + variables: { first: 1 }, + }); + } + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: data1, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: undefined, + variables: { first: 1 }, + }); + } - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); - expect(result.current.data).toEqual(data1); expect(onCompleted).toHaveBeenLastCalledWith(data1); - rerender({ variables: { first: 2 } }); - expect(result.current.loading).toBe(true); + await rerender({ variables: { first: 2 } }); + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: undefined, + called: true, + loading: true, + networkStatus: NetworkStatus.setVariables, + previousData: data1, + variables: { first: 2 }, + }); + } + + { + const result = await takeSnapshot(); + + expect(result).toEqualQueryResult({ + data: data2, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: data1, + variables: { first: 2 }, + }); + } - await waitFor( - () => { - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); - expect(result.current.data).toEqual(data2); expect(onCompleted).toHaveBeenLastCalledWith(data2); - rerender({ variables: { first: 1 } }); - expect(result.current.loading).toBe(false); - expect(result.current.data).toEqual(data1); - await waitFor( - () => { - expect(onCompleted).toHaveBeenLastCalledWith(data1); - }, - { interval: 1 } - ); + await rerender({ variables: { first: 1 } }); + + { + const result = await takeSnapshot(); + expect(result).toEqualQueryResult({ + data: data1, + called: true, + loading: false, + networkStatus: NetworkStatus.ready, + previousData: data2, + variables: { first: 1 }, + }); + } + + expect(onCompleted).toHaveBeenLastCalledWith(data1); expect(onCompleted).toHaveBeenCalledTimes(3); + + await expect(takeSnapshot).not.toRerender(); }); });