【问题标题】:How to use a mocked data with react-apollo for tests如何使用带有 react-apollo 的模拟数据进行测试
【发布时间】:2018-01-23 19:53:33
【问题描述】:

我正在使用 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?

【问题讨论】:

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


    【解决方案1】:

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

    Apollo 有一个名为 LinkSchema 的东西,这使得 Carlos 提到的第一种方法更容易。它仍然需要一些设置,但我认为这是值得的。如果您手动创建响应,则您必须更加担心保持测试最新/当架构更改并且您没有在代码中考虑它时得到误报。

    【讨论】:

      【解决方案2】:

      我发现了 2 种为 apollo 客户端查询创建模拟数据的不同方法:

      第一个是使用graphql-tools 根据您的后端架构创建一个模拟服务器,为了将这个模拟服务器与您的测试连接起来,可以像这样创建一个模拟网络接口:

      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 架构,所以我觉得这样做有点麻烦。

      另一种方法是使用apollo-client/test-utils提供的mockNetworkInterface

      你可以这样使用它:

      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

      【讨论】:

      • 感谢您的提问和回答!经过数小时的搜索,这让我走上了正确的道路!
      • 很高兴能提供帮助,我也为此苦苦挣扎了一段时间
      • @CarlosMartinez 哪一个是公认的最佳实践或最受支持的库/选项?
      • @CarlosMartinez 这太棒了!我知道如何测试服务器端代码没问题,但对如何使用react-apollo 集成管理前端代码库感到迷茫。写得很棒,非常感谢您提供关于这个问题的研究。
      • 我在尝试运行此代码时收到错误 TypeError: Cannot read property 'apply' of undefined
      【解决方案3】:

      你也可以使用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 组件。最好测试那些处于“未连接”状态的人。

      【讨论】:

      • 是的,你可以,我对 MockedProvider 的唯一问题是你不能将 addTypename: false 传递给底层的 apollo 客户端,所以你的模拟需要在任何地方都包含 __typename。他们合并了我打开的一个 PR 来解决这个问题 github.com/apollographql/react-apollo/pull/1001
      • 哦,我明白了,那是你的道具!哈哈 - 我今天才注意到它
      • 使用渲染道具而不是 HOC 时你会怎么做?
      • 我不再使用这种方法,我转而对我的组件进行集成测试。另外,我还没有使用 render prop 组件,所以我不能告诉你,对不起。
      • @DanielOcampo 我没有时间写一篇文章,但我用我使用这种方法的项目中的一些代码 sn-ps 做了一个要点。 gist.github.com/devboell/971c5477532fcae674c49110ab720ceb
      猜你喜欢
      • 2022-11-28
      • 2021-05-29
      • 1970-01-01
      • 2020-05-17
      • 2023-03-26
      • 2020-02-28
      • 2020-09-13
      • 2021-08-28
      • 2015-05-07
      相关资源
      最近更新 更多