From e95c1fbd685fcb60486e607d1d0cc5f4d17b7f5d Mon Sep 17 00:00:00 2001 From: Mateus Craveiro Date: Tue, 13 Dec 2022 08:36:02 -0300 Subject: [PATCH 1/2] fix: error when server returns an error and we are also querying for a local field closes #10345 --- .changeset/small-lemons-grow.md | 5 ++++ src/__tests__/local-state/general.ts | 41 ++++++++++++++++++++++++++++ src/core/LocalState.ts | 4 +++ 3 files changed, 50 insertions(+) create mode 100644 .changeset/small-lemons-grow.md diff --git a/.changeset/small-lemons-grow.md b/.changeset/small-lemons-grow.md new file mode 100644 index 00000000000..1fd7e1dc905 --- /dev/null +++ b/.changeset/small-lemons-grow.md @@ -0,0 +1,5 @@ +--- +"@apollo/client": patch +--- + +Fix error when server returns an error and we are also querying for a local field diff --git a/src/__tests__/local-state/general.ts b/src/__tests__/local-state/general.ts index 0ac52d61aca..498ddde236f 100644 --- a/src/__tests__/local-state/general.ts +++ b/src/__tests__/local-state/general.ts @@ -1196,4 +1196,45 @@ describe('Combining client and server state/operations', () => { }, }); }); + + itAsync('should handle server errors when field is required', (resolve, reject) => { + const query = gql` + query GetUser { + user { + firstName @client + lastName + } + } + `; + + const cache = new InMemoryCache(); + const link = new ApolloLink(operation => { + expect(operation.operationName).toBe('GetUser'); + return Observable.of({ + data: null, + errors: [new GraphQLError("something went wrong", { + extensions: { + code: "INTERNAL_SERVER_ERROR" + }, + path: ["user"] + })] + }); + }); + + const client = new ApolloClient({ + cache, + link, + resolvers: {}, + }); + + client.watchQuery({ query }).subscribe({ + error(error) { + expect(error.message).toEqual("something went wrong"); + resolve(); + }, + next() { + reject(); + }, + }); + }); }); diff --git a/src/core/LocalState.ts b/src/core/LocalState.ts index e6e9518016b..2ac99ceafdb 100644 --- a/src/core/LocalState.ts +++ b/src/core/LocalState.ts @@ -353,6 +353,10 @@ export class LocalState { rootValue: any, execContext: ExecContext, ): Promise { + if (!rootValue) { + return null; + } + const { variables } = execContext; const fieldName = field.name.value; const aliasedFieldName = resultKeyNameFromField(field); From 863e0f17428e7cfc8003ce86e21cc0b0ab1e5e6c Mon Sep 17 00:00:00 2001 From: Alessia Bellisario Date: Thu, 2 Feb 2023 11:43:53 -0500 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Jerel Miller --- src/__tests__/local-state/general.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/__tests__/local-state/general.ts b/src/__tests__/local-state/general.ts index 498ddde236f..2be807a54ea 100644 --- a/src/__tests__/local-state/general.ts +++ b/src/__tests__/local-state/general.ts @@ -1197,7 +1197,7 @@ describe('Combining client and server state/operations', () => { }); }); - itAsync('should handle server errors when field is required', (resolve, reject) => { + itAsync('handles server errors when root data property is null', (resolve, reject) => { const query = gql` query GetUser { user { @@ -1209,7 +1209,6 @@ describe('Combining client and server state/operations', () => { const cache = new InMemoryCache(); const link = new ApolloLink(operation => { - expect(operation.operationName).toBe('GetUser'); return Observable.of({ data: null, errors: [new GraphQLError("something went wrong", {