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

Mutation error render prop #2374

Merged
merged 5 commits into from
Sep 28, 2018
Merged
Show file tree
Hide file tree
Changes from 4 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
8 changes: 5 additions & 3 deletions src/Mutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,14 @@ class Mutation<TData = any, TVariables = OperationVariables> extends React.Compo
}
const { onCompleted, ignoreResults } = this.props;

const data = response.data as TData;
const { data, errors } = response;
const error =
errors && errors.length > 0 ? new ApolloError({ graphQLErrors: errors }) : undefined;

const callOncomplete = () => (onCompleted ? onCompleted(data) : null);
const callOncomplete = () => (onCompleted ? onCompleted(data as TData) : null);

if (this.isMostRecentMutation(mutationId) && !ignoreResults) {
this.setState({ loading: false, data }, callOncomplete);
this.setState({ loading: false, data, error }, callOncomplete);
} else {
callOncomplete();
}
Expand Down
142 changes: 140 additions & 2 deletions test/client/Mutation.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import { mount } from 'enzyme';
import gql from 'graphql-tag';
import { ApolloClient } from 'apollo-client';
import { ApolloClient, ApolloError } from 'apollo-client';
import { InMemoryCache as Cache } from 'apollo-cache-inmemory';
import { DataProxy } from 'apollo-cache';
import { ExecutionResult } from 'graphql';
import { ExecutionResult, GraphQLError } from 'graphql';

import { ApolloProvider, Mutation, Query } from '../../src';
import { MockedProvider, MockLink, mockSingleLink } from '../../src/test-utils';
Expand Down Expand Up @@ -465,6 +465,144 @@ it('renders an error state', done => {
);
});

it('renders an error state and throws when encountering graphql errors', done => {
let count = 0;

const expectedError = new ApolloError({ graphQLErrors: [new GraphQLError('error occurred')] });

const Component = () => (
<Mutation mutation={mutation}>
{(createTodo, result) => {
if (count === 0) {
setTimeout(() =>
createTodo()
.then(() => {
done.fail('Did not expect a result');
})
.catch(e => {
expect(e).toEqual(expectedError);
}),
);
} else if (count === 1) {
expect(result.loading).toBeTruthy();
} else if (count === 2) {
expect(result.error).toEqual(expectedError);
done();
}
count++;
return <div />;
}}
</Mutation>
);

const mockError = [
{
request: { query: mutation },
result: {
errors: [new GraphQLError('error occurred')],
},
},
];

mount(
<MockedProvider mocks={mockError}>
<Component />
</MockedProvider>,
);
});

it('renders an error state and does not throw when encountering graphql errors when errorPolicy=all', done => {
let count = 0;
const Component = () => (
<Mutation mutation={mutation}>
{(createTodo, result) => {
if (count === 0) {
setTimeout(() =>
createTodo()
.then(fetchResult => {
if (fetchResult && fetchResult.errors) {
expect(fetchResult.errors.length).toEqual(1);
expect(fetchResult.errors[0]).toEqual(new GraphQLError('error occurred'));
} else {
done.fail(`Expected an object with array of errors but got ${fetchResult}`);
}
})
.catch(e => {
done.fail(e);
}),
);
} else if (count === 1) {
expect(result.loading).toBeTruthy();
} else if (count === 2) {
expect(result.error).toEqual(
new ApolloError({ graphQLErrors: [new GraphQLError('error occurred')] }),
);
done();
}
count++;
return <div />;
}}
</Mutation>
);

const mockError = [
{
request: { query: mutation },
result: {
errors: [new GraphQLError('error occurred')],
},
},
];

mount(
<MockedProvider defaultOptions={{ mutate: { errorPolicy: 'all' } }} mocks={mockError}>
<Component />
</MockedProvider>,
);
});

it('renders an error state and throws when encountering network errors when errorPolicy=all', done => {
let count = 0;
const expectedError = new ApolloError({ networkError: new Error('network error') });
const Component = () => (
<Mutation mutation={mutation}>
{(createTodo, result) => {
if (count === 0) {
setTimeout(() =>
createTodo()
.then(() => {
done.fail('Did not expect a result');
})
.catch(e => {
expect(e).toEqual(expectedError);
}),
);
} else if (count === 1) {
expect(result.loading).toBeTruthy();
} else if (count === 2) {
expect(result.error).toEqual(expectedError);
done();
}
count++;
return <div />;
}}
</Mutation>
);

const mockError = [
{
request: { query: mutation },
error: new Error('network error'),
},
];

mount(
<MockedProvider defaultOptions={{ mutate: { errorPolicy: 'all' } }} mocks={mockError}>
<Component />
</MockedProvider>,
);
});

it('calls the onError prop if the mutation encounters an error', done => {
let onRenderCalled = false;

Expand Down