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

Commit

Permalink
fix: force update just after loading done with error even if the erro…
Browse files Browse the repository at this point in the history
…r is unchanged (#3477)
  • Loading branch information
jet2jet authored and hwillson committed Sep 11, 2019
1 parent fe55a38 commit e9d33d8
Show file tree
Hide file tree
Showing 2 changed files with 226 additions and 1 deletion.
220 changes: 220 additions & 0 deletions packages/hooks/src/__tests__/useQuery.test.tsx
Expand Up @@ -498,6 +498,226 @@ describe('useQuery Hook', () => {
});
}
);

it('should render errors (different error messages) with loading done on refetch', async () => {
const query = gql`
query SomeQuery {
stuff {
thing
}
}
`;

const mocks = [
{
request: { query },
result: {
errors: [new GraphQLError('an error 1')]
}
},
{
request: { query },
result: {
errors: [new GraphQLError('an error 2')]
}
}
];

let renderCount = 0;
function App() {
const { loading, error, refetch } = useQuery(query, {
notifyOnNetworkStatusChange: true
});

switch (renderCount) {
case 0:
expect(loading).toBeTruthy();
expect(error).toBeUndefined();
break;
case 1:
expect(loading).toBeFalsy();
expect(error).toBeDefined();
expect(error!.message).toEqual('GraphQL error: an error 1');
setTimeout(() => {
// catch here to avoid failing due to 'uncaught promise rejection'
refetch().catch(() => {});
});
break;
case 2:
expect(loading).toBeTruthy();
break;
case 3:
expect(loading).toBeFalsy();
expect(error).toBeDefined();
expect(error!.message).toEqual('GraphQL error: an error 2');
break;
default: // Do nothing
}

renderCount += 1;
return null;
}

render(
<MockedProvider mocks={mocks}>
<App />
</MockedProvider>
);

await wait(() => {
expect(renderCount).toBe(4);
});
});

it('should render errors (same error messages) with loading done on refetch', async () => {
const query = gql`
query SomeQuery {
stuff {
thing
}
}
`;

const mocks = [
{
request: { query },
result: {
errors: [new GraphQLError('same error message')]
}
},
{
request: { query },
result: {
errors: [new GraphQLError('same error message')]
}
}
];

let renderCount = 0;
function App() {
const { loading, error, refetch } = useQuery(query, {
notifyOnNetworkStatusChange: true
});

switch (renderCount) {
case 0:
expect(loading).toBeTruthy();
expect(error).toBeUndefined();
break;
case 1:
expect(loading).toBeFalsy();
expect(error).toBeDefined();
expect(error!.message).toEqual('GraphQL error: same error message');
setTimeout(() => {
// catch here to avoid failing due to 'uncaught promise rejection'
refetch().catch(() => {});
});
break;
case 2:
expect(loading).toBeTruthy();
break;
case 3:
expect(loading).toBeFalsy();
expect(error).toBeDefined();
expect(error!.message).toEqual('GraphQL error: same error message');
break;
default: // Do nothing
}

renderCount += 1;
return null;
}

render(
<MockedProvider mocks={mocks}>
<App />
</MockedProvider>
);

await wait(() => {
expect(renderCount).toBe(4);
});
});

it('should render both success and errors (same error messages) with loading done on refetch', async () => {
const mocks = [
{
request: { query: CAR_QUERY },
result: {
errors: [new GraphQLError('same error message')]
}
},
{
request: { query: CAR_QUERY },
result: {
data: CAR_RESULT_DATA
}
},
{
request: { query: CAR_QUERY },
result: {
errors: [new GraphQLError('same error message')]
}
}
];

let renderCount = 0;
function App() {
const { loading, data, error, refetch } = useQuery(CAR_QUERY, {
notifyOnNetworkStatusChange: true
});

switch (renderCount) {
case 0:
expect(loading).toBeTruthy();
expect(error).toBeUndefined();
break;
case 1:
expect(loading).toBeFalsy();
expect(error).toBeDefined();
expect(error!.message).toEqual('GraphQL error: same error message');
setTimeout(() => {
// catch here to avoid failing due to 'uncaught promise rejection'
refetch().catch(() => {});
});
break;
case 2:
expect(loading).toBeTruthy();
break;
case 3:
expect(loading).toBeFalsy();
expect(error).toBeUndefined();
expect(data).toEqual(CAR_RESULT_DATA);
setTimeout(() => {
// catch here to avoid failing due to 'uncaught promise rejection'
refetch().catch(() => {});
});
break;
case 4:
expect(loading).toBeTruthy();
break;
case 5:
expect(loading).toBeFalsy();
expect(error).toBeDefined();
expect(error!.message).toEqual('GraphQL error: same error message');
break;
default: // Do nothing
}

renderCount += 1;
return null;
}

render(
<MockedProvider mocks={mocks}>
<App />
</MockedProvider>
);

await wait(() => {
expect(renderCount).toBe(6);
});
});
});

describe('Pagination', () => {
Expand Down
7 changes: 6 additions & 1 deletion packages/hooks/src/data/QueryData.ts
Expand Up @@ -298,7 +298,12 @@ export class QueryData<TData, TVariables> extends OperationData {
error: error => {
this.resubscribeToQuery();
if (!error.hasOwnProperty('graphQLErrors')) throw error;
if (!isEqual(error, this.previousData.error)) {

const previousResult = this.previousData.result;
if (
(previousResult && previousResult.loading) ||
!isEqual(error, this.previousData.error)
) {
this.previousData.error = error;
this.forceUpdate();
}
Expand Down

0 comments on commit e9d33d8

Please sign in to comment.