From 98ec1444cc3591de2f46403328346ed0724da7b8 Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Fri, 14 Apr 2023 12:27:46 +0200 Subject: [PATCH 1/2] deprecate `useFragement` `returnPartialData` option --- .changeset/brave-buttons-grab.md | 5 ++ .../hooks/__tests__/useFragment.test.tsx | 90 +++++++++++++++++++ src/react/hooks/useFragment.ts | 15 +++- 3 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 .changeset/brave-buttons-grab.md diff --git a/.changeset/brave-buttons-grab.md b/.changeset/brave-buttons-grab.md new file mode 100644 index 00000000000..92355059920 --- /dev/null +++ b/.changeset/brave-buttons-grab.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +deprecate `useFragement` `returnPartialData` option diff --git a/src/react/hooks/__tests__/useFragment.test.tsx b/src/react/hooks/__tests__/useFragment.test.tsx index dab0f5efcb5..3abed0ff8a2 100644 --- a/src/react/hooks/__tests__/useFragment.test.tsx +++ b/src/react/hooks/__tests__/useFragment.test.tsx @@ -911,4 +911,94 @@ describe("useFragment", () => { ]); }); }); + + describe("tests with incomplete data", () => { + let cache: InMemoryCache, wrapper: React.FunctionComponent; + const ItemFragment = gql` + fragment ItemFragment on Item { + id + text + } + `; + + beforeEach(() => { + cache = new InMemoryCache(); + + wrapper = ({ children }: any) => {children}; + + // silence the console for the incomplete fragment write + const spy = jest.spyOn(console, 'error').mockImplementation(() => {}); + cache.writeFragment({ + fragment: ItemFragment, + data: { + __typename: "Item", + id: 5, + }, + }); + spy.mockRestore(); + }); + + it("assumes `returnPartialData: true` per default", () => { + const { result } = renderHook( + () => + useFragment({ + fragment: ItemFragment, + from: { __typename: "Item", id: 5 }, + }), + { wrapper } + ); + + expect(result.current.data).toEqual({ __typename: "Item", id: 5 }); + expect(result.current.complete).toBe(false); + }); + + it("throws an exception with `returnPartialData: false` if only partial data is available", () => { + // this is actually not intended behavuor, but it is the current behaviour + // let's document it in a test until we remove `returnPartialData` in 3.8 + + let error: Error; + + renderHook( + () => { + // we can't just `expect(() => renderHook(...)).toThrow(...)` because it will render a second time, resulting in an uncaught exception + try { + useFragment({ + fragment: ItemFragment, + from: { __typename: "Item", id: 5 }, + returnPartialData: false, + }); + } catch (e) { + error = e; + } + }, + { wrapper } + ); + + expect(error!.toString()).toMatch(`Error: Can't find field 'text' on Item:5 object`); + }); + + it("throws an exception with `returnPartialData: false` if no data is available", () => { + // this is actually not intended behavuor, but it is the current behaviour + // let's document it in a test until we remove `returnPartialData` in 3.8 + let error: Error; + + renderHook( + () => { + // we can't just `expect(() => renderHook(...)).toThrow(...)` because it will render a second time, resulting in an uncaught exception + try { + useFragment({ + fragment: ItemFragment, + from: { __typename: "Item", id: 6 }, + returnPartialData: false, + }); + } catch (e) { + error = e; + } + }, + { wrapper } + ); + + expect(error!.toString()).toMatch(`Error: Dangling reference to missing Item:6 object`); + }); + }); }); diff --git a/src/react/hooks/useFragment.ts b/src/react/hooks/useFragment.ts index 187a83222aa..38fa56c220e 100644 --- a/src/react/hooks/useFragment.ts +++ b/src/react/hooks/useFragment.ts @@ -15,18 +15,27 @@ import { OperationVariables } from "../../core"; export interface UseFragmentOptions extends Omit< - Cache.DiffOptions, + Cache.DiffOptions, | "id" | "query" | "optimistic" | "previousResult" ->, Omit< - Cache.ReadFragmentOptions, + | "returnPartialData" +>, Omit, | "id" + | "returnPartialData" > { from: StoreObject | Reference | string; // Override this field to make it optional (default: true). optimistic?: boolean; + + /** + * Whether to return incomplete data rather than null. + * Defaults to `true`. + * @deprecated This option will be removed in Apollo Client 3.8. + * Please check `result.missing` instead. + */ + returnPartialData?: boolean; } // Since the above definition of UseFragmentOptions can be hard to parse without From f147bd696c685fa9826f60395e7625521162b0ab Mon Sep 17 00:00:00 2001 From: Lenz Weber-Tronic Date: Mon, 17 Apr 2023 10:26:39 +0200 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Jerel Miller --- .changeset/brave-buttons-grab.md | 2 +- src/react/hooks/__tests__/useFragment.test.tsx | 4 ++-- src/react/hooks/useFragment.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.changeset/brave-buttons-grab.md b/.changeset/brave-buttons-grab.md index 92355059920..18c136161ed 100644 --- a/.changeset/brave-buttons-grab.md +++ b/.changeset/brave-buttons-grab.md @@ -2,4 +2,4 @@ "@apollo/client": patch --- -deprecate `useFragement` `returnPartialData` option +Deprecate `useFragment` `returnPartialData` option diff --git a/src/react/hooks/__tests__/useFragment.test.tsx b/src/react/hooks/__tests__/useFragment.test.tsx index 3abed0ff8a2..5e7f8ed5adf 100644 --- a/src/react/hooks/__tests__/useFragment.test.tsx +++ b/src/react/hooks/__tests__/useFragment.test.tsx @@ -953,7 +953,7 @@ describe("useFragment", () => { }); it("throws an exception with `returnPartialData: false` if only partial data is available", () => { - // this is actually not intended behavuor, but it is the current behaviour + // this is actually not intended behavior, but it is the current behavior // let's document it in a test until we remove `returnPartialData` in 3.8 let error: Error; @@ -978,7 +978,7 @@ describe("useFragment", () => { }); it("throws an exception with `returnPartialData: false` if no data is available", () => { - // this is actually not intended behavuor, but it is the current behaviour + // this is actually not intended behavior, but it is the current behavior // let's document it in a test until we remove `returnPartialData` in 3.8 let error: Error; diff --git a/src/react/hooks/useFragment.ts b/src/react/hooks/useFragment.ts index 38fa56c220e..5bf0a282958 100644 --- a/src/react/hooks/useFragment.ts +++ b/src/react/hooks/useFragment.ts @@ -15,7 +15,7 @@ import { OperationVariables } from "../../core"; export interface UseFragmentOptions extends Omit< - Cache.DiffOptions, + Cache.DiffOptions, | "id" | "query" | "optimistic"