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

Car*_*nez 10 testing apollo jestjs 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>
    );
  });
});
Run Code Online (Sandbox Code Playgroud)

商店正在使用Redux,正在创建客户端,如下所示:

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

export const apolloClient = new ApolloClient({
  networkInterface
});
Run Code Online (Sandbox Code Playgroud)

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

Car*_*nez 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);
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以将此网络接口传递给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}`);
  });
});
Run Code Online (Sandbox Code Playgroud)

传递addTypename: falseApolloClient实例很重要,否则您需要__typename手动添加所有查询.

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


dev*_*ell 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)
Run Code Online (Sandbox Code Playgroud)

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>,
  )
})
Run Code Online (Sandbox Code Playgroud)

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