Skip to content

Latest commit

 

History

History
239 lines (171 loc) · 9.87 KB

cypress-react-component-test.zh.md

File metadata and controls

239 lines (171 loc) · 9.87 KB

[过时] 使用 Cypress 进行 React 组件的单元测试

此部分现已标记为过时,因为它指的是一个非常古老的 Cypress 版本(现在已完全支持组件测试)。


更新Cypress 10 发布,集成了组件测试和 E2E 测试,请查看并忽略下面报告的所有配置步骤,因为它们已经过时了!


更新Cypress 7 发布,支持全新的组件测试,快去看看吧!而且,还有其他令人兴奋的消息即将到来,感谢Storybook 6.2 发布


如今,使用 Cypress 进行 React 组件的单元测试已经成为可能,这是 使用 Cypress 和 Storybook 进行组件测试 的一个扩展章节。

前一章的目标是在React 组件测试世界中进行一些实验,这是现今一个非常重要的主题。

动机非常简单:

  • 你可能已经在你的团队中使用了 Storybook(如果没有,请考虑添加!)

  • 你可能不熟悉使用 Testing Library 进行组件测试,或者你对 JSDom 有一些偏见,或者你希望在真实浏览器中测试你的 UI 组件,而不是在模拟的 DOM 环境中进行测试。

  • 你可能已经熟悉 CypressTestCafé(如果没有,请考虑它们用于你的 UI 测试),并且你可能希望只使用一个工具进行测试。

方法也很简单:

  • 将故事的 props 暴露给测试工具,用于控制渲染的组件。

  • 从 Cypress/TestCafé 中获取它们,自动执行用户操作并断言 props 的内容。

但是也有一些注意事项

  • 性能问题:在章节中,我花费了额外的努力来最小化故事切换导致的速度下降。

  • 测试和故事的耦合性:由于 Cypress 甚至都使用了 Storybook,故事不仅要为团队共享的设计系统负责,还要为组件测试负责。

  • 回调测试变得困难:检查回调 props 的参数和调用变得困难。

我的实验中的一些问题可以通过 daedalius 的方法 缓解,但解决方案还不够理想,但是然后…

Cypress 4.5.0 已发布

在 4 月 28 日,Cypress 4.5.0 版本发布了,唯一的功能更新如下

当将 experimentalComponentTesting 配置选项设置为 true 时,Cypress 现在支持使用特定于框架的适配器执行组件测试。有关详细信息,请参见 cypress-react-unit-testcypress-vue-unit-test 仓库。

这是什么意思呢?这意味着 Cypress 现在可以直接挂载 React 组件,为 cypress-react-unit-test 带来了新的生机!在 Cypress 4.5.0 发布之前,该插件相当有限,但现在它得到了一流的支持!事实上,cypress-react-unit-test 现在非常可靠,是一个有意义的插件。

测试 VirtualList 组件:第二集

组件依然是 VirtualList,关于它的更多信息请查看上一章。我们需要同时设置 cypress-react-unit-test 和 TypeScript 转换(该组件使用 TypeScript 编写,是 Lerna monorepo 的一部分,并且使用 Webpack 进行编译)。这两个步骤都很简单,但是由于插件在其文档中有一个专门的安装部分,因此 TypeScript 编译可能不太明显,而且有许多过时或部分过时的不同方法和资源。

最简洁而有效的解决方案是André Pena 的方法,因此我只需要:

  • 添加 cypress/webpack.config.js 文件
module.exports = {
  mode: 'development',
  devtool: false,
  resolve: {
    extensions: ['.ts', '.tsx', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        exclude: [/node_modules/],
        use: [
          {
            loader: 'ts-loader',
            options: {
              // skip typechecking for speed
              transpileOnly: true,
            },
          },
        ],
      },
    ],
  },
}
  • 添加 cypress/tsconfig.json 文件
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "types": ["cypress", "cypress-wait-until"]
  }
}

请注意:

  • ../tsconfig.json 文件与 React 应用程序使用相同的文件

  • cypress-wait-until 不是必需的,但我经常使用它,它是 Cypress 最常安装的插件之一

上述与转译相关的文件,以及以下的 cypress.json 文件

{
  "experimentalComponentTesting": true,
  "componentFolder": "cypress/component"
}

