【问题标题】:How can I test if a prop is passed to child?如何测试道具是否传递给孩子?
【发布时间】:2021-03-04 10:38:27
【问题描述】:

我的组件看起来像这样:(它具有更多的功能和列,但我没有包含这些以使示例更简单)

const WeatherReport: FunctionComponent<Props> = ({ cityWeatherCollection, loading, rerender }) => {
  /* some use effects skipped */
  /* some event handlers skipped */

  const columns = React.useMemo(() => [
    {
      header: 'City',
      cell: ({ name, title }: EnhancedCityWeather) => <Link to={`/${name}`} className="city">{title}</Link>
    },
    {
      header: 'Temp',
      cell: ({ temperature }: EnhancedCityWeather) => (
        <div className="temperature">
          <span className="celcius">{`${temperature}°C`}</span>
          <span className="fahrenheit">{` (~${Math.round(temperature * (9 / 5)) + 32}°F)`}</span>
        </div>
      )
    },
    {
      header: '',
      cell: ({ isFavorite } : EnhancedCityWeather) => isFavorite && (
        <HeartIcon
          fill="#6d3fdf"
          height={20}
          width={20}
        />
      ),
    },
  ], []);

  return (
    <Table columns={columns} items={sortedItems} loading={loading} />
  );
};

现在,我写了一些这样的测试:

jest.mock('../../../components/Table', () => ({
  __esModule: true,
  default: jest.fn(() => <div data-testid="Table" />),
}));

let cityWeatherCollection: EnhancedCityWeather[];
let loading: boolean;
let rerender: () => {};

beforeEach(() => {
  cityWeatherCollection = [/*...some objects...*/];

  loading = true;
  rerender = jest.fn();

  render(
    <BrowserRouter>
      <WeatherReport
        cityWeatherCollection={cityWeatherCollection}
        loading={loading}
        rerender={rerender}
      />
    </BrowserRouter>
  );
});

it('renders a Table', () => {
  expect(screen.queryByTestId('Table')).toBeInTheDocument();
});

it('passes loading prop to Table', () => {
  expect(Table).toHaveBeenCalledWith(
    expect.objectContaining({ loading }),
    expect.anything(),
  );
});

it('passes items prop to Table after sorting by isFavorite and then alphabetically', () => {
  expect(Table).toHaveBeenCalledWith(
    expect.objectContaining({
      items: cityWeatherCollection.sort((item1, item2) => (
        +item2.isFavorite - +item1.isFavorite
        || item1.name.localeCompare(item2.name)
      )),
    }),
    expect.anything(),
  );
});

如果您检查我的组件,它有一个名为列的变量。我正在将该变量分配给 Table 组件。

我认为,我应该测试列是否作为道具传递给 Table 组件。我想对了吗?如果是这样,您能告诉我如何为此编写测试用例吗?

另外,如果您能建议我如何测试在 columns 属性中声明的每个单元格,这将很有帮助。

【问题讨论】:

标签: reactjs typescript jestjs react-testing-library


【解决方案1】:

您可以使用props() 方法,执行如下操作:

 expect(Table.props().propYouWantToCheck).toBeFalsy();

只要做你的 component.props() 然后你想要的道具,你可以用它做任何断言。

【讨论】:

  • 感谢您尝试回答我的问题。但是如果你检查测试文件的第一行,你可以看到 Table 实际上没有渲染。它被嘲笑。在这种情况下,我会收到道具吗?
  • 我不是百分百肯定,但我认为您可以将这一行更改为: default: jest.fn((props) =>
    ),仍然可以验证它。但由于您正在尝试验证表格呈现本身,您可以模拟数据或传递给表格的获取请求,而不是模拟表格。
  • 我的测试结构不需要我渲染表格。表格组件已经过很好的测试并且工作正常。这就是我嘲笑桌子的原因。我将尝试向模拟版本添加道具并检查它是否有 4 列,因为我的实际组件正在传递 4 列。你能告诉我,我还要测试什么?基本上,我正在学习如何测试组件,所以我问了一些愚蠢的问题。如果您能告诉我,这也会有所帮助:如何测试列的单元格属性?
  • @OtacílioMaia 你可能指的是different testing framework
【解决方案2】:

not recommended 使用 React 测试库测试实现细节,例如组件道具。相反,您应该在屏幕内容上进行断言。


推荐

expect(await screen.findByText('some city')).toBeInTheDocument();
expect(screen.queryByText('filtered out city')).not.toBeInTheDocument();

不推荐

如果你还是想测试 props,你可以试试下面的示例代码。 Source

import Table from './Table'
jest.mock('./Table', () => jest.fn(() => null))

// ... in your test
expect(Table).toHaveBeenCalledWith(props, context)

您可能主要在以下两种情况下考虑这种方法。

您已经尝试了推荐的方法,但您注意到组件是:

  1. 使用遗留代码,因此测试非常困难。重构组件也会花费太长时间或太冒险。
  2. 非常慢,并且会大大增加测试时间。该组件也已经在其他地方进行了测试。

看看一个非常相似的问题here

【讨论】:

  • 感谢您再次帮助我。我对此进行了一些研究,我认为 Kent C. Dodds 给出了一些令人困惑的陈述。他说:“像真正的用户在测试它们一样测试你的组件”。所以,总是希望屏幕上出现一些文本或类似内容。但是您提供的代码也来自他。他在那里测试组件的道具(这不是用户将测试的)。他在代码中添加了一条语句:“我的模拟通常类似于给出的代码”。
  • 另外,考虑一个场景,其中所有常见组件都经过了很好的测试。现在我正在编写一些使用这些通用组件的组件。内部使用的每个组件都应按其应有的方式运行,这是我的组件的责任吗?我相信没有。因为这些组件都经过了很好的测试。我认为,我的组件唯一应该担心的是:编排这些不同的组件以按预期协同工作。那我应该测试什么?作为开发人员的功能还是 ui 部分(已经过测试)?
  • 我很难做出这样的决定。如果你能帮我解决这些问题,那我就完成了!谢谢。
  • Kent C. Dodds is giving some confusing statements 你应该阅读整个推特线程,他明确表示他不推荐给定的代码,但他还是提供了它来提供帮助。 Is it my component's responsibility that each component used inside it should function as how it should? 不,但你也不需要模拟它们,除非它们是非常重的组件。
  • The only thing my component should be worried about is: orchestrating > 试试看,添加一些道具测试。您会很快注意到,当您必须更改实现细节时,您的测试变得更难维护。当你达到这一点时,决定你喜欢什么......在我做出切换之前,我测试了组件道具 2 年。 Then what should I test for? > 想想你的拉取请求添加了什么以及如何在测试中验证它。
猜你喜欢
  • 2020-08-08
  • 1970-01-01
  • 1970-01-01
  • 2018-04-09
  • 2016-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多