内容简介: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.
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'
- 我采用的是手动创建的方式
- 首先在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。
- 添加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);
- 添加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 }, });
- 运行
npm run storybook
,这时启动一个server,并自动打开一个storybook的页面
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组件库直接移植过来
- 将 Pagination 、 IconV 组件源码放入 components 目录;
- 编写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 }, });
- 运行效果如下:
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快照。
PS:下次运行Jest时,只有DOM结构与上次完全一致测试才会通过,通常会有两种方法来解决这种情况:
- 找到问题,修复不同;
- 用新的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插件的使用 。
4.4 测试样式
样式测试这里采用 Puppeteer 和 Jest 来实现,其原理是利用 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组件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Container容器组件的使用
- Khala路由组件介绍与使用
- react-组件类型及使用场景
- 使用Docker运行整套项目组件
- 使用storybook搭建私有组件库
- 使用 utterances 作为博客评论组件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。