Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

手摸手,打造属于自己的 React 组件库02 — 测试篇 #4

Open
jokingzhang opened this issue Jan 30, 2020 · 0 comments
Open

Comments

@jokingzhang
Copy link
Owner

jokingzhang commented Jan 30, 2020

第二部分 - 测试篇:给组件加上单元测试

原文链接

引言

在第一部分,我们基于 create-react-app 构建了项目的基础结构。对于一个组件库来说,不仅要有简单,实用的组件,每一个组件的质量也是至关重要。而单元测试,正是提升软件质量的一种有效的手段。在本文中,不仅会在之前的项目中完成单元测试的配置,还会带着大家一起走进单元测试的世界~

board-361516_640

教程部分

本篇文章,是这个系列的第二篇 - 单元测试

2020到了,我还需要单元测试吗?

首先,告诉大家一个小秘密,就是我不太喜欢单元测试。它很费时,重构项目会变得很吃力。而且,单元测试没有一个明确的边界,有时总会觉得自己的单元测试写的不够。而且,代码也并不会因为单元测试就不会出现 BUG,即使你的测试覆盖率达到了💯%。

值得幸运的是,对于 React 应用来说,单元测试的成本正在逐步降低。

优秀的 TypeScript

首先,在 TypeScript 出现之后,我们不需要去写大部分的单元测试。

举个简单的例子,这是 TypeScript 的实现:

type Props = {
  name: string;
};

而下面的这段代码,是单元测试的版本:

import React from 'react';
import Component from './Component';
test('does not do something completely embarassing if I forgot to pass a name', () => {
  const { getByText } = render(<Component />);
  expect(getByText('Name: ')).not.toBeInTheDocument();
});

所以,TypeScript 的类型系统的出现,已经不再需要这部分的单元测试了。

ESLint 和 Prettier

Eslint 会分析代码,并根据一组规则对其进行检查。这听起来也很像测试。而 Prettier 可以根据一组规则来约束代码风格。并且,在编写代码的时候,配合编辑器就可以得到即时的反馈了。

像用户一样编写测试

上面所提到的技术,更多是从语言,代码质量,代码风格的角度来提升软件的质量,但却没有像一个用户一样来使用我们的软件。毕竟,软件怎么使用,只有开发者清楚。

除了编写文档、注释、编写 Demo。单元测试也更像是软件的一种说明书,为软件的使用提供了保障。

React 文档 中所描述的一样,本文也只是讨论:渲染组件树,在一个简化的测试环境中渲染组件树并对它们的输出做断言检查。

技术栈

  • Jest:JavaScript 测试框架。
  • @testing-library/react:将 React 组件转化成 Dom 节点来测试,而不是渲染的 React 组件的实例,可以当做是 Enzyme 的替代。
  • ts-jest:是一个 TypeScript 预处理器,它支持 Jest 的源映射,允许你使用 Jest 测试用 TypeScript 编写的项目。
  • jest-html-reporter:一个生成测试报告的库。

项目配置

因为之前使用的是 react-app-rewired 作为 Cli 工具,它会对 Jest 的版本有所限制。所以,下面安装依赖时,有些库会锁住版本。

npm i -D ts-jest@24.1.0 @types/jest jest@24.9.0 jest-html-reporter @testing-library/react @babel/preset-env @babel/preset-react

为了使用安装的这些依赖,接下来需要修改下 package.json ,增加测试,以及提交之前的校验。

...
  "scripts": {
+    "test": "jest --no-cache",
  }
...
  "lint-staged": {
    "*.{js,ts,tsx}": [
       "eslint --fix src/**/*.{ts,tsx}",
+      "jest --bail --coverage --findRelatedTests",
       "git add ."
    ],
    "*.{md,css,html,less}": [
       "prettier --write",
       "git add ."
    ]
  }

最后,还需要给 Jest 增加一个配置文件:jest.config.js

module.exports = {
  preset: 'ts-jest',
  transform: {
    '^.+\\.tsx?$': 'ts-jest',
  },
  globals: {
    'ts-jest': {
      babelConfig: {
        presets: ['@babel/preset-env', '@babel/preset-react'],
      },
    },
  },
  testEnvironment: 'jsdom',
  testMatch: [
    '<rootDir>/src/**/__tests__/**/*.{ts,tsx,js,jsx,mjs}',
    '<rootDir>/src/**/?(*.)(spec|test).{ts,tsx,js,jsx,mjs}',
  ],
  reporters: [
    'default',
    [
      './node_modules/jest-html-reporter',
      {
        pageTitle: '测试报告',
      },
    ],
  ],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  collectCoverage: true,
  collectCoverageFrom: ['app/react/**/*.{ts,tsx}', '!app/react/__tests__/api/api-test-helpers.ts'],
};

编写测试用例

这里,我需要给之前添加的 EmptyLine,增加测试用例。

empty-line/index.tsx
import './style/index.less';
import EmptyLine from './EmptyLine';

export default EmptyLine;
empty-line/EmptyLine.tsx
import React from 'react';

export interface IEmptyLineProps {
  height?: number;
}

const EmptyLine = ({ height = 20 }: IEmptyLineProps) => {
  return <div className="d-empty-line" style={{ height }} />;
};

export default EmptyLine;
empty-line/__test__/index.test.tsx
import React from 'react';
import { create, act } from 'react-test-renderer';
import EmptyLine from '../EmptyLine';

test('默认高度渲染正常', () => {
  const emptyLine = create(<EmptyLine />).toJSON();

  expect(emptyLine?.props.style).toEqual(
    expect.objectContaining({
      height: 20,
    }),
  );
});

test('自定义高度渲染正常', () => {
  let emptyLine: any;

  act(() => {
    emptyLine = create(<EmptyLine height={30} />);
  });

  expect(emptyLine.toJSON()?.props.style).toEqual(
    expect.objectContaining({
      height: 30,
    }),
  );
});

下面,就是两个 EmptyLine 常见的使用场景,已经在我们的单元测试中都覆盖到了。

需要注意的是,这里的 EmptyLine.tsx 组件中并没有引入样式,而是在同级的 index.tsx 中引入了样式。因为,这里样式在测试的时候是不支持引入的,会出问题。

运行 npm run test 就可以看到结果:

image

当我们提交代码,commit 的时候,也会在根目录生成一个测试报告:

image

结束语

到这里,我们给组件库增加了测试的功能。使我们的组件库也变得更加有保障,高大上了起来。最后,在第三章中,我们会聊聊如何打包,并上传至 NPM 的事情,敬请期待吧。

@jokingzhang jokingzhang changed the title 手摸手,打造属于自己的 React 组件库 —— 测试篇 手摸手,打造属于自己的 React 组件库02 — 测试篇 Jan 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant