diff --git a/src/__tests__/useMutation-test.tsx b/src/__tests__/useMutation-test.tsx index 0f99ce8..1ea7996 100644 --- a/src/__tests__/useMutation-test.tsx +++ b/src/__tests__/useMutation-test.tsx @@ -84,6 +84,31 @@ const TASKS_MOCKS = [ }, }, }, + + { + request: { + query: gql` + mutation AddTaskMissingFieldMutation($input: AddTaskMutationInput!) { + addTask(input: $input) { + id + text + __typename + } + } + `, + variables: { input: { text: 'Learn Jest' } }, + }, + result: { + data: { + __typename: 'Mutation', + addTask: { + __typename: 'Task', + id: '4', + text: 'Learn Jest', + }, + }, + }, + }, ]; const TASKS_QUERY = gql` @@ -115,6 +140,15 @@ const ADD_TASK_MUTATION = gql` } `; +const ADD_TASK_MISSING_FIELD_MUTATION = gql` + mutation AddTaskMissingFieldMutation($input: AddTaskMutationInput!) { + addTask(input: $input) { + id + text + } + } +`; + interface TaskFragment { id: number; text: string; @@ -254,3 +288,194 @@ it('should allow to pass options forwarded to the mutation', async () => { expect(container.querySelectorAll('li')).toHaveLength(4); expect(container.querySelectorAll('li')[3].textContent).toBe('Learn Jest'); }); + +it('should have an error if the mutation has a field missings', async () => { + // Added 1 more time the query mock for TASKS_QUERY, because of this comment + // https://github.com/apollographql/react-apollo/issues/617#issuecomment-29310361 + TASKS_MOCKS.push({ + request: { + query: gql` + query TasksQuery { + tasks { + id + text + completed + __typename + } + } + `, + variables: {}, + }, + result: { + data: { + __typename: 'Query', + tasks: [ + ...SAMPLE_TASKS, + { + __typename: 'Task', + id: 4, + text: 'Learn Jest', + } as any, + ], + }, + }, + }); + + let tasks; + function TasksWithMutation() { + const { data, error, loading } = useQuery(TASKS_QUERY); + const addTask = useMutation }>( + ADD_TASK_MISSING_FIELD_MUTATION, + { + update: (proxy, mutationResult) => { + const previousData = proxy.readQuery<{ tasks: TaskFragment[] }>({ + query: TASKS_QUERY, + }); + previousData!.tasks.push(mutationResult!.data!.addTask); + proxy.writeQuery({ data: previousData, query: TASKS_QUERY }); + }, + variables: { + input: { + text: 'Learn Jest', + }, + }, + } + ); + + tasks = data.tasks; + if (error) { + throw error; + } + + if (loading) { + return <>Loading; + } + + return ( + <> + + + + ); + } + + const client = createClient({ mocks: TASKS_MOCKS }); + const { container, getByTestId } = render( + + + + ); + + await wait(); + + const addTaskButton = getByTestId('add-task-button'); + fireEvent.click(addTaskButton); + await wait(); + + expect(container.querySelectorAll('li')).toHaveLength(0); + expect(tasks).toBe(undefined); +}); + +it('should work if the mutation has a field missings and the partialRefetch is true', async () => { + // Added 1 more time the query mock for TASKS_QUERY, because of this comment + // https://github.com/apollographql/react-apollo/issues/617#issuecomment-29310361 + TASKS_MOCKS.push({ + request: { + query: gql` + query TasksQuery { + tasks { + id + text + completed + __typename + } + } + `, + variables: {}, + }, + result: { + data: { + __typename: 'Query', + tasks: [ + ...SAMPLE_TASKS, + { + __typename: 'Task', + id: 4, + text: 'Learn Jest', + } as any, + ], + }, + }, + }); + + let tasks; + function TasksWithMutation() { + const { data, error, loading } = useQuery(TASKS_QUERY, { + partialRefetch: true, + }); + const addTask = useMutation }>( + ADD_TASK_MISSING_FIELD_MUTATION, + { + update: (proxy, mutationResult) => { + const previousData = proxy.readQuery<{ tasks: TaskFragment[] }>({ + query: TASKS_QUERY, + }); + previousData!.tasks.push(mutationResult!.data!.addTask); + proxy.writeQuery({ data: previousData, query: TASKS_QUERY }); + }, + variables: { + input: { + text: 'Learn Jest', + }, + }, + } + ); + + tasks = data.tasks; + if (error) { + throw error; + } + + if (loading) { + return <>Loading; + } + + return ( + <> + + + + ); + } + + const client = createClient({ mocks: TASKS_MOCKS }); + const { getByTestId } = render( + + + + ); + + await wait(); + + const addTaskButton = getByTestId('add-task-button'); + fireEvent.click(addTaskButton); + await wait(); + + expect(tasks).toHaveLength(4); +}); diff --git a/src/useQuery.ts b/src/useQuery.ts index 17a7c47..57e73dd 100644 --- a/src/useQuery.ts +++ b/src/useQuery.ts @@ -42,6 +42,7 @@ export interface QueryHookOptions ssr?: boolean; skip?: boolean; suspend?: boolean; + partialRefetch?: boolean; } export interface QueryHookResult @@ -67,6 +68,7 @@ export function useQuery< ssr = true, skip = false, suspend = false, + partialRefetch = false, // Watch options pollInterval, @@ -163,6 +165,28 @@ export function useQuery< }; } + // Taken from https://github.com/apollographql/react-apollo/blob/22f8ebf52b26b348d6be905d5b7fbbfea51c1541/src/Query.tsx#L455-L472 + if ( + partialRefetch && + Object.keys(result.data).length === 0 && + result.partial && + fetchPolicy !== 'cache-only' + ) { + data = { + ...result.data, + ...(observableQuery.getLastResult() || {}).data, + }; + + const partialRefetchResult = { + ...helpers, + data, + loading: true, + networkStatus: NetworkStatus.loading, + }; + partialRefetchResult.refetch(); + return partialRefetchResult; + } + return { ...helpers, data,