【问题标题】:How can I properly test a component which is an Apollo GraphQL query?如何正确测试作为 Apollo GraphQL 查询的组件?
【发布时间】:2019-06-17 18:48:52
【问题描述】:

我有一种情况,在同一个测试工作几个小时后,我感到很沮丧。我有一个返回datatable 的查询组件。该组件我已经对其进行了测试,它具有 100% 的测试覆盖率。

该测试声称缺少第 42、145、148、151 行的覆盖范围(请参阅下面的组件以查看有关这些行的注释)。

如果您一直查看它声称覆盖某些操作处理程序的组件的末尾。

但现在我正在测试它的父组件:

// imports

const GetShipments = ({
  t,
  shipmentsPaginationHandler,
  toggleFiltersModalHandler,
  isFiltersModalOpened,
}) => {
  const removeFilterConst = filterKey => () => {
    removeFilterHandler(filterKey);
  };

  return (
    <>
      <TableToolbarComp
        toggleFiltersModal={toggleFiltersModalHandler} // LINE 42
        isFiltersModalOpened={isFiltersModalOpened}
        removeFilter={removeFilterConst}
      />
      <Query
        query={GET_SHIPMENTS}
        variables={{
          ...filters,
          shippedDate: filters.shippedDate,
          limit: pagination.pageSize,
          offset: (pagination.page - 1) * pagination.pageSize,
        }}
        context={{ uri: `/this?url=${softlayerAccountId}` }}
      >
        {({ loading, error, data }) => {
          let tableRowsModel;
          let itemsCount;

          if (error) {
            return (...);
          }

          if (loading) return (...);

          if (data && data.GetShipments) {
            ({ itemsCount } = data.GetShipments);

            if (data.GetShipments.shipments) {
              tableRowsModel = data.GetShipments.shipments.map(row => ({
                ...row,
                id: `${row.id}`,
                type: row.type.name : '',
                status: row.status ? row.status.name : '',
              }));
            } else {
              tableRowsModel = [];
            }

            setCSVDataHandler(data.GetShipments);
          }

          return (
            <ShipmentsTable tableRows={tableRowsModel} />
          );
        }}
      </Query>
    </>
  );
};

GetShipments.propTypes = {
  // propTypes validation
};

export default compose(
  connect(
    store => ({
      softlayerAccountId: store.global.softlayerAccountId,
      isFiltersModalOpened: store.shipments.filtersModalOpened,
    }),
    dispatch => ({
      removeFilterHandler: filterKey => {
        dispatch(removeFilter(filterKey));
      },
      toggleFiltersModalHandler: () => {
        dispatch(toggleFiltersModal()); // LINE 145
      },
    }),
  ),
  translate(),
)(GetShipments);

我创建的大多数测试似乎只是忽略了我正在做的事情。

这是我目前所拥有的:

import React from 'react';
import { MockedProvider } from 'react-apollo/test-utils';
import { mount } from 'enzyme';
import { Provider as ReduxProvider } from 'react-redux';
import GetShipments from '../../containers/GetShipments';
import createMockStore from '../../../../utils/createMockStore';

import store from '../../../../redux/store';

import mocks from '../../__fixtures__/shipments-mock';

jest.mock('react-i18next', () => ({
  // this mock makes sure any components using the translate HoC receive the t function as a prop
  translate: () => Component => {
    Component.defaultProps = { ...Component.defaultProps, t: key => key }; 
    return Component;
  },
}));

describe('Container to test: GetShipments', () => {
  let props;

  beforeEach(() => {
    props = {
      t: jest.fn(() => k => k),
      softlayerAccountId: 123,
      isFiltersModalOpened: false,
      toggleFiltersModalHandler: jest.fn(() => k => k),
      setFiltersHandler: jest.fn(() => k => k),
      removeFilterHandler: jest.fn(() => k => k),
    };
  });

  it('should render without errors', () => {
    mount(
      <MockedProvider
        mocks={mocks.filter(mock => mock.id === 'get-shipments-default')}
      >
        <ReduxProvider store={store}>
          <GetShipments
            {...props}
            store={createMockStore({
              global: {
                accountGuid: 'abcd-1234',
                softlayerAccountId: '1234',
              },
            })}
          />
        </ReduxProvider>
      </MockedProvider>,
    );
  });

  it('should render loading state initially', () => {
    const wrapper = mount(
      <MockedProvider mocks={[]} addTypename={false}>
        <ReduxProvider store={store}>
          <GetShipments {...props} />
        </ReduxProvider>
      </MockedProvider>,
    );

    expect(wrapper.find('DataTableSkeleton')).toHaveLength(1);
  });

  it('should render data', async () => {
    const wrapper = mount(
      <MockedProvider mocks={mocks} addTypename={false}>
        <ReduxProvider store={store}>
          <GetShipments store={store} {...props} />
        </ReduxProvider>
      </MockedProvider>,
    );

    await new Promise(resolve => setTimeout(resolve));
    await wrapper.update();

    console.log(wrapper.debug());
  });

  it('should NOT render any data', () => {
    mount(
      <MockedProvider mocks={[]} addTypename={false}>
        <GetShipments store={store} />
      </MockedProvider>,
    );
  });
});

那么我错过了什么?

【问题讨论】:

    标签: javascript reactjs ecmascript-6 jestjs enzyme


    【解决方案1】:

    首先,您似乎在许多测试中都缺少断言。这是有目的的吗?例如,我希望您在第一个测试用例中使用快照断言(“它应该无错误地呈现”)。唯一断言某事的测试用例是“应该呈现加载状态”。

    关于丢失的覆盖率,在没有看到完整的 Jest 测试报告的情况下,我将简单地假设您突出显示的功能从未运行,即您没有测试 dispatch(toggleFiltersModal()) 在执行时正在运行 @ 987654322@。为了达到 100% 的测试覆盖率,您需要测试这些功能。当您使用 Enzyme 时,这可能很简单:

    const wrapper = mount(
        <MockedProvider mocks={mocks} addTypename={false}>
            <ReduxProvider store={store}>
                <GetShipments store={store} {...props} />
            </ReduxProvider>
       </MockedProvider>
    );
    
    wrapper.props().toggleFiltersModalHandler();
    

    不幸的是,当您使用 HOC 时,您很可能必须 find 您的组件才能在 prop 上执行函数,如下所示:

    const wrapper = mount(
        <MockedProvider mocks={mocks} addTypename={false}>
            <ReduxProvider store={store}>
                <GetShipments store={store} {...props} />
            </ReduxProvider>
       </MockedProvider>
    );
    
    wrapper.find(GetShipments).props().toggleFiltersModalHandler();
    

    毫无疑问,您必须反复试验才能在包装器中找到该道具,但一旦找到它,只需执行它并断言该函数已使用开玩笑的间谍执行。

    【讨论】:

      猜你喜欢
      • 2020-10-05
      • 2022-07-15
      • 2018-10-03
      • 2018-10-19
      • 2017-03-12
      • 1970-01-01
      • 2019-07-22
      • 2019-12-30
      • 2019-04-07
      相关资源
      最近更新 更多