diff --git a/CHANGELOG.md b/CHANGELOG.md
index 95dbdd144c4..c82df26d60d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,18 @@
+## Apollo Client 3.5 (unreleased)
+
+### Bug Fixes
+- `useQuery` and `useLazyQuery` will now have observableQuery methods defined consistently.
[@brainkim](https://github.com/brainkim) in [#8596](https://github.com/apollographql/apollo-client/pull/8596)
+
+- Calling `useLazyQuery` methods like `startPolling` will start the query
[@brainkim](https://github.com/brainkim) in [#8596](https://github.com/apollographql/apollo-client/pull/8596)
+
+- Calling the `useLazyQuery` execution function will now behave more like `refetch`. `previousData` will be preserved.
[@brainkim](https://github.com/brainkim) in [#8596](https://github.com/apollographql/apollo-client/pull/8596)
+
+- `standby` fetchPolicies will now act like `skip: true` more consistently
[@brainkim](https://github.com/brainkim) in [#8596](https://github.com/apollographql/apollo-client/pull/8596)
+
+- Calling `refetch` on a skipped query will have no effect (https://github.com/apollographql/apollo-client/issues/8270).
[@brainkim](https://github.com/brainkim) in [#8596](https://github.com/apollographql/apollo-client/pull/8596)
+
+- Improvements to `onError` and `onCompleted` functions, preventing them from firing continuously, and working with polling
[@brainkim](https://github.com/brainkim) in [#8596](https://github.com/apollographql/apollo-client/pull/8596)
+
## Apollo Client 3.4.8
### Bug Fixes
diff --git a/config/entryPoints.js b/config/entryPoints.js
index 71c05482311..99d3a46485d 100644
--- a/config/entryPoints.js
+++ b/config/entryPoints.js
@@ -17,7 +17,6 @@ const entryPoints = [
{ dirs: ['react'] },
{ dirs: ['react', 'components'] },
{ dirs: ['react', 'context'] },
- { dirs: ['react', 'data'] },
{ dirs: ['react', 'hoc'] },
{ dirs: ['react', 'hooks'] },
{ dirs: ['react', 'parser'] },
diff --git a/package.json b/package.json
index 52a79df2f96..a3f36cb39d4 100644
--- a/package.json
+++ b/package.json
@@ -41,7 +41,7 @@
"resolve": "ts-node-script config/resolveModuleIds.ts",
"clean": "rimraf -r dist coverage lib temp",
"test": "jest --config ./config/jest.config.js",
- "test:debug": "BABEL_ENV=server node --inspect-brk node_modules/.bin/jest --config ./config/jest.config.js --runInBand",
+ "test:debug": "BABEL_ENV=server node --inspect-brk node_modules/.bin/jest --config ./config/jest.config.js --runInBand --testTimeout 99999",
"test:ci": "npm run test:coverage && npm run test:memory",
"test:watch": "jest --config ./config/jest.config.js --watch",
"test:memory": "cd scripts/memory && npm i && npm test",
diff --git a/src/__tests__/__snapshots__/exports.ts.snap b/src/__tests__/__snapshots__/exports.ts.snap
index 3835a31be88..f797e80a0ce 100644
--- a/src/__tests__/__snapshots__/exports.ts.snap
+++ b/src/__tests__/__snapshots__/exports.ts.snap
@@ -256,15 +256,6 @@ Array [
]
`;
-exports[`exports of public entry points @apollo/client/react/data 1`] = `
-Array [
- "MutationData",
- "OperationData",
- "QueryData",
- "SubscriptionData",
-]
-`;
-
exports[`exports of public entry points @apollo/client/react/hoc 1`] = `
Array [
"graphql",
@@ -291,6 +282,7 @@ Array [
"DocumentType",
"operationName",
"parser",
+ "verifyDocumentType",
]
`;
diff --git a/src/__tests__/exports.ts b/src/__tests__/exports.ts
index 13e00747a14..88ca3b43640 100644
--- a/src/__tests__/exports.ts
+++ b/src/__tests__/exports.ts
@@ -16,7 +16,6 @@ import * as linkWS from "../link/ws";
import * as react from "../react";
import * as reactComponents from "../react/components";
import * as reactContext from "../react/context";
-import * as reactData from "../react/data";
import * as reactHOC from "../react/hoc";
import * as reactHooks from "../react/hooks";
import * as reactParser from "../react/parser";
@@ -56,7 +55,6 @@ describe('exports of public entry points', () => {
check("@apollo/client/react", react);
check("@apollo/client/react/components", reactComponents);
check("@apollo/client/react/context", reactContext);
- check("@apollo/client/react/data", reactData);
check("@apollo/client/react/hoc", reactHOC);
check("@apollo/client/react/hooks", reactHooks);
check("@apollo/client/react/parser", reactParser);
diff --git a/src/core/ObservableQuery.ts b/src/core/ObservableQuery.ts
index 6038a87755f..ff8f6a62bf2 100644
--- a/src/core/ObservableQuery.ts
+++ b/src/core/ObservableQuery.ts
@@ -305,9 +305,11 @@ export class ObservableQuery<
// (no-cache, network-only, or cache-and-network), override it with
// network-only to force the refetch for this fetchQuery call.
const { fetchPolicy } = this.options;
- if (fetchPolicy === 'no-cache') {
+ if (fetchPolicy === 'standby' || fetchPolicy === 'cache-and-network') {
+ reobserveOptions.fetchPolicy = fetchPolicy;
+ } else if (fetchPolicy === 'no-cache') {
reobserveOptions.fetchPolicy = 'no-cache';
- } else if (fetchPolicy !== 'cache-and-network') {
+ } else {
reobserveOptions.fetchPolicy = 'network-only';
}
diff --git a/src/react/components/Query.tsx b/src/react/components/Query.tsx
index ed33d9890f1..f70d33918b0 100644
--- a/src/react/components/Query.tsx
+++ b/src/react/components/Query.tsx
@@ -9,7 +9,7 @@ export function Query(
) {
const { children, query, ...options } = props;
const result = useQuery(query, options);
- return result ? children(result) : null;
+ return result ? children(result as any) : null;
}
export interface Query {
diff --git a/src/react/components/__tests__/client/Mutation.test.tsx b/src/react/components/__tests__/client/Mutation.test.tsx
index 272e1b5ed48..e14a48c97dc 100644
--- a/src/react/components/__tests__/client/Mutation.test.tsx
+++ b/src/react/components/__tests__/client/Mutation.test.tsx
@@ -7,7 +7,12 @@ import { ApolloClient } from '../../../../core';
import { ApolloError } from '../../../../errors';
import { DataProxy, InMemoryCache as Cache } from '../../../../cache';
import { ApolloProvider } from '../../../context';
-import { MockedProvider, MockLink, mockSingleLink } from '../../../../testing';
+import {
+ itAsync,
+ MockedProvider,
+ MockLink,
+ mockSingleLink,
+} from '../../../../testing';
import { Query } from '../../Query';
import { Mutation } from '../../Mutation';
@@ -156,24 +161,28 @@ describe('General Mutation testing', () => {
expect(spy).toHaveBeenCalledWith(mocksProps[1].result);
});
- it('performs a mutation', async () => {
+ itAsync('performs a mutation', (resolve, reject) => {
let count = 0;
const Component = () => (
{(createTodo: any, result: any) => {
- if (count === 0) {
- expect(result.loading).toEqual(false);
- expect(result.called).toEqual(false);
- createTodo();
- } else if (count === 1) {
- expect(result.called).toEqual(true);
- expect(result.loading).toEqual(true);
- } else if (count === 2) {
- expect(result.called).toEqual(true);
- expect(result.loading).toEqual(false);
- expect(result.data).toEqual(data);
+ try {
+ if (count === 0) {
+ expect(result.loading).toEqual(false);
+ expect(result.called).toEqual(false);
+ createTodo();
+ } else if (count === 1) {
+ expect(result.called).toEqual(true);
+ expect(result.loading).toEqual(true);
+ } else if (count === 2) {
+ expect(result.called).toEqual(true);
+ expect(result.loading).toEqual(false);
+ expect(result.data).toEqual(data);
+ }
+ count++;
+ } catch (err) {
+ reject(err);
}
- count++;
return ;
}}
@@ -185,7 +194,7 @@ describe('General Mutation testing', () => {
);
- await wait();
+ wait().then(resolve, reject);
});
it('can bind only the mutation and not rerender by props', done => {
@@ -922,7 +931,7 @@ describe('General Mutation testing', () => {
});
});
- it('allows a refetchQueries prop as string and variables have updated', async () => {
+ it('allows a refetchQueries prop as string and variables have updated', async () => new Promise((resolve, reject) => {
const query = gql`
query people($first: Int) {
allPeople(first: $first) {
@@ -978,33 +987,42 @@ describe('General Mutation testing', () => {
{(createTodo: any, resultMutation: any) => (
{(resultQuery: any) => {
- if (count === 0) {
- // "first: 1" loading
- expect(resultQuery.loading).toBe(true);
- } else if (count === 1) {
- // "first: 1" loaded
- expect(resultQuery.loading).toBe(false);
- setTimeout(() => setVariables({ first: 2 }));
- } else if (count === 2) {
- // "first: 2" loading
- expect(resultQuery.loading).toBe(true);
- } else if (count === 3) {
- // "first: 2" loaded
- expect(resultQuery.loading).toBe(false);
- setTimeout(() => createTodo());
- } else if (count === 4) {
- // mutation loading
- expect(resultMutation.loading).toBe(true);
- } else if (count === 5) {
- // mutation loaded
- expect(resultMutation.loading).toBe(false);
- } else if (count === 6) {
- // query refetched
- expect(resultQuery.loading).toBe(false);
- expect(resultMutation.loading).toBe(false);
- expect(resultQuery.data).toEqual(peopleData3);
+ try {
+ if (count === 0) {
+ // "first: 1" loading
+ expect(resultQuery.loading).toBe(true);
+ } else if (count === 1) {
+ // "first: 1" loaded
+ expect(resultQuery.loading).toBe(false);
+ expect(resultQuery.data).toEqual(peopleData1);
+ setTimeout(() => setVariables({ first: 2 }));
+ } else if (count === 2) {
+ expect(resultQuery.loading).toBe(false);
+ expect(resultQuery.data).toEqual(peopleData1);
+ } else if (count === 3) {
+ // "first: 2" loading
+ expect(resultQuery.loading).toBe(true);
+ } else if (count === 4) {
+ // "first: 2" loaded
+ expect(resultQuery.loading).toBe(false);
+ expect(resultQuery.data).toEqual(peopleData2);
+ setTimeout(() => createTodo());
+ } else if (count === 5) {
+ // mutation loading
+ expect(resultMutation.loading).toBe(true);
+ } else if (count === 6) {
+ // mutation loaded
+ expect(resultMutation.loading).toBe(false);
+ } else if (count === 7) {
+ // query refetched
+ expect(resultQuery.loading).toBe(false);
+ expect(resultMutation.loading).toBe(false);
+ expect(resultQuery.data).toEqual(peopleData3);
+ }
+ count++;
+ } catch (err) {
+ reject(err);
}
- count++;
return null;
}}
@@ -1019,12 +1037,12 @@ describe('General Mutation testing', () => {
);
- await wait(() => {
- expect(count).toBe(7);
- });
- });
+ wait(() => {
+ expect(count).toBe(8);
+ }).then(resolve, reject);
+ }));
- it('allows refetchQueries to be passed to the mutate function', async () => {
+ it('allows refetchQueries to be passed to the mutate function', () => new Promise((resolve, reject) => {
const query = gql`
query getTodo {
todo {
@@ -1071,18 +1089,22 @@ describe('General Mutation testing', () => {
{(createTodo: any, resultMutation: any) => (
{(resultQuery: any) => {
- if (count === 0) {
- setTimeout(() => createTodo({ refetchQueries }), 10);
- } else if (count === 1) {
- expect(resultMutation.loading).toBe(false);
- expect(resultQuery.loading).toBe(false);
- } else if (count === 2) {
- expect(resultMutation.loading).toBe(true);
- expect(resultQuery.data).toEqual(queryData);
- } else if (count === 3) {
- expect(resultMutation.loading).toBe(false);
+ try {
+ if (count === 0) {
+ setTimeout(() => createTodo({ refetchQueries }), 10);
+ } else if (count === 1) {
+ expect(resultMutation.loading).toBe(false);
+ expect(resultQuery.loading).toBe(false);
+ } else if (count === 2) {
+ expect(resultMutation.loading).toBe(true);
+ expect(resultQuery.data).toEqual(queryData);
+ } else if (count === 3) {
+ expect(resultMutation.loading).toBe(false);
+ }
+ count++;
+ } catch (err) {
+ reject(err);
}
- count++;
return null;
}}
@@ -1096,10 +1118,10 @@ describe('General Mutation testing', () => {
);
- await wait(() => {
+ wait(() => {
expect(count).toBe(4);
- });
- });
+ }).then(resolve, reject);
+ }));
it('has an update prop for updating the store after the mutation', async () => {
const update = (_proxy: DataProxy, response: ExecutionResult) => {
diff --git a/src/react/components/__tests__/client/Query.test.tsx b/src/react/components/__tests__/client/Query.test.tsx
index c3fa0a77422..5b6c2d9d6b6 100644
--- a/src/react/components/__tests__/client/Query.test.tsx
+++ b/src/react/components/__tests__/client/Query.test.tsx
@@ -8,7 +8,7 @@ import { ApolloError } from '../../../../errors';
import { ApolloLink } from '../../../../link/core';
import { InMemoryCache } from '../../../../cache';
import { ApolloProvider } from '../../../context';
-import { itAsync, MockedProvider, mockSingleLink, withErrorSpy } from '../../../../testing';
+import { itAsync, MockedProvider, mockSingleLink } from '../../../../testing';
import { Query } from '../../Query';
const allPeopleQuery: DocumentNode = gql`
@@ -53,16 +53,49 @@ describe('Query component', () => {
const Component = () => (
{(result: any) => {
- const { client: clientResult, ...rest } = result;
- if (result.loading) {
- expect(rest).toMatchSnapshot(
- 'result in render prop while loading'
- );
- expect(clientResult).toBe(client);
- } else {
- expect(rest).toMatchSnapshot(
- 'result in render prop'
- );
+ const {
+ client: clientResult,
+ fetchMore,
+ refetch,
+ startPolling,
+ stopPolling,
+ subscribeToMore,
+ updateQuery,
+ ...rest
+ } = result;
+ try {
+ if (result.loading) {
+ expect(rest).toEqual({
+ called: true,
+ data: undefined,
+ error: undefined,
+ loading: true,
+ networkStatus: 1,
+ previousData: undefined,
+ variables: {},
+ });
+ expect(clientResult).toBe(client);
+ } else {
+ expect(rest).toEqual({
+ called: true,
+ data: {
+ allPeople: {
+ people: [
+ {
+ name: "Luke Skywalker",
+ },
+ ],
+ },
+ },
+ error: undefined,
+ loading: false,
+ networkStatus: 7,
+ previousData: undefined,
+ variables: {},
+ });
+ }
+ } catch (err) {
+ reject(err);
}
return null;
}}
@@ -994,16 +1027,6 @@ describe('Query component', () => {
},
};
- componentDidMount() {
- setTimeout(() => {
- this.setState({
- variables: {
- first: 2,
- },
- });
- }, 50);
- }
-
render() {
const { variables } = this.state;
@@ -1013,14 +1036,28 @@ describe('Query component', () => {
if (result.loading) {
return null;
}
+
try {
- if (count === 0) {
- expect(variables).toEqual({ first: 1 });
- expect(result.data).toEqual(data1);
- }
- if (count === 1) {
- expect(variables).toEqual({ first: 2 });
- expect(result.data).toEqual(data2);
+ switch (count) {
+ case 0:
+ expect(variables).toEqual({ first: 1 });
+ expect(result.data).toEqual(data1);
+ setTimeout(() => {
+ this.setState({
+ variables: {
+ first: 2,
+ },
+ });
+ });
+ break;
+ case 1:
+ expect(variables).toEqual({ first: 2 });
+ expect(result.data).toEqual(data1);
+ break;
+ case 2:
+ expect(variables).toEqual({ first: 2 });
+ expect(result.data).toEqual(data2);
+ break;
}
} catch (error) {
reject(error);
@@ -1040,7 +1077,7 @@ describe('Query component', () => {
);
- return wait(() => expect(count).toBe(2)).then(resolve, reject);
+ return wait(() => expect(count).toBe(3)).then(resolve, reject);
});
itAsync('if the query changes', (resolve, reject) => {
@@ -1084,14 +1121,22 @@ describe('Query component', () => {
{(result: any) => {
if (result.loading) return null;
try {
- if (count === 0) {
- expect(result.data).toEqual(data1);
- setTimeout(() => {
- this.setState({ query: query2 });
- });
- }
- if (count === 1) {
- expect(result.data).toEqual(data2);
+ switch (count) {
+ case 0:
+ expect(query).toEqual(query1);
+ expect(result.data).toEqual(data1);
+ setTimeout(() => {
+ this.setState({ query: query2 });
+ });
+ break;
+ case 1:
+ expect(query).toEqual(query2);
+ expect(result.data).toEqual(data1);
+ break;
+ case 2:
+ expect(query).toEqual(query2);
+ expect(result.data).toEqual(data2);
+ break;
}
} catch (error) {
reject(error);
@@ -1111,7 +1156,7 @@ describe('Query component', () => {
);
- return wait(() => expect(count).toBe(2)).then(resolve, reject);
+ return wait(() => expect(count).toBe(3)).then(resolve, reject);
});
itAsync('with data while loading', (resolve, reject) => {
@@ -1153,35 +1198,42 @@ describe('Query component', () => {
},
};
- componentDidMount() {
- setTimeout(() => {
- this.setState({ variables: { first: 2 } });
- }, 10);
- }
-
render() {
const { variables } = this.state;
return (
{(result: any) => {
- if (count === 0) {
- expect(result.loading).toBe(true);
- expect(result.data).toBeUndefined();
- expect(result.networkStatus).toBe(NetworkStatus.loading);
- } else if (count === 1) {
- expect(result.loading).toBe(false);
- expect(result.data).toEqual(data1);
- expect(result.networkStatus).toBe(NetworkStatus.ready);
- } else if (count === 2) {
- expect(result.loading).toBe(true);
- expect(result.data).toBeUndefined();
- expect(result.networkStatus).toBe(NetworkStatus.setVariables);
- } else if (count === 3) {
- expect(result.loading).toBe(false);
- expect(result.data).toEqual(data2);
- expect(result.networkStatus).toBe(NetworkStatus.ready);
+ try {
+ switch (count) {
+ case 0:
+ expect(result.loading).toBe(true);
+ expect(result.data).toBeUndefined();
+ expect(result.networkStatus).toBe(NetworkStatus.loading);
+ break;
+ case 1:
+ setTimeout(() => {
+ this.setState({ variables: { first: 2 } });
+ });
+ // fallthrough
+ case 2:
+ expect(result.loading).toBe(false);
+ expect(result.data).toEqual(data1);
+ expect(result.networkStatus).toBe(NetworkStatus.ready);
+ break;
+ case 3:
+ expect(result.loading).toBe(true);
+ expect(result.networkStatus).toBe(NetworkStatus.setVariables);
+ break;
+ case 4:
+ expect(result.data).toEqual(data2);
+ expect(result.networkStatus).toBe(NetworkStatus.ready);
+ break;
+ }
+ } catch (err) {
+ reject(err);
}
+
count++;
return null;
}}
@@ -1196,7 +1248,7 @@ describe('Query component', () => {
);
- return wait(() => expect(count).toBe(4)).then(resolve, reject);
+ return wait(() => expect(count).toBe(5)).then(resolve, reject);
});
itAsync('should update if a manual `refetch` is triggered after a state change', (resolve, reject) => {
@@ -1381,7 +1433,7 @@ describe('Query component', () => {
const link = mockSingleLink(
{ request: { query }, result: { data } },
{ request: { query }, error: new Error('This is an error!') },
- { request: { query }, result: { data: dataTwo } }
+ { request: { query }, result: { data: dataTwo }, delay: 10 },
);
const client = new ApolloClient({
link,
@@ -1395,22 +1447,18 @@ describe('Query component', () => {
function Container() {
return (
-
+
{(result: any) => {
try {
switch (count++) {
case 0:
// Waiting for the first result to load
- expect(result.loading).toBeTruthy();
+ expect(result.loading).toBe(true);
break;
case 1:
- if (!result.data!.allPeople) {
- reject('Should have data by this point');
- break;
- }
// First result is loaded, run a refetch to get the second result
// which is an error.
- expect(result.data!.allPeople).toEqual(
+ expect(result.data.allPeople).toEqual(
data.allPeople
);
setTimeout(() => {
@@ -1421,33 +1469,28 @@ describe('Query component', () => {
break;
case 2:
// Waiting for the second result to load
- expect(result.loading).toBeTruthy();
+ expect(result.loading).toBe(true);
break;
case 3:
- // The error arrived, run a refetch to get the third result
- // which should now contain valid data.
- expect(result.loading).toBeFalsy();
- expect(result.error).toBeTruthy();
setTimeout(() => {
result.refetch().catch(() => {
reject('Expected good data on second refetch.');
});
}, 0);
+ // fallthrough
+ // The error arrived, run a refetch to get the third result
+ // which should now contain valid data.
+ expect(result.loading).toBe(false);
+ expect(result.error).toBeTruthy();
break;
case 4:
- expect(result.loading).toBeTruthy();
+ expect(result.loading).toBe(true);
expect(result.error).toBeFalsy();
break;
case 5:
- expect(result.loading).toBeFalsy();
+ expect(result.loading).toBe(false);
expect(result.error).toBeFalsy();
- if (!result.data) {
- reject('Should have data by this point');
- break;
- }
- expect(result.data.allPeople).toEqual(
- dataTwo.allPeople
- );
+ expect(result.data.allPeople).toEqual(dataTwo.allPeople);
break;
default:
throw new Error('Unexpected fall through');
@@ -1620,8 +1663,6 @@ describe('Query component', () => {
let renderCount = 0;
let onCompletedCallCount = 0;
- let unmount: any;
-
class Component extends React.Component {
state = {
variables: {
@@ -1650,26 +1691,30 @@ describe('Query component', () => {
{({ loading, data }: any) => {
switch (renderCount) {
case 0:
- expect(loading).toBeTruthy();
+ expect(loading).toBe(true);
break;
case 1:
- expect(loading).toBeFalsy();
- expect(data).toEqual(data1);
- break;
case 2:
- expect(loading).toBeTruthy();
+ expect(loading).toBe(false);
+ expect(data).toEqual(data1);
break;
case 3:
- expect(loading).toBeFalsy();
- expect(data).toEqual(data2);
- setTimeout(() => this.setState({ variables: { first: 1 } }));
+ expect(loading).toBe(true);
break;
case 4:
- expect(loading).toBeFalsy();
+ expect(loading).toBe(false);
+ expect(data).toEqual(data2);
+ setTimeout(() => {
+ this.setState({ variables: { first: 1 } });
+ });
+ case 5:
+ expect(loading).toBe(false);
+ expect(data).toEqual(data2);
+ break;
+ case 6:
+ expect(loading).toBe(false);
expect(data).toEqual(data1);
- setTimeout(unmount);
break;
- default:
}
renderCount += 1;
return null;
@@ -1679,11 +1724,11 @@ describe('Query component', () => {
}
}
- unmount = render(
+ render(
- ).unmount;
+ );
return wait(() => {
expect(onCompletedCallCount).toBe(3);
@@ -1740,22 +1785,40 @@ describe('Query component', () => {
});
describe('Partial refetching', () => {
- const origConsoleWarn = console.warn;
+ let errorSpy!: ReturnType;
- beforeAll(() => {
- console.warn = () => null;
+ beforeEach(() => {
+ errorSpy = jest.spyOn(console, 'error')
+ .mockImplementation(() => {});
});
afterAll(() => {
- console.warn = origConsoleWarn;
+ errorSpy.mockRestore();
});
- withErrorSpy(itAsync,
+ // TODO(brian): This is a terrible legacy test which is causing console
+ // error calls no matter what I try and I do not want to care about it
+ // anymore :)
+ itAsync(
'should attempt a refetch when the query result was marked as being ' +
'partial, the returned data was reset to an empty Object by the ' +
'Apollo Client QueryManager (due to a cache miss), and the ' +
'`partialRefetch` prop is `true`',
(resolve, reject) => {
+ const allPeopleQuery: DocumentNode = gql`
+ query people {
+ allPeople(first: 1) {
+ people {
+ name
+ }
+ }
+ }
+ `;
+
+ let done = false;
+ const allPeopleData = {
+ allPeople: { people: [{ name: 'Luke Skywalker' }] },
+ };
const query = allPeopleQuery;
const link = mockSingleLink(
{ request: { query }, result: { data: {} } },
@@ -1764,15 +1827,22 @@ describe('Query component', () => {
const client = new ApolloClient({
link,
- cache: new InMemoryCache({ addTypename: false }),
+ cache: new InMemoryCache(),
});
const Component = () => (
-
+
{(result: any) => {
const { data, loading } = result;
- if (!loading) {
- expect(data).toEqual(allPeopleData);
+ try {
+ if (!loading) {
+ expect(data).toEqual(allPeopleData);
+ expect(errorSpy).toHaveBeenCalledTimes(1);
+ expect(errorSpy.mock.calls[0][0]).toMatch('Missing field');
+ done = true;
+ }
+ } catch (err) {
+ reject(err);
}
return null;
}}
@@ -1785,7 +1855,7 @@ describe('Query component', () => {
);
- return wait().then(resolve, reject);
+ wait(() => done).then(resolve, reject);
}
);
diff --git a/src/react/components/__tests__/client/Subscription.test.tsx b/src/react/components/__tests__/client/Subscription.test.tsx
index b6a33ca9165..c2f6eb809bd 100644
--- a/src/react/components/__tests__/client/Subscription.test.tsx
+++ b/src/react/components/__tests__/client/Subscription.test.tsx
@@ -361,28 +361,35 @@ describe('should update', () => {
{(result: any) => {
const { loading, data } = result;
try {
- if (count === 0) {
- expect(loading).toBeTruthy();
- expect(data).toBeUndefined();
- } else if (count === 1) {
- expect(loading).toBeFalsy();
- expect(data).toEqual(results[0].result.data);
- setTimeout(() => {
- this.setState(
- {
- client: client2
- },
- () => {
- link2.simulateResult(results[1]);
- }
- );
- });
- } else if (count === 2) {
- expect(loading).toBeTruthy();
- expect(data).toBeUndefined();
- } else if (count === 3) {
- expect(loading).toBeFalsy();
- expect(data).toEqual(results[1].result.data);
+ switch (count) {
+ case 0:
+ expect(loading).toBeTruthy();
+ expect(data).toBeUndefined();
+ break;
+ case 1:
+ setTimeout(() => {
+ this.setState(
+ {
+ client: client2
+ },
+ () => {
+ link2.simulateResult(results[1]);
+ }
+ );
+ });
+ // fallthrough
+ case 2:
+ expect(loading).toBeFalsy();
+ expect(data).toEqual(results[0].result.data);
+ break;
+ case 3:
+ expect(loading).toBeTruthy();
+ expect(data).toBeUndefined();
+ break;
+ case 4:
+ expect(loading).toBeFalsy();
+ expect(data).toEqual(results[1].result.data);
+ break;
}
} catch (error) {
reject(error);
@@ -401,7 +408,7 @@ describe('should update', () => {
link.simulateResult(results[0]);
- return wait(() => expect(count).toBe(4)).then(resolve, reject);
+ return wait(() => expect(count).toBe(5)).then(resolve, reject);
});
itAsync('if the query changes', (resolve, reject) => {
@@ -449,28 +456,35 @@ describe('should update', () => {
{(result: any) => {
const { loading, data } = result;
try {
- if (count === 0) {
- expect(loading).toBeTruthy();
- expect(data).toBeUndefined();
- } else if (count === 1) {
- expect(loading).toBeFalsy();
- expect(data).toEqual(results[0].result.data);
- setTimeout(() => {
- this.setState(
- {
- subscription: subscriptionHero
- },
- () => {
- heroLink.simulateResult(heroResult);
- }
- );
- });
- } else if (count === 2) {
- expect(loading).toBeTruthy();
- expect(data).toBeUndefined();
- } else if (count === 3) {
- expect(loading).toBeFalsy();
- expect(data).toEqual(heroResult.result.data);
+ switch (count) {
+ case 0:
+ expect(loading).toBeTruthy();
+ expect(data).toBeUndefined();
+ break;
+ case 1:
+ setTimeout(() => {
+ this.setState(
+ {
+ subscription: subscriptionHero
+ },
+ () => {
+ heroLink.simulateResult(heroResult);
+ }
+ );
+ });
+ // fallthrough
+ case 2:
+ expect(loading).toBeFalsy();
+ expect(data).toEqual(results[0].result.data);
+ break;
+ case 3:
+ expect(loading).toBeTruthy();
+ expect(data).toBeUndefined();
+ break;
+ case 4:
+ expect(loading).toBeFalsy();
+ expect(data).toEqual(heroResult.result.data);
+ break;
}
} catch (error) {
reject(error);
@@ -491,7 +505,7 @@ describe('should update', () => {
userLink.simulateResult(results[0]);
- return wait(() => expect(count).toBe(4)).then(resolve, reject);
+ return wait(() => expect(count).toBe(5)).then(resolve, reject);
});
itAsync('if the variables change', (resolve, reject) => {
@@ -518,31 +532,7 @@ describe('should update', () => {
}
};
- class MockSubscriptionLinkOverride extends MockSubscriptionLink {
- variables: any;
- request(req: Operation) {
- this.variables = req.variables;
- return super.request(req);
- }
-
- simulateResult() {
- if (this.variables.name === 'Luke Skywalker') {
- return super.simulateResult({
- result: {
- data: dataLuke
- }
- });
- } else if (this.variables.name === 'Han Solo') {
- return super.simulateResult({
- result: {
- data: dataHan
- }
- });
- }
- }
- }
-
- const mockLink = new MockSubscriptionLinkOverride();
+ const mockLink = new MockSubscriptionLink();
const mockClient = new ApolloClient({
link: mockLink,
@@ -565,28 +555,35 @@ describe('should update', () => {
{(result: any) => {
const { loading, data } = result;
try {
- if (count === 0) {
- expect(loading).toBeTruthy();
- expect(data).toBeUndefined();
- } else if (count === 1) {
- expect(loading).toBeFalsy();
- expect(data).toEqual(dataLuke);
- setTimeout(() => {
- this.setState(
- {
- variables: variablesHan
- },
- () => {
- mockLink.simulateResult();
- }
- );
- });
- } else if (count === 2) {
- expect(loading).toBeTruthy();
- expect(data).toBeUndefined();
- } else if (count === 3) {
- expect(loading).toBeFalsy();
- expect(data).toEqual(dataHan);
+ switch (count) {
+ case 0:
+ expect(loading).toBeTruthy();
+ expect(data).toBeUndefined();
+ break;
+ case 1:
+ setTimeout(() => {
+ this.setState(
+ {
+ variables: variablesHan
+ },
+ () => {
+ mockLink.simulateResult({ result: { data: dataHan } });
+ }
+ );
+ });
+ // fallthrough
+ case 2:
+ expect(loading).toBeFalsy();
+ expect(data).toEqual(dataLuke);
+ break;
+ case 3:
+ expect(loading).toBeTruthy();
+ expect(data).toBeUndefined();
+ break;
+ case 4:
+ expect(loading).toBeFalsy();
+ expect(data).toEqual(dataHan);
+ break;
}
} catch (error) {
reject(error);
@@ -606,9 +603,9 @@ describe('should update', () => {
);
- mockLink.simulateResult();
+ mockLink.simulateResult({ result: { data: dataLuke } });
- return wait(() => expect(count).toBe(4)).then(resolve, reject);
+ return wait(() => expect(count).toBe(5)).then(resolve, reject);
});
});
diff --git a/src/react/components/__tests__/client/__snapshots__/Query.test.tsx.snap b/src/react/components/__tests__/client/__snapshots__/Query.test.tsx.snap
deleted file mode 100644
index 895c6167e70..00000000000
--- a/src/react/components/__tests__/client/__snapshots__/Query.test.tsx.snap
+++ /dev/null
@@ -1,61 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Query component Partial refetching should attempt a refetch when the query result was marked as being partial, the returned data was reset to an empty Object by the Apollo Client QueryManager (due to a cache miss), and the \`partialRefetch\` prop is \`true\` 1`] = `
-[MockFunction] {
- "calls": Array [
- Array [
- "Missing field 'allPeople' while writing result {}",
- ],
- ],
- "results": Array [
- Object {
- "type": "return",
- "value": undefined,
- },
- ],
-}
-`;
-
-exports[`Query component calls the children prop: result in render prop 1`] = `
-Object {
- "called": true,
- "data": Object {
- "allPeople": Object {
- "people": Array [
- Object {
- "name": "Luke Skywalker",
- },
- ],
- },
- },
- "error": undefined,
- "fetchMore": [Function],
- "loading": false,
- "networkStatus": 7,
- "previousData": undefined,
- "refetch": [Function],
- "startPolling": [Function],
- "stopPolling": [Function],
- "subscribeToMore": [Function],
- "updateQuery": [Function],
- "variables": Object {},
-}
-`;
-
-exports[`Query component calls the children prop: result in render prop while loading 1`] = `
-Object {
- "called": true,
- "data": undefined,
- "error": undefined,
- "fetchMore": [Function],
- "loading": true,
- "networkStatus": 1,
- "previousData": undefined,
- "refetch": [Function],
- "startPolling": [Function],
- "stopPolling": [Function],
- "subscribeToMore": [Function],
- "updateQuery": [Function],
- "variables": Object {},
-}
-`;
diff --git a/src/react/context/ApolloContext.ts b/src/react/context/ApolloContext.ts
index 9e899297881..6a0322bbfae 100644
--- a/src/react/context/ApolloContext.ts
+++ b/src/react/context/ApolloContext.ts
@@ -1,10 +1,11 @@
import * as React from 'react';
import { ApolloClient } from '../../core';
import { canUseWeakMap } from '../../utilities';
+import type { RenderPromises } from '../ssr';
export interface ApolloContextValue {
client?: ApolloClient