storybook使用指南

概述

storybook 在应用之外,为 UI 组件提供了独立的开发、调试环境。react-transition-group 类库的测试工作即通过 storybook 实现。

storybook 支持调试 react, vue, angular, react-native 组件。storybook官网

操作指南

  1. 全局安装 @storybook/cli
  2. 项目目录安装依赖:react 项目为 @storybook/react,vue 项目为 @storybook/vue,angular 项目为 @storybook/angular。同时需要安装 babel-core。
  3. package.json 添加

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // -h 选项 指定以 127.0.0.1 作为主机
    // -p 选项 指定以 9001 作为端口号
    // -s 选项 指定 public 作为为静态文件目录
    // -c 选项 指定以 .storybook 作为配置目录
    // -o 选项 指定以 .out 作为打包文件目录
    {
    "scripts": {
    "storybook": "start-storybook -h 127.0.0.1 -p 9001 -s ./public -c .storybook",
    "build:storybook": "build-storybook -s ./public -c .storybook -o .out"
    }
    }
  4. 创建配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // .storybook/config.js
    import { configure } from '@storybook/react';

    function loadStories() {
    require('../stories/index.js');
    // You can require as many stories as you need.
    }

    configure(loadStories, module);
  5. 编写 story。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // stories/index.js
    import React from 'react';
    import { storiesOf } from '@storybook/react';
    import { action } from '@storybook/addon-actions';
    import Button from '../components/Button';// 来自于工程目录

    storiesOf('Button', module)
    .add('with text', () => (
    <Button onClick={action('clicked')}>Hello Button</Button>
    ))
    .add('with some emoji', () => (
    <Button onClick={action('clicked')}>😀 😎 👍 💯</Button>
    ));
  6. npm run storybook,将在 9001 端口启动服务,Button 按钮下有 with text, with some emoji 两个 story。

  7. npm run build:storybook,打包输出静态文件。通过 storybook-deployer 工具可以将静态文件发布到 github 上,或者通过 build-storybook 命令将文件打包到 docs 目录中,作为 github pages 的根目录。

贴示

  1. storybook 内部集成 webpack,通过 babel 编译 js,.babelrc 文件可替代 storybook 的默认配置;支持 css, json, 图片等静态文件的加载。
    自定义 webpack 配置通过在 .storybook 目录中添加 webpack.config.js 实现,如

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // 除了 babel-loader 外,默认配置中的其余加载器全部停用
    // 这种配置方式不能用于配置 babel-loader(第一个加载器), entry, output
    const path = require('path');

    module.exports = {
    module: {
    rules: [
    {
    test: /\.scss$/,
    loaders: ["style-loader", "css-loader", "sass-loader"],
    include: path.resolve(__dirname, '../')
    }
    ]
    }
    }

    // 或者
    // 这种配置方式不能用于替换 babel-loader(第一个加载器), entry, output,所有已存在的插件
    const path = require('path');

    module.exports = (storybookBaseConfig, configType, defaultConfig) => {
    storybookBaseConfig.module.rules.push({
    test: /\.scss$/,
    loaders: ["style-loader", "css-loader", "sass-loader"],
    include: path.resolve(__dirname, '../')
    });

    return storybookBaseConfig;
    };
  2. html,head 头部添加标签。

    1
    2
    3
    4
    5
    // .storybook/preview-head.html 配置文件将如下标签注入到渲染导入组件的 iframe 中,不影响 storybook 主界面
    <script src="https://use.typekit.net/xxxyyy.js"></script>
    <script>try{ Typekit.load(); } catch(e){ }</script>

    // .storybook/preview-head.html 配置文件,将影响 storybook 主界面
  3. 通过访问 http://localhost:9009/iframe.html?selectedKind=Button&selectedStory=with+text&dataId=0 可以访问 Button 下的 with text 这个 story,浏览器显示将不带左边栏。

辅助测试

Structural Testing

Structural Testing 结构测试的目的是判断页面元素是否异常,缺失或增加等。

在 storybook 中,借助 Jest’s snapshot testing 实现结构测试。针对 react,Jest 将为虚拟 DOM 拍摄快照,将其转化为 json 数据,在下一次运行时比对两张快照是否有偏差。

具体步骤为:

  1. 安装 @storybook/addon-storyshots 插件。
  2. 编写 storyshots.test.js 文件。

    1
    2
    3
    4
    import initStoryshots from '@storybook/addon-storyshots';

    // getStorybook() 函数获取所有 story
    initStoryshots({ /* configuration options */ });
  3. 执行 storyshots.test.js 脚本,可用于测试组件逻辑是否崩盘。

参考文档:ReactStorybook 的各种故事

interaction testing

关于 interaction testing 交互测试,可以通过模拟用户输入,在 Enzyme 测试框架 Jest, Mocha 实现。

在 storybook 中,交互测试可通过 storybook-addon-specifications 插件实现。

