Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Resubscribe after error -- apollo-client issue 2513 #1531

Merged
merged 6 commits into from
Jan 17, 2018
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"bundlesize": [
{
"path": "./lib/umd/react-apollo.js",
"maxSize": "4.7 KB"
"maxSize": "4.8 KB"
}
],
"lint-staged": {
Expand Down
19 changes: 19 additions & 0 deletions src/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ export default function graphql<
};

const handleError = error => {
this.resubscribeToQuery();
// Quick fix for https://github.com/apollostack/react-apollo/issues/378
if (error.hasOwnProperty('graphQLErrors')) return next({ error });
throw error;
Expand All @@ -476,6 +477,24 @@ export default function graphql<
}
}

resubscribeToQuery() {
const lastSubscription = this.querySubscription;
if (lastSubscription) {
delete this.querySubscription;
}
const { lastError, lastResult } = this.queryObservable;
// If lastError is set, the observable will immediately
// send it, causing the stream to terminate on initialization.
// We clear everything here and restore it afterward to
// make sure the new subscription sticks.
this.queryObservable.resetLastResults();
this.subscribeToQuery();
Object.assign(this.queryObservable, { lastError, lastResult });
if (lastSubscription) {
(lastSubscription as ZenObservable.Subscription).unsubscribe();
}
}

shouldSkip(props = this.props) {
return mapPropsToSkip(props);
}
Expand Down
85 changes: 84 additions & 1 deletion test/client/graphql/queries/errors.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ describe('[queries] errors', () => {
expect(stripSymbols(props.data.allPeople)).toEqual(
data.allPeople,
);
props.data.refetch();
props.data.refetch().catch(() => null);
break;
case 1:
expect(props.data.loading).toBeTruthy();
Expand Down Expand Up @@ -418,4 +418,87 @@ describe('[queries] errors', () => {
</ApolloProvider>,
);
});

it('can refetch after there was a network error', done => {
const query = gql`
query somethingelse {
allPeople(first: 1) {
people {
name
}
}
}
`;
const data = { allPeople: { people: [{ name: 'Luke Skywalker' }] } };
const dataTwo = { allPeople: { people: [{ name: 'Princess Leia' }] } };
const link = mockSingleLink(
{ request: { query }, result: { data } },
{ request: { query }, error: new Error('This is an error!') },
{ request: { query }, result: { data: dataTwo } },
);
const client = new ApolloClient({
link,
cache: new Cache({ addTypename: false }),
});

let count = 0;
const noop = () => null;
@graphql(query, { options: { notifyOnNetworkStatusChange: true } })
class Container extends React.Component<any, any> {
componentWillReceiveProps(props) {
try {
switch (count++) {
case 0:
props.data
.refetch()
.then(() => {
done.fail('Expected error value on first refetch.');
})
.catch(noop);
break;
case 1:
expect(props.data.loading).toBeTruthy();
break;
case 2:
expect(props.data.loading).toBeFalsy();
expect(props.data.error).toBeTruthy();
props.data
.refetch()
.then(noop)
.catch(() => {
done.fail('Expected good data on second refetch.');
});
break;
// Further fix required in QueryManager
// case 3:
// expect(props.data.loading).toBeTruthy();
// expect(props.data.error).toBeFalsy();
// break;
case 3:
expect(props.data.loading).toBeFalsy();
expect(props.data.error).toBeFalsy();
expect(stripSymbols(props.data.allPeople)).toEqual(
dataTwo.allPeople,
);
done();
break;
default:
throw new Error('Unexpected fall through');
}
} catch (e) {
done.fail(e);
}
}

render() {
return null;
}
}

renderer.create(
<ApolloProvider client={client}>
<Container />
</ApolloProvider>,
);
});
});