From 2d4547433773cfda6201dad2033a93a936a76479 Mon Sep 17 00:00:00 2001 From: Mark Neuburger Date: Tue, 1 Jun 2021 14:22:28 -0400 Subject: [PATCH 1/3] Improve 'No more mocked responses' error message --- .../mocking/__tests__/MockedProvider.test.tsx | 3 ++- .../MockedProvider.test.tsx.snap | 26 +++++++++++++++---- src/utilities/testing/mocking/mockLink.ts | 18 ++++++++++--- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/utilities/testing/mocking/__tests__/MockedProvider.test.tsx b/src/utilities/testing/mocking/__tests__/MockedProvider.test.tsx index b8bd658edd1..17173541017 100644 --- a/src/utilities/testing/mocking/__tests__/MockedProvider.test.tsx +++ b/src/utilities/testing/mocking/__tests__/MockedProvider.test.tsx @@ -157,7 +157,8 @@ describe('General use', () => { } const variables2 = { - username: 'other_user' + username: 'other_user', + age: undefined }; render( diff --git a/src/utilities/testing/mocking/__tests__/__snapshots__/MockedProvider.test.tsx.snap b/src/utilities/testing/mocking/__tests__/__snapshots__/MockedProvider.test.tsx.snap index 89d4ffd6cef..353ad947a33 100644 --- a/src/utilities/testing/mocking/__tests__/__snapshots__/MockedProvider.test.tsx.snap +++ b/src/utilities/testing/mocking/__tests__/__snapshots__/MockedProvider.test.tsx.snap @@ -14,7 +14,9 @@ exports[`General use should error if the query in the mock and component do not __typename } } -, variables: {"username":"mock_username"}] + +Expected variables: + {"username":"mock_username"}] `; exports[`General use should error if the variables do not deep equal 1`] = ` @@ -24,7 +26,12 @@ exports[`General use should error if the variables do not deep equal 1`] = ` __typename } } -, variables: {"username":"some_user","age":42}] + +Expected variables: + {"username":"some_user","age":42} +Found 1 mock with variables: + 1: {"age":13,"username":"some_user"} +] `; exports[`General use should error if the variables in the mock and component do not match 1`] = ` @@ -34,7 +41,12 @@ exports[`General use should error if the variables in the mock and component do __typename } } -, variables: {"username":"other_user"}] + +Expected variables: + {"username":"other_user","age":"undefined"} +Found 1 mock with variables: + 1: {"username":"mock_username"} +] `; exports[`General use should mock the data 1`] = ` @@ -64,7 +76,9 @@ exports[`General use should return "No more mocked responses" errors in response __typename } } -, variables: {}] + +Expected variables: + {}] `; exports[`General use should support custom error handling using setOnError 1`] = ` @@ -74,5 +88,7 @@ exports[`General use should support custom error handling using setOnError 1`] = __typename } } -, variables: {"username":"mock_username"}] + +Expected variables: + {"username":"mock_username"}] `; diff --git a/src/utilities/testing/mocking/mockLink.ts b/src/utilities/testing/mocking/mockLink.ts index a66e2a7f5a4..9fe1cc451d6 100644 --- a/src/utilities/testing/mocking/mockLink.ts +++ b/src/utilities/testing/mocking/mockLink.ts @@ -73,6 +73,7 @@ export class MockLink extends ApolloLink { this.operation = operation; const key = requestToKey(operation, this.addTypename); let responseIndex: number = 0; + const diffs: Array> = []; const response = (this.mockedResponsesByKey[key] || []).find( (res, index) => { const requestVariables = operation.variables || {}; @@ -81,6 +82,7 @@ export class MockLink extends ApolloLink { responseIndex = index; return true; } + diffs.push(mockedResponseVariables); return false; } ); @@ -88,11 +90,21 @@ export class MockLink extends ApolloLink { let configError: Error; if (!response || typeof responseIndex === 'undefined') { + const replacer = (key: string, value: any) => + typeof value === 'undefined' ? "undefined" : value; configError = new Error( `No more mocked responses for the query: ${print( operation.query - )}, variables: ${JSON.stringify(operation.variables)}` - ); + )}\nExpected variables:\n\t${JSON.stringify(operation.variables, replacer)}${ + diffs.length > 0 + ? `\nFound ${diffs.length} mock${ + diffs.length > 1 ? "s" : "" + } with variables:\n${diffs.map( + (d, i) => `\t${i + 1}: ${JSON.stringify(d, replacer)}\n` + )}` + : "" + }` + ) } else { this.mockedResponsesByKey[key].splice(responseIndex, 1); @@ -151,7 +163,7 @@ export class MockLink extends ApolloLink { ): MockedResponse { const newMockedResponse = cloneDeep(mockedResponse); const queryWithoutConnection = removeConnectionDirectiveFromDocument( - newMockedResponse.request.query + newMockedResponse.request.query ); invariant(queryWithoutConnection, "query is required"); newMockedResponse.request.query = queryWithoutConnection!; From 95f68ee62200186961ad658b154578cae6068d69 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 7 Jun 2021 16:53:42 -0400 Subject: [PATCH 2/3] Tweaks to formatting of 'No more mocked responses...' error message. --- .../MockedProvider.test.tsx.snap | 28 ++++----- src/utilities/testing/mocking/mockLink.ts | 63 ++++++++++--------- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/utilities/testing/mocking/__tests__/__snapshots__/MockedProvider.test.tsx.snap b/src/utilities/testing/mocking/__tests__/__snapshots__/MockedProvider.test.tsx.snap index 353ad947a33..f5819bd6f17 100644 --- a/src/utilities/testing/mocking/__tests__/__snapshots__/MockedProvider.test.tsx.snap +++ b/src/utilities/testing/mocking/__tests__/__snapshots__/MockedProvider.test.tsx.snap @@ -15,8 +15,8 @@ exports[`General use should error if the query in the mock and component do not } } -Expected variables: - {"username":"mock_username"}] +Expected variables: {"username":"mock_username"} +] `; exports[`General use should error if the variables do not deep equal 1`] = ` @@ -27,10 +27,10 @@ exports[`General use should error if the variables do not deep equal 1`] = ` } } -Expected variables: - {"username":"some_user","age":42} -Found 1 mock with variables: - 1: {"age":13,"username":"some_user"} +Expected variables: {"username":"some_user","age":42} + +Failed to match 1 mock for this query, which had the following variables: + {"age":13,"username":"some_user"} ] `; @@ -42,10 +42,10 @@ exports[`General use should error if the variables in the mock and component do } } -Expected variables: - {"username":"other_user","age":"undefined"} -Found 1 mock with variables: - 1: {"username":"mock_username"} +Expected variables: {"username":"other_user","age":} + +Failed to match 1 mock for this query, which had the following variables: + {"username":"mock_username"} ] `; @@ -77,8 +77,8 @@ exports[`General use should return "No more mocked responses" errors in response } } -Expected variables: - {}] +Expected variables: {} +] `; exports[`General use should support custom error handling using setOnError 1`] = ` @@ -89,6 +89,6 @@ exports[`General use should support custom error handling using setOnError 1`] = } } -Expected variables: - {"username":"mock_username"}] +Expected variables: {"username":"mock_username"} +] `; diff --git a/src/utilities/testing/mocking/mockLink.ts b/src/utilities/testing/mocking/mockLink.ts index 9fe1cc451d6..7b3a24b49ba 100644 --- a/src/utilities/testing/mocking/mockLink.ts +++ b/src/utilities/testing/mocking/mockLink.ts @@ -15,10 +15,18 @@ import { removeClientSetsFromDocument, removeConnectionDirectiveFromDocument, cloneDeep, + makeUniqueId, } from '../../../utilities'; export type ResultFunction = () => T; +function stringifyForDisplay(value: any): string { + const undefId = makeUniqueId("stringifyForDisplay"); + return JSON.stringify(value, (key, value) => { + return value === void 0 ? undefId : value; + }).split(JSON.stringify(undefId)).join(""); +} + export interface MockedResponse> { request: GraphQLRequest; result?: FetchResult | ResultFunction>; @@ -72,46 +80,41 @@ export class MockLink extends ApolloLink { public request(operation: Operation): Observable | null { this.operation = operation; const key = requestToKey(operation, this.addTypename); - let responseIndex: number = 0; - const diffs: Array> = []; - const response = (this.mockedResponsesByKey[key] || []).find( - (res, index) => { - const requestVariables = operation.variables || {}; - const mockedResponseVariables = res.request.variables || {}; - if (equal(requestVariables, mockedResponseVariables)) { - responseIndex = index; - return true; - } - diffs.push(mockedResponseVariables); - return false; + const unmatchedVars: Array> = []; + const requestVariables = operation.variables || {}; + const mockedResponses = this.mockedResponsesByKey[key]; + const responseIndex = mockedResponses ? mockedResponses.findIndex((res, index) => { + const mockedResponseVars = res.request.variables || {}; + if (equal(requestVariables, mockedResponseVars)) { + return true; } - ); + unmatchedVars.push(mockedResponseVars); + return false; + }) : -1; + + const response = responseIndex >= 0 + ? mockedResponses[responseIndex] + : void 0; let configError: Error; - if (!response || typeof responseIndex === 'undefined') { - const replacer = (key: string, value: any) => - typeof value === 'undefined' ? "undefined" : value; + if (!response) { configError = new Error( - `No more mocked responses for the query: ${print( - operation.query - )}\nExpected variables:\n\t${JSON.stringify(operation.variables, replacer)}${ - diffs.length > 0 - ? `\nFound ${diffs.length} mock${ - diffs.length > 1 ? "s" : "" - } with variables:\n${diffs.map( - (d, i) => `\t${i + 1}: ${JSON.stringify(d, replacer)}\n` - )}` - : "" - }` - ) +`No more mocked responses for the query: ${print(operation.query)} +Expected variables: ${stringifyForDisplay(operation.variables)} +${unmatchedVars.length > 0 ? ` +Failed to match ${unmatchedVars.length} mock${ + unmatchedVars.length === 1 ? "" : "s" +} for this query, which had the following variables: +${unmatchedVars.map(d => ` ${stringifyForDisplay(d)}`).join('\n')} +` : ""}`); } else { - this.mockedResponsesByKey[key].splice(responseIndex, 1); + mockedResponses.splice(responseIndex, 1); const { newData } = response; if (newData) { response.result = newData(); - this.mockedResponsesByKey[key].push(response); + mockedResponses.push(response); } if (!response.result && !response.error) { From 0e9f7980d0ff7ba521ff2068ef97deae1fdd7998 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 7 Jun 2021 17:07:45 -0400 Subject: [PATCH 3/3] Mention PR #8340 in CHANGELOG.md. --- CHANGELOG.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57e680c690c..737a239fa0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,9 +17,11 @@ }) ``` [@benjamn](https://github.com/benjamn) in [#7810](https://github.com/apollographql/apollo-client/pull/7810) -- Make sure the `MockedResponse` `ResultFunction` type is re-exported.
+ +- Make sure the `MockedResponse` `ResultFunction` type is re-exported.
[@hwillson](https://github.com/hwillson) in [#8315](https://github.com/apollographql/apollo-client/pull/8315) -- Fix polling when used with skip
+ +- Fix polling when used with `skip`.
[@brainkim](https://github.com/brainkim) in [#8346](https://github.com/apollographql/apollo-client/pull/8346) ### Potentially breaking changes @@ -74,7 +76,11 @@ - Fully remove result cache entries from LRU dependency system when the corresponding entities are removed from `InMemoryCache` by eviction, or by any other means.
[@sofianhn](https://github.com/sofianhn) and [@benjamn](https://github.com/benjamn) in [#8147](https://github.com/apollographql/apollo-client/pull/8147) -- Expose missing field errors in results.
[@brainkim](github.com/brainkim) in [#8262](https://github.com/apollographql/apollo-client/pull/8262) +- Expose missing field errors in results.
+ [@brainkim](github.com/brainkim) in [#8262](https://github.com/apollographql/apollo-client/pull/8262) + +- Add expected/received `variables` to `No more mocked responses...` error messages generated by `MockLink`.
+ [@markneub](github.com/markneub) in [#8340](https://github.com/apollographql/apollo-client/pull/8340) ### Documentation TBD