使用storybook管理React组件

栏目: IOS · Android · 发布时间: 5年前

内容简介:2018年10月storybook发布了4.0版本,在UI层支持、构建、移动端、stroy参数等多个方面进行了升级优化。本文已React的UI组件为例,演示如何新建/集成Storybook到项目中,并对UI组件进行全方位的管理,包括发布、demo文档、测试等。PS:由于babel-loader的最新版本是v8,需要babel版本是v7,所以按照官方教程直接安装babel-core(最高版本是v6)运行会失败,这里选择安装的是babel6。
Storybook is a development environment for UI components. It allows you to browse a component library, view the different states of each component, and interactively develop and test components.

使用storybook管理React组件

2018年10月storybook发布了4.0版本,在UI层支持、构建、移动端、stroy参数等多个方面进行了升级优化。本文已React的UI组件为例,演示如何新建/集成Storybook到项目中,并对UI组件进行全方位的管理,包括发布、demo文档、测试等。

1. 新建一个Storybook React项目

  • 按照官方教程使用 npx -p [@storybook](/user/storybook)/cli sb init 安装,一直会报错:
TypeError: Cannot create property 'dependencies' on boolean 'false'
  • 我采用的是手动创建的方式
    1. 首先在React项目中手动添加@storybook/react和babel依赖和运行脚本
"scripts": {
    "storybook": "start-storybook -p 9001 -c .storybook"
 }
"devDependencies": {
    "[@storybook](/user/storybook)/addon-actions": "^4.0.11",
    "[@storybook](/user/storybook)/react": "^4.0.11",
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.5"
},
"dependencies": {
    "react": "^16.6.3",
    "react-dom": "^16.6.3"
}

PS:由于babel-loader的最新版本是v8,需要babel版本是v7,所以按照官方教程直接安装babel-core(最高版本是v6)运行会失败,这里选择安装的是babel6。

  1. 添加storybook配置文件
import { configure, addDecorator } from '[@storybook](/user/storybook)/react';
function loadStories() {
  require('../stories/index.js');
  // You can require as many stories as you need.
}
configure(loadStories, module);
  1. 添加story
// /stories/index.js
import React from 'react';
import { storiesOf } from '[@storybook](/user/storybook)/react';
import { Button } from '[@storybook](/user/storybook)/react/demo';

storiesOf('Button', module)
  .addDecorator(story => <div style={{ textAlign: 'center' }}>{story()}</div>)
  .add('with text abc', () => <Button onClick={action('clicked')}>hello world!</Button>, {
    notes: { markdown: docs },
  })
  .add('with some emoji', () => (
    <Button onClick={action('clicked')}>
      <span role="img" aria-label="so cool">
        :grinning: :sunglasses: :+1: :100:
      </span>
    </Button>
  ), {
    notes: { markdown: docs },
  });
  1. 运行 npm run storybook ,这时启动一个server,并自动打开一个storybook的页面

使用storybook管理React组件

2. 使用storybook的插件功能

storybook的很多功能都是靠插件来实现的,大多数插件都需要提前注册,在页面中有一个单独的tab来对storybook进行增强。

下面介绍几款官方插件:

// /.storybook/addons.js
import '[@storybook](/user/storybook)/addon-actions/register'; // 记录事件日志
import '[@storybook](/user/storybook)/addon-notes/register'; // story笔记文档,支持markdown
import '[@storybook](/user/storybook)/addon-options/register'; // storybook页面自定义
import '[@storybook](/user/storybook)/addon-links/register'; // storybook页面跳转
import '[@storybook](/user/storybook)/addon-knobs/register'; // 组件可视化配置

@storybook/addon-info 插件比较特殊,不需要提前注册,它可以显示story的源码,并针对props提供一些文档。

3. 以一个分页组件为例

从团队的stoneUI组件库直接移植过来

  1. PaginationIconV 组件源码放入 components 目录;
  2. 编写story:
import React from 'react';
import { storiesOf } from '[@storybook](/user/storybook)/react';
import { withKnobs, number } from '[@storybook](/user/storybook)/addon-knobs';

import Pagination from '../components/Pagination';
import paginationDoc from '../components/Pagination/readme.md';

storiesOf('Stone UI', module)
  .addDecorator(story => <div style={{ marginTop: '50px' }}>{story()}</div>)
  .addDecorator(withKnobs)
  .add('Pagination', () => {
    const totalPage = number('totalPage', 100);
    const currentPage = number('currentPage', 45);
    const maxDisplayNumber = number('maxDisplayNumber', 4);

    return (<Pagination totalPage={totalPage} page={currentPage - 1} maxDisplayNumber={maxDisplayNumber} />);
  }, {
    notes: { markdown: paginationDoc },
  });
  1. 运行效果如下:

使用storybook管理React组件

4. 测试UI组件

4.1 写测试用例的原因

  • 找到bug
  • 新修改没有改变已有的接口和功能
  • 将测试用例作为文档

4.2 测试结构

使用storyshots插件来实现,其核心是使用 Jest ,原理是每次生成一份DOM结构文档(类似于html源码),可以无痛集成到组件测试中。