具体步骤为:

  1. 安装 storybook-addon-specifications 插件。
  2. 编写 .storybook/addons.js 配置文件。

    1
    import 'storybook-addon-specifications/register';
  3. 添加测试文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import { storiesOf } from '@kadira/storybook'
    import { specs, describe, it } from 'storybook-addon-specifications'

    import {mount} from "enzyme";
    import expect from "expect";

    const stories = storiesOf('Button', module);

    stories.add('Hello World', function () {
    const story =
    <button onClick={action('Hello World')}>
    Hello World
    </button>;

    // describe 首参必须与 story 名字相同
    specs(() => describe('Hello World', function () {
    it('Should have the Hello World label', function () {
    let output = mount(story);
    expect(output.text()).toContain('Hello World');
    });
    }));

    return story;
    });

插件

使用插件

在 storybook 中,插件分为两类,装饰器 Decorator(通过封装 react 组件实现,如 storybook-router) 或 以面板形式注入的 Native Addon(如 addon-actions)。

  1. 添加 .storybook/addons.js 配置文件用于向页面添加右下方插件面板。如:

    1
    2
    3
    import '@storybook/addon-actions/register';
    import '@storybook/addon-links/register';
    import '@storybook/addon-notes/register';
  2. 编写 stroy

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    import { storiesOf } from '@storybook/react';
    import { action } from '@storybook/addon-actions';
    import { WithNotes } from '@storybook/addon-notes';

    import Button from './Button';

    storiesOf('Button', module)
    .add('with some emoji', () => (
    <WithNotes notes={'Here we use some emoji as the Button text. Doesn&apos;t it look nice?'}>
    <Button onClick={action('clicked')}>😀 😎 👍 💯</Button>
    </WithNotes>
    ));

    // 使用装饰器 1
    import { storiesOf } from '@storybook/react';
    import { action } from '@storybook/addon-actions';

    import Button from './button';

    const styles = {
    textAlign: 'center',
    };
    const CenterDecorator = (storyFn) => (
    <div style={styles}>
    { storyFn() }
    </div>
    );

    storiesOf('Button', module)
    .addDecorator(CenterDecorator)
    .add('with text', () => (
    <Button onClick={action('clicked')}>Hello Button</Button>
    ))
    .add('with some emojies', () => (
    <Button onClick={action('clicked')}>😀 😎 👍 💯</Button>
    ));

    // 使用装饰器 2
    import { storiesOf, addDecorator } from '@storybook/react';
    import { action } from '@storybook/addon-actions';
    import { linkTo } from '@storybook/addon-links';

    import Button from './button';
    import Welcome from './welcome';

    const styles = {
    textAlign: 'center',
    };
    const CenterDecorator = (storyFn) => (
    <div style={styles}>
    { storyFn() }
    </div>
    );
    addDecorator(CenterDecorator);

    storiesOf('Welcome', module)
    .add('to Storybook', () => (
    <Welcome showApp={linkTo('Button')}/>
    ));

    storiesOf('Button', module)
    .add('with text', () => (
    <Button onClick={action('clicked')}>Hello Button</Button>
    ))
    .add('with some emojies', () => (
    <Button onClick={action('clicked')}>😀 😎 👍 💯</Button>
    ));

插件清单

  1. Storyshots: 快照测试。
  2. Specs: 交互测试。
  3. Notes: 在 story 中添加备注。
  4. Info: 用于创建 css 框架手册。
  5. Readme: 将 markdown 导入为 story。
  6. actions: 显示事件的 event 对象。
  7. Intl: 添加 locales 面板,用于切换语言。
  8. State: 添加 state 面板,展示或更新 state,重绘视图。
  9. Props Combinations: 配置可能有的props,一次性绘出多个组件作对比。
  10. Knobs: 页面上变更 props 重绘视图。
  11. Links: 通过 linkTo 函数或 LinkTo 组件链接多个 story,支持点击跳转。
  12. Story-router: 装饰器,支持 storybook 使用 react-router 等路由组件。
  13. Backgrounds: 切换背景图或背景颜色。
  14. i18n tools: 切换文字对齐方式,左对齐或右对齐。
  15. Material-UI: 添加并切换自定义主题。
  16. Host: 装饰器,在页面上以盒模式展示组件。
  17. Chapters: 在同一个 story 中以章节形式展示多个组件。
  18. Options: 调整 storybook 页面外观,切换为全屏等。
  19. Console: 将浏览器控制台 console 信息输出到 storybook log 面板。
  20. JSX preview: 展示及拷贝 JSX 代码。
  21. Versions: 添加版本号,查看各版本的变化。
  22. Apollo: 添加 Apollo client,模拟 GraphQL 查询。
  23. Screenshot: 保存网页截图。
  24. Styles: storybook 预览界面添加自定义样式。
  25. Figma: 添加 Figma 设计面板。