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

Resuscribe after error in Query component #1580

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
22 changes: 21 additions & 1 deletion src/Query.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,13 @@ class Query<TData = any> extends React.Component<
private startQuerySubscription = () => {
this.querySubscription = this.queryObservable.subscribe({
next: this.updateCurrentData,
error: this.updateCurrentData,
error: error => {
this.resubscribeToQuery();
// Quick fix for https://github.com/apollostack/react-apollo/issues/378
if (!error.hasOwnProperty('graphQLErrors')) throw error;

this.updateCurrentData();
},
});
};

Expand All @@ -193,6 +199,20 @@ class Query<TData = any> extends React.Component<
}
};

private resubscribeToQuery() {
this.removeQuerySubscription();

const lastError = this.queryObservable.getLastError();
const lastResult = this.queryObservable.getLastResult();
// 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.startQuerySubscription();
Object.assign(this.queryObservable, { lastError, lastResult });
}

private updateCurrentData = () => {
this.setState({ result: this.queryObservable.currentResult() });
};
Expand Down
101 changes: 101 additions & 0 deletions test/client/Query.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -982,4 +982,105 @@ describe('Query component', () => {
</MockedProvider>,
);
});

it('should be able to 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;

function Container() {
return (
<Query query={query} notifyOnNetworkStatusChange>
{(result) => {
try {
switch (count++) {
case 0:
// Waiting for the first result to load
expect(result.loading).toBeTruthy();
break;
case 1:
// First result is loaded, run a refetch to get the second result
// which is an error.
expect(stripSymbols(result.data.allPeople)).toEqual(
data.allPeople,
);
setTimeout(() => {
result
.refetch()
.then((val) => {
done.fail('Expected error value on first refetch.');
}, noop);
}, 0);
break;
case 2:
// Waiting for the second result to load
expect(result.loading).toBeTruthy();
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(() => {
done.fail('Expected good data on second refetch.');
});
}, 0);
break;
// Further fix required in QueryManager, we should have an extra
// step for the loading status of the third result
// case 4:
// expect(result.loading).toBeTruthy();
// expect(result.error).toBeFalsy();
// break;
case 4:
// Third result's data is loaded
expect(result.loading).toBeFalsy();
expect(result.error).toBeFalsy();
expect(stripSymbols(result.data.allPeople)).toEqual(
dataTwo.allPeople,
);
done();
break;
default:
throw new Error('Unexpected fall through');
}
} catch (e) {
done.fail(e);
}
return null;
}}
</Query>
)
}

wrapper = mount(
<ApolloProvider client={client}>
<Container />
</ApolloProvider>,
);
});
});
4 changes: 1 addition & 3 deletions test/client/__snapshots__/Query.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ Object {
}
`;

exports[
`Query component calls the children prop: result in render prop while loading 1`
] = `
exports[`Query component calls the children prop: result in render prop while loading 1`] = `
Object {
"data": Object {},
"error": undefined,
Expand Down