对于React项目,需额外安装如下npm包:

npm i -D [@storybook](/user/storybook)/addon-storyshots jest react-test-renderer

新建一个测试文件 storyshots.test.js (路径随意,以 .test.js 结尾即可)

import initStoryshots from '[@storybook](/user/storybook)/addon-storyshots';

initStoryshots({ /* configuration options */ });

在控制台运行 npm test 即可(在package.json中配置好scripts: "test": "jest" ),测试完成后会在 storyshots.test.js 生成一个 stories/index.js 对应的DOM快照。

使用storybook管理React组件

PS:下次运行Jest时,只有DOM结构与上次完全一致测试才会通过,通常会有两种方法来解决这种情况:

  1. 找到问题,修复不同;
  2. 用新的DOM结构替换旧的。

4.3 测试交互

storybook交互性测试可以使用 Enzyme 来模拟用户输入,然后使用 Mocha or Jest 来进行结果测试,storybook又一个专门的插件帮助我们集成他们: specifications

首先,需要安装如下npm包:

npm i -D enzyme enzyme-adapter-react-16 expect storybook-addon-specifications

storybook/config.js 中配置enzyme

import { configure as enzymeConfigure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

enzymeConfigure({ adapter: new Adapter() });

stories/test.js 中编写测试用例:

import React from 'react';
import { storiesOf } from '[@storybook](/user/storybook)/react';

import { specs, describe, it } from 'storybook-addon-specifications';
import { mount } from 'enzyme';
import expect from 'expect';

storiesOf('Interaction test', module)
  .add('Button test', () => {
    const story = (
      <button onClick={action('Hello World')}>
        Hello World
      </button>
    );

    specs(() => describe('Hello World', () => {
      it('Should have the Hello World label', () => {
        const output = mount(story);
        expect(output.text()).toContain('Hello World');
      });
    }));

    return story;
  });

在组件挂载后,通过断言来测试UI组件的属性,更多使用方法可以参考 specifications插件的使用

使用storybook管理React组件

4.4 测试样式

样式测试这里采用 PuppeteerJest 来实现,其原理是利用 Puppeteer 的无头的chrome浏览器和storybook的url绑定组件特点,来渲染不同的UI组件,再进行图片快照的对比。

首先安装几个npm包:(puppeteer默认会下载Chromium,比较慢要耐心等候)

npm install --save-dev jest puppeteer jest-puppeteer jest-image-snapshot start-server-and-test

然后添加一些文件到 integration 目录下:

// integration/jest.config.js
module.exports = {
  preset: 'jest-puppeteer',
  testRegex: './*\\.test\\.js$',
  setupTestFrameworkScriptFile: './setupTests.js',
};

// integration/setupTests.js
import { toMatchImageSnapshot } from 'jest-image-snapshot';
expect.extend({ toMatchImageSnapshot });

// integration/Button.test.js
describe('Button', () => {
  it('visually looks correct', async () => {
    // APIs from jest-puppeteer
    await page.goto('http://localhost:9009/iframe.html?selectedKind=Button&selectedStory=with+text');
    const image = await page.screenshot();

    // API from jest-image-snapshot
    expect(image).toMatchImageSnapshot();
  });
});

然后在package.json中添加两个scripts命令:

"jest:integration": "jest -c integration/jest.config.js",
"test:integration": "start-server-and-test storybook http-get://localhost:9009 jest:integration",

第一次运行 npm run test:integration 可以生成UI组件渲染的一次快照,再次运行会将新旧快照进行对比,只有完全一致才能测试通过。

PS:测试不通过时,运行 npm run jest:integration 将强制更新原有快照。

4.5 手动测试

再好的自动化测试,都和人的体验存在差距,所以发布之前还是需要经过人眼测试,因为storybook活文档的特点,我们可以直接运行体验UI组件,通过交互操作、 knobs 插件等来进行全面体验。

5. 包管理

使用 lerna 进行包管理和发布。

6. 参考链接

7. 写在最后

本文是作者学习storybook的一些总结,总体感觉是接入成本不算高,但是模块包版本安装可能会有一些坑,但收获是给组件的管理、文档和测试提供了一个一体化的解决方案,还是很值得的。

PS:文中所涉及的demo已放入Github仓库 storybook-react


以上所述就是小编给大家介绍的《使用storybook管理React组件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

菜鸟侦探挑战数据分析

菜鸟侦探挑战数据分析

[日] 石田基广 / 支鹏浩 / 人民邮电出版社 / 2017-1 / 42

本书以小说的形式展开,讲述了主人公俵太从大学文科专业毕业后进入征信所,从零开始学习数据分析的故事。书中以主人公就职的征信所所在的商业街为舞台,选取贴近生活的案例,将平均值、t检验、卡方检验、相关、回归分析、文本挖掘以及时间序列分析等数据分析的基础知识融入到了生动有趣的侦探故事中,讲解由浅入深、寓教于乐,没有深奥的理论和晦涩的术语,同时提供了大量实际数据,使用免费自由软件RStudio引领读者进一步......一起来看看 《菜鸟侦探挑战数据分析》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具