以上就足够开始尝试编写 cypress/component/VirtualList.spec.tsx 测试了!在前一章中,第一个测试是标准渲染,即“当组件接收到 10000 个项时,只渲染最少数量的项”测试,就这样吧:

/// <reference types="Cypress" />
/// <reference types="cypress-wait-until" />

import React from 'react'
import { mount } from 'cypress-react-unit-test'
import '[@testing](http://twitter.com/testing)-library/cypress/add-commands'

import { VirtualList } from '../../src/atoms/VirtualList'
import { getStoryItems } from '../../stories/atoms/VirtualList/utils'

describe('VirtualList', () => {
  it('When the list receives 10000 items, then only the minimum number of them are rendered', () => {
    // Arrange
    const itemsAmount = 10000
    const itemHeight = 30
    const listHeight = 300
    const items = getStoryItems({ amount: itemsAmount })
    const visibleItemsAmount = listHeight / itemHeight

    // Act
    mount(
      <VirtualList
        items={items}
        getItemHeights={() => itemHeight}
        RenderItem={createRenderItem({ height: itemHeight })}
        listHeight={listHeight}
      />
    )

    // Assert
    const visibleItems = items.slice(0, visibleItemsAmount - 1)
    itemsShouldBeVisible(visibleItems)

    // first not-rendered item check
    cy.findByText(getItemText(items[visibleItemsAmount])).should('not.exist')
  })
})

与 Storybook 相关的章节相比:

/// <reference types="Cypress" />
/// <reference types="cypress-wait-until" />

在开始时需要这些内容,以便让 VSCode 正确利用 TypeScript 的建议和错误报告

  • 我们使用 cypress-react-unit-test 的 mount API 来挂载组件,如果你习惯于 Testing Library APIs,这并没有什么特别的新东西

没有更多,Cypress 测试与 Storybook 相关的测试一样 😊

回调测试

将所有测试从上一章迁移过来相当容易,缺失的是“选择测试”的回调测试部分。

创建一个名为 WithSelectionManagement 的包装组件,它渲染 VirtualList 并管理项的选择是相当容易的,我们可以将我们的存根传递给它并对其进行断言。

it('When the items are clicked, then they are selected', () => {
  const itemHeight = 30
  const listHeight = 300
  let testItems

  const WithSelectionManagement: React.FC<{
    testHandleSelect: (newSelectedIds: ItemId[]) => {}
  }> = (props) => {
    const { testHandleSelect } = props
    const items = getStoryItems({ amount: 10000 })

    const [selectedItems, setSelectedItems] = React.useState<(string | number)[]>([])

    const handleSelect = React.useCallback<(params: OnSelectCallbackParams<StoryItem>) => void>(
      ({ newSelectedIds }) => {
        setSelectedItems(newSelectedIds)
        testHandleSelect(newSelectedIds)
      },
      [setSelectedItems, testHandleSelect]
    )

    React.useEffect(() => {
      testItems = items
    }, [items])

    return (
      <VirtualList
        items={items}
        getItemHeights={() => itemHeight}
        listHeight={listHeight}
        RenderItem={createSelectableRenderItem({ height: itemHeight })}
        selectedItemIds={selectedItems}
        onSelect={handleSelect}
      />
    )
  }
  WithSelectionManagement.displayName = 'WithSelectionManagement'

  mount(<WithSelectionManagement testHandleSelect={cy.stub().as('handleSelect')} />)

  cy.then(() => expect(testItems).to.have.length.greaterThan(0))
  cy.wrap(testItems).then(() => {
    cy.findByText(getItemText(testItems[0])).click()
    cy.get('[@handleSelect](http://twitter.com/handleSelect)').should((stub) => {
      expect(stub).to.have.been.calledOnce
      expect(stub).to.have.been.calledWith([testItems[0].id])
    })
  })
})

请参考完整的 SinonJS(由 Cypress 包装和使用)Stub/Spy 文档,了解详细的 API。

总结

请查看此视频中的结果。现在测试只需要不到七秒,无需依赖或加载 Storybook,充分利用 Cypress 的一流支持。

接下来呢?cypress-react-unit-test 插件目前相当稳定和实用,一个全新的实验领域正向我们展开,许多中小型项目可以选择将 Cypress 作为唯一的测试工具。



NoriStedev.toMedium上进行联合发表.