From 23d131a7ec202f6b3f9952a1f9a04dd8866aa7d2 Mon Sep 17 00:00:00 2001 From: Jonas Faber Date: Wed, 5 Jul 2017 17:40:08 +0200 Subject: [PATCH] Add support for client in options (#729) * add support for client in options Adds support for client in graphql HoC to support usecases with more than one ApolloClient * Client is no longer required in context because it can get passed via options. * Dont use calculateOptions if using a mutation. Because it checks if variables are present * Use mapProps instead of calcluateOptions for componentWillReceiveProps. * Update client if client props change. * Skip-Test now no longer expects option.client to be not accesed. * Add test for client in options. * Update Changelog.md --- Changelog.md | 1 + src/graphql.tsx | 23 ++++-- .../client/graphql/client-option.test.tsx | 81 +++++++++++++++++++ .../client/graphql/queries/skip.test.tsx | 4 +- 4 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 test/react-web/client/graphql/client-option.test.tsx diff --git a/Changelog.md b/Changelog.md index 5b356eac23..7033501e7b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,7 @@ # Change log ### vNext +- Feature: You can now supply a client in options object passed to the `graphql` high oder component. [PR #729] ### 1.4.2 - Fix: Fix component reference and variable statement for flow types diff --git a/src/graphql.tsx b/src/graphql.tsx index c1e2a779a6..884c86a649 100644 --- a/src/graphql.tsx +++ b/src/graphql.tsx @@ -39,6 +39,7 @@ export declare interface MutationOpts { variables?: Object; optimisticResponse?: Object; updateQueries?: MutationQueryReducersMap; + client?: ApolloClient; } export declare interface QueryOpts { @@ -46,6 +47,7 @@ export declare interface QueryOpts { variables?: { [key: string]: any }; fetchPolicy?: FetchPolicy; pollInterval?: number; + client?: ApolloClient; // deprecated skip?: boolean; } @@ -161,7 +163,7 @@ export default function graphql + +import * as React from 'react'; +import * as PropTypes from 'prop-types'; +import * as ReactDOM from 'react-dom'; +import * as renderer from 'react-test-renderer'; +import { mount, shallow } from 'enzyme'; +import gql from 'graphql-tag'; +import ApolloClient, { ApolloError, ObservableQuery } from 'apollo-client'; +import { mockNetworkInterface } from '../../../../src/test-utils'; +import { ApolloProvider, graphql} from '../../../../src'; + +describe('client option', () => { + + it('renders with client from options', () => { + const query = gql`query people { allPeople(first: 1) { people { name } } }`; + const data = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } }; + const networkInterface = mockNetworkInterface({ request: { query }, result: { data } }); + const client = new ApolloClient({ networkInterface, addTypename: false }); + const config = { + options: { + client, + } + }; + const ContainerWithData = graphql(query, config)((props) => null); + shallow(); + }); + + it('ignores client from context if client from options is present', (done) => { + const query = gql`query people { allPeople(first: 1) { people { name } } }`; + const dataProvider = { allPeople: { people: [ { name: 'Leia Organa Solo' } ] } }; + const networkInterfaceProvider = mockNetworkInterface({ request: { query }, result: { data: dataProvider } }); + const clientProvider = new ApolloClient({ networkInterface: networkInterfaceProvider, addTypename: false }); + const dataOptions = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } }; + const networkInterfaceOptions = mockNetworkInterface({ request: { query }, result: { data: dataOptions } }); + const clientOptions = new ApolloClient({ networkInterface: networkInterfaceOptions, addTypename: false }); + + const config = { + options: { + client: clientOptions, + } + }; + + class Container extends React.Component { + componentWillReceiveProps({ data }) { // tslint:disable-line + expect(data.loading).toBe(false); // first data + expect(data.allPeople).toMatchObject({ people: [ { name: 'Luke Skywalker' } ] }); + done(); + } + render() { + return null; + } + }; + const ContainerWithData = graphql(query, config)(Container); + renderer.create(); + + }); + it('exposes refetch as part of the props api', (done) => { + const query = gql`query people($first: Int) { allPeople(first: $first) { people { name } } }`; + const variables = { first: 1 }; + const data1 = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } }; + const networkInterface = mockNetworkInterface( + { request: { query, variables }, result: { data: data1 } }, + ); + const client = new ApolloClient({ networkInterface, addTypename: false }); + + let hasRefetched, count = 0; + @graphql(query) + class Container extends React.Component { + componentWillReceiveProps({ data }) { // tslint:disable-line + expect(data.loading).toBe(false); // first data + done(); + } + render() { + return null; + } + }; + + renderer.create(); + }); +}); diff --git a/test/react-web/client/graphql/queries/skip.test.tsx b/test/react-web/client/graphql/queries/skip.test.tsx index 1e38cfd1df..5bb7b76162 100644 --- a/test/react-web/client/graphql/queries/skip.test.tsx +++ b/test/react-web/client/graphql/queries/skip.test.tsx @@ -123,7 +123,7 @@ describe('[queries] skip', () => { renderer.create(); }); - it('doesn\'t run options or props when skipped', (done) => { + it('doesn\'t run options or props when skipped, except option.client', (done) => { const query = gql`query people { allPeople(first: 1) { people { name } } }`; const data = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } }; const networkInterface = mockNetworkInterface({ request: { query }, result: { data } }); @@ -132,7 +132,7 @@ describe('[queries] skip', () => { let queryExecuted; @graphql(query, { skip: ({ skip }) => skip, - options: ({ willThrowIfAccesed }) => ({ pollInterval: willThrowIfAccesed.pollInterval }), + options: ({ client, ...willThrowIfAccesed }) => ({ pollInterval: willThrowIfAccesed.pollInterval }), props: ({ willThrowIfAccesed }) => ({ pollInterval: willThrowIfAccesed.pollInterval }), }) class Container extends React.Component {