diff --git a/CHANGELOG.md b/CHANGELOG.md
index fd450e3778f..6176314c47d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -41,6 +41,9 @@
- Preserve `networkStatus` for incomplete `cache-and-network` queries.
[@benjamn](https://github.com/benjamn) in [#4765](https://github.com/apollographql/apollo-client/pull/4765)
+- Preserve `cache-and-network` `fetchPolicy` when refetching.
+ [@benjamn](https://github.com/benjamn) in [#4840](https://github.com/apollographql/apollo-client/pull/4840)
+
### Apollo Cache In-Memory
- Support `new InMemoryCache({ freezeResults: true })` to help enforce immutability.
diff --git a/packages/apollo-client/src/core/ObservableQuery.ts b/packages/apollo-client/src/core/ObservableQuery.ts
index be7e3bb9424..55d70f06a02 100644
--- a/packages/apollo-client/src/core/ObservableQuery.ts
+++ b/packages/apollo-client/src/core/ObservableQuery.ts
@@ -296,9 +296,11 @@ export class ObservableQuery<
));
}
- // Override fetchPolicy for this call only
- // only network-only and no-cache are safe to use
- if (fetchPolicy !== 'no-cache') {
+ // Unless the provided fetchPolicy always consults the network
+ // (no-cache, network-only, or cache-and-network), override it with
+ // network-only to force the refetch for this fetchQuery call.
+ if (fetchPolicy !== 'no-cache' &&
+ fetchPolicy !== 'cache-and-network') {
fetchPolicy = 'network-only';
}
diff --git a/packages/apollo-client/src/core/__tests__/ObservableQuery.ts b/packages/apollo-client/src/core/__tests__/ObservableQuery.ts
index f52cff21814..506fcd1e4f2 100644
--- a/packages/apollo-client/src/core/__tests__/ObservableQuery.ts
+++ b/packages/apollo-client/src/core/__tests__/ObservableQuery.ts
@@ -18,6 +18,7 @@ import ApolloClient from '../../';
import wrap from '../../util/wrap';
import subscribeAndCount from '../../util/subscribeAndCount';
import { stripSymbols } from 'apollo-utilities';
+import { ApolloError } from '../../errors/ApolloError';
describe('ObservableQuery', () => {
// Standard data for all these tests
@@ -1070,7 +1071,7 @@ describe('ObservableQuery', () => {
const observable = queryManager.watchQuery({
query: firstRequest.query,
variables: firstRequest.variables,
- fetchPolicy: 'cache-and-network',
+ fetchPolicy: 'cache-first',
});
const origFetchQuery = queryManager.fetchQuery;
@@ -1200,6 +1201,131 @@ describe('ObservableQuery', () => {
}
});
});
+
+ it('cache-and-network refetch should run @client(always: true) resolvers when network request fails', done => {
+ const query = gql`
+ query MixedQuery {
+ counter @client(always: true)
+ name
+ }
+ `;
+
+ let count = 0;
+
+ let linkObservable = Observable.of({
+ data: {
+ name: 'Ben',
+ },
+ });
+
+ const intentionalNetworkFailure = new ApolloError({
+ networkError: new Error('intentional network failure'),
+ });
+
+ const errorObservable: typeof linkObservable = new Observable(
+ observer => {
+ observer.error(intentionalNetworkFailure);
+ },
+ );
+
+ const client = new ApolloClient({
+ link: new ApolloLink(request => linkObservable),
+ cache: new InMemoryCache(),
+ resolvers: {
+ Query: {
+ counter() {
+ return ++count;
+ },
+ },
+ },
+ });
+
+ const observable = client.watchQuery({
+ query,
+ fetchPolicy: 'cache-and-network',
+ returnPartialData: true,
+ });
+
+ let handleCount = 0;
+ observable.subscribe({
+ error(error) {
+ expect(error).toBe(intentionalNetworkFailure);
+ },
+
+ next(result) {
+ ++handleCount;
+
+ if (handleCount === 1) {
+ expect(result).toEqual({
+ data: {},
+ loading: true,
+ networkStatus: NetworkStatus.loading,
+ stale: false,
+ });
+ } else if (handleCount === 2) {
+ expect(result).toEqual({
+ data: {
+ counter: 1,
+ },
+ loading: true,
+ networkStatus: NetworkStatus.loading,
+ stale: false,
+ });
+ } else if (handleCount === 3) {
+ expect(result).toEqual({
+ data: {
+ counter: 2,
+ name: 'Ben',
+ },
+ loading: false,
+ networkStatus: NetworkStatus.ready,
+ stale: false,
+ });
+
+ // Make the next network request fail.
+ linkObservable = errorObservable;
+
+ observable.refetch().then(
+ result => {
+ expect(result).toEqual({
+ data: {
+ counter: 3,
+ name: 'Ben',
+ },
+ });
+ },
+ error => {
+ expect(error).toBe(intentionalNetworkFailure);
+ },
+ );
+ } else if (handleCount === 4) {
+ expect(result).toEqual({
+ data: {
+ counter: 2,
+ name: 'Ben',
+ },
+ loading: true,
+ networkStatus: NetworkStatus.refetch,
+ stale: false,
+ });
+ } else if (handleCount === 5) {
+ expect(result).toEqual({
+ data: {
+ counter: 3,
+ name: 'Ben',
+ },
+ loading: true,
+ networkStatus: NetworkStatus.refetch,
+ stale: false,
+ });
+
+ done();
+ } else if (handleCount > 5) {
+ done.fail(new Error('should not get here'));
+ }
+ },
+ });
+ });
});
describe('currentResult', () => {