diff --git a/.vscode/launch.json b/.vscode/launch.json index 104f6f0aadf..c68c3827db4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,17 +3,16 @@ "configurations": [ { "name": "Test", + "request": "launch", "type": "node", - "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", + "program": + "${workspaceRoot}/packages/apollo-client/node_modules/jest/bin/jest.js", + "internalConsoleOptions": "openOnSessionStart", "stopOnEntry": false, - "args": [ - "--no-timeouts", - "lib/test/tests.js" - ], - "cwd": "${workspaceRoot}", - "runtimeExecutable": null, + "args": ["-i"], + "cwd": "${workspaceRoot}/packages/apollo-client", "sourceMaps": true, - "outDir": "${workspaceRoot}/lib" + "outFiles": ["${workspaceRoot}/lib/**/*"] } ] } diff --git a/packages/apollo-client/AUTHORS b/packages/apollo-client/AUTHORS index b84a8991a19..b0185081470 100644 --- a/packages/apollo-client/AUTHORS +++ b/packages/apollo-client/AUTHORS @@ -29,6 +29,7 @@ John Pinkerton Jonas Helfer Jonas Helfer Kamil Kisiela +Kamran Ayub Kerem Kazan Kiran Abburi Louis DeScioli diff --git a/packages/apollo-client/CHANGELOG.md b/packages/apollo-client/CHANGELOG.md index f94c68ad206..bb99a5396ae 100644 --- a/packages/apollo-client/CHANGELOG.md +++ b/packages/apollo-client/CHANGELOG.md @@ -8,6 +8,7 @@ ### 2.2.4 - Added `getCacheKey` function to the link context for use in state-link [PR#2998](https://github.com/apollographql/apollo-client/pull/2998) +- Fix `no-cache` fetch policy so it returns data [PR#3102](https://github.com/apollographql/apollo-client/pull/3102) - Fix Memory Leak in Query Manager [PR#3119](https://github.com/apollographql/apollo-client/pull/3119) - Pass non-optimistic query to `subscribeToMore` updateQuery [PR#3068](https://github.com/apollographql/apollo-client/pull/3068) diff --git a/packages/apollo-client/src/core/ObservableQuery.ts b/packages/apollo-client/src/core/ObservableQuery.ts index 5f061f522c4..87e42365c0d 100644 --- a/packages/apollo-client/src/core/ObservableQuery.ts +++ b/packages/apollo-client/src/core/ObservableQuery.ts @@ -238,8 +238,9 @@ export class ObservableQuery extends Observable> { } public refetch(variables?: any): Promise> { + const { fetchPolicy } = this.options; // early return if trying to read from cache during refetch - if (this.options.fetchPolicy === 'cache-only') { + if (fetchPolicy === 'cache-only') { return Promise.reject( new Error( 'cache-only fetchPolicy option should not be used together with query refetch.', @@ -264,9 +265,13 @@ export class ObservableQuery extends Observable> { } // Override fetchPolicy for this call only + // only network-only and no-cache are safe to use + const isNetworkFetchPolicy = + fetchPolicy === 'network-only' || fetchPolicy === 'no-cache'; + const combinedOptions: WatchQueryOptions = { ...this.options, - fetchPolicy: 'network-only', + fetchPolicy: isNetworkFetchPolicy ? fetchPolicy : 'network-only', }; return this.queryManager diff --git a/packages/apollo-client/src/core/QueryManager.ts b/packages/apollo-client/src/core/QueryManager.ts index 986f20c4b5f..d2f646c4fcf 100644 --- a/packages/apollo-client/src/core/QueryManager.ts +++ b/packages/apollo-client/src/core/QueryManager.ts @@ -1081,6 +1081,10 @@ export class QueryManager { reject(e); return; } + } else { + this.setQuery(queryId, () => ({ + newData: { result: result.data, complete: true }, + })); } this.queryStore.markQueryResult( @@ -1105,7 +1109,7 @@ export class QueryManager { errorsFromStore = result.errors; } - if (fetchMoreForQueryId) { + if (fetchMoreForQueryId || fetchPolicy === 'no-cache') { // We don't write fetchMore results to the store because this would overwrite // the original result in case an @connection directive is used. resultFromStore = result.data; diff --git a/packages/apollo-client/src/core/__tests__/ObservableQuery.ts b/packages/apollo-client/src/core/__tests__/ObservableQuery.ts index d8e5533a08b..4a8448cc9b9 100644 --- a/packages/apollo-client/src/core/__tests__/ObservableQuery.ts +++ b/packages/apollo-client/src/core/__tests__/ObservableQuery.ts @@ -11,7 +11,7 @@ import { mockSingleLink } from '../../__mocks__/mockLinks'; import { ObservableQuery, ApolloCurrentResult } from '../ObservableQuery'; import { NetworkStatus } from '../networkStatus'; -import { ApolloQueryResult } from '../types'; +import { ApolloQueryResult, FetchType } from '../types'; import { QueryManager } from '../QueryManager'; import { DataStore } from '../../data/store'; import ApolloClient from '../../'; @@ -1149,6 +1149,82 @@ describe('ObservableQuery', () => { }); }); + describe('refetch', () => { + it('calls fetchRequest with fetchPolicy `network-only` when using a non-networked fetch policy', done => { + const mockedResponses = [ + { + request: { query, variables }, + result: { data: dataOne }, + }, + { + request: { query, variables: differentVariables }, + result: { data: dataTwo }, + }, + ]; + + const queryManager = mockQueryManager(...mockedResponses); + const firstRequest = mockedResponses[0].request; + const observable = queryManager.watchQuery({ + query: firstRequest.query, + variables: firstRequest.variables, + fetchPolicy: 'cache-and-network', + }); + + const origFetchQuery = queryManager.fetchQuery; + queryManager.fetchQuery = jest.fn(() => + origFetchQuery.apply(queryManager, arguments), + ); + + subscribeAndCount(done, observable, (handleCount, result) => { + if (handleCount === 1) { + observable.refetch(differentVariables); + } else if (handleCount === 3) { + expect(queryManager.fetchQuery.mock.calls[1][1].fetchPolicy).toEqual( + 'network-only', + ); + done(); + } + }); + }); + + it('calls fetchRequest with fetchPolicy `no-cache` when using `no-cache` fetch policy', done => { + const mockedResponses = [ + { + request: { query, variables }, + result: { data: dataOne }, + }, + { + request: { query, variables: differentVariables }, + result: { data: dataTwo }, + }, + ]; + + const queryManager = mockQueryManager(...mockedResponses); + const firstRequest = mockedResponses[0].request; + const observable = queryManager.watchQuery({ + query: firstRequest.query, + variables: firstRequest.variables, + fetchPolicy: 'no-cache', + }); + + const origFetchQuery = queryManager.fetchQuery; + queryManager.fetchQuery = jest.fn(() => + origFetchQuery.apply(queryManager, arguments), + ); + + subscribeAndCount(done, observable, (handleCount, result) => { + if (handleCount === 1) { + observable.refetch(differentVariables); + } else if (handleCount === 3) { + expect(queryManager.fetchQuery.mock.calls[1][1].fetchPolicy).toEqual( + 'no-cache', + ); + done(); + } + }); + }); + }); + describe('currentResult', () => { it('returns the same value as observableQuery.next got', done => { const queryWithFragment = gql` diff --git a/packages/apollo-client/src/core/__tests__/fetchPolicies.ts b/packages/apollo-client/src/core/__tests__/fetchPolicies.ts index 0ffa0616450..51fe843d7c2 100644 --- a/packages/apollo-client/src/core/__tests__/fetchPolicies.ts +++ b/packages/apollo-client/src/core/__tests__/fetchPolicies.ts @@ -218,6 +218,28 @@ describe('network-only', () => { }); }); describe('no-cache', () => { + it('requests from the network when not in cache', () => { + let called = 0; + const inspector = new ApolloLink((operation, forward) => { + called++; + return forward(operation).map(result => { + called++; + return result; + }); + }); + + const client = new ApolloClient({ + link: inspector.concat(createLink()), + cache: new InMemoryCache({ addTypename: false }), + }); + + return client + .query({ fetchPolicy: 'no-cache', query }) + .then(actualResult => { + expect(actualResult.data).toEqual(result); + expect(called).toBe(2); + }); + }); it('requests from the network even if already in cache', () => { let called = 0; const inspector = new ApolloLink((operation, forward) => {