如何使用react-apollo模拟数据进行测试

时间:2017-08-15 19:56:11

标签: testing jestjs apollo react-apollo apollo-client

我正在使用react-apollo来构建一个使用GraphQL API的客户端,但是,我非常坚持测试。我想要的是模拟服务器,这样我就可以轻松测试应用程序而无需进行网络调用。

我找到了一些关于如何模拟服务器的指示:

但是在我的应用测试中如何使用这个模拟服务器并没有真正的例子来避免命中服务器。

我的目标是设置集成测试以声明应用程序实际正在运行:

describe('Profile feature', () => {
  beforeAll(() => {
    store = setupStore();
    app = mount(
      <ApolloProvider store={store} client={apolloClient}>
        <ConnectedRouter history={history}>
          <App />
        </ConnectedRouter>
      </ApolloProvider>
    );
  });
});

商店正在使用Redux,正在创建客户端:

const networkInterface = createNetworkInterface({
  uri: process.env.REACT_APP_API_URL
});

export const apolloClient = new ApolloClient({
  networkInterface
});

如何在这里使用带有graphql-tools的模拟服务器而不是实际的API?

3 个答案:

答案 0 :(得分:13)

我找到了两种为apollo-client查询创建模拟数据的方法:

第一种是使用graphql-tools根据您的后端架构创建一个模拟服务器,为了将这个模拟服务器与您的测试连接,可以创建一个mockNetworkInterface,如下所示:

const { mockServer } = require("graphql-tools");
const { print } = require("graphql/language/printer");


class MockNetworkInterface {
  constructor(schema, mocks = {}) {
    if (schema === undefined) {
      throw new Error('Cannot create Mock Api without specifying a schema');
    }
    this.mockServer = mockServer(schema, mocks);
  }

  query(request) {
    return this.mockServer.query(print(request.query), request.variables);
  }
}

您可以将此网络接口传递给ApolloClient组件,它应该可以正常工作!

进行此设置需要在您的客户端中更新您的API架构,因此我觉得这样做有点痛苦。

另一种方法是使用mockNetworkInterface

提供的apollo-client/test-utils

你可以这样使用它:

import App from './App';
import { UserMock, PublicationMock } from '../__mocks__/data';
import { mockNetworkInterface } from 'react-apollo/test-utils';
import ApolloClient from 'apollo-client';
import { ApolloProvider } from 'react-apollo';

// We will be using here the exact same Query defined in our components
// We will provide a custom result or a custom error
const GraphQLMocks = [
  {
    request: {
      query: UserProfileQuery,
      variables: {}
    },
    result: {
      data: {
        current_user: UserMock
      }
    }
  }
];

// To set it up we pass the mocks to the mockNetworkInterface
const setupTests = () => {
  const networkInterface = mockNetworkInterface.apply(null, GraphQLMocks);
  const client = new ApolloClient({ networkInterface, addTypename: false });

  const wrapper = mount(
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  );

  return {
    store,
    wrapper
  };
};

// Then the tests look like this
describe('Profile feature', () => {
  test('Profile view should render User details', async () => {
    const { wrapper, store } = setupTests();

    const waitFor = createWaitForElement('.profile');

    await waitFor(wrapper);

    const tag = wrapper.find('.profile-username');
    expect(tag.text()).toEqual(`${UserMock.first_name} ${UserMock.last_name}`);
  });
});

addTypename: false传递给ApolloClient个实例很重要,否则您需要手动为所有查询添加__typename

您可以在此处检查mockNetworkInterface的实现:https://github.com/apollographql/apollo-test-utils/blob/master/src/mocks/mockNetworkInterface.ts

答案 1 :(得分:7)

你也可以使用MockedProvider,这样可以更简单。

<强> withPersons.js

import { gql, graphql } from 'react-apollo'

export const PERSONS_QUERY = gql`
  query personsQuery {
    persons {
      name
      city
    }
  }
`

export const withPersons = graphql(PERSONS_QUERY)

<强> withPersons.test.js

/* eslint-disable react/prop-types */

import React, { Component } from 'react'
import { MockedProvider } from 'react-apollo/test-utils'

import { withPersons, PERSONS_QUERY } from '../withPersons'

it('withPersons', (done) => {
  const mockedData = {
    persons: [
      {
        name: 'John',
        city: 'Liverpool',
      },
      {
        name: 'Frank',
        city: 'San Diego',
      },
    ],
  }

  const variables = { cache: false }

  class Dummy extends Component {
    componentDidMount() {
      const { loading, persons } = this.props.data
      expect(loading).toBe(true)
      expect(persons).toBe(undefined)
    }

    componentWillReceiveProps(nextProps) {
      const { loading, persons } = nextProps.data

      expect(loading).toBe(false)
      expect(persons).toEqual(mockedData.persons)
      done()
    }

    render() {
      return null
    }
  }
  const DummyWithPersons = withPersons(Dummy)
  mount(
    <MockedProvider
      removeTypename
      mocks={[
        {
          request: { query: PERSONS_QUERY, variables },
          result: { data: mockedData } },
      ]}
    >
      <DummyWithPersons />
    </MockedProvider>,
  )
})

注意:通过使用Dummy组件,您只需测试graphql()查询和突变以及配置它们的方式(选项,道具,跳过,变量等)。因此您不会安装实际的React组件。最好对那些处于“未连接”状态的人进行测试。

答案 2 :(得分:1)

一段时间以来,我写了一篇博客文章可能会有所帮助:http://blog.dideric.is/2018/03/18/Testing-apollo-containers/

阿波罗(Apollo)有一种叫做LinkSchema的东西,这使卡洛斯(Carlos)提到的第一种方法变得容易得多。它仍然需要一些设置,但是我认为这是值得的。如果您是手动创建响应,那么您就不得不担心让测试保持最新状态,或者在架构更改且代码中没有考虑到它时获得误报。