component

測試小工具  StoryBook

1. StoryBook 環境建置

# React:
  npx create-react-app taskbox
  cd taskbox
    
# 加入 Storybook:
  npx -p @storybook/cli sb init

# 啟動 storybook
  npm run storybook
webpack

  "scripts": {
  // localhost:9009
    "storybook": "start-storybook -p 9009",
    "build-storybook": "build-storybook"
  },

2. 檔案設定

.storybook

src/stories

1. addon.js
引入 storybook 內建 function

2. config.js
引入 src/stories 的檔案

寫各種你想測試的元件

3. 元件驅動開發 (CDD)

 "自下而上"開始構建 UI 的過程,從元件開始到整個頁面結束。

React component 開發模式

Storybook就是用來幫助我們完整這套模式的測試工具

1.利於合作,並行開發
(工程 ←→ 工程)

2.元件內控管所有狀態,並同步更新
(設計 ←→ 工程)

3.創建組件庫(component library)

    Button

     →ButtonList

     →TextButton

4.可視化測試(Visual TDD)

     運用 component explorer 產生prototype
     ex: storybook

4. stories component

分成 stories 和 child story

如:Task.js & Task.stories.js


將每個 story 視為stories component的排列
可以根據需要為每個stories 建 child story

  • stories
    • story
    • story
    • story

linkto()

  • 連結,可連到別的stories

action()

  • 建立一個callback
    • 如按鈕單擊時觸發
    • 使我們能在在 測試 UI 中 確定按鈕單擊 是否成功.

5. story component

// @flow

import React from 'react';
import { css } from 'emotion';
import { action } from '@storybook/addon-actions';
import { linkTo } from '@storybook/addon-links';

function Modal({state}) {
  return (
    <div className={classes.wrapper}>
      <h3>{state}</h3>
      <p>Modal</p>
      <button
       onClick={state === 'NORMAL' ? linkTo('TASK') : action('clicked')}
       type="button">
       按鈕
      </button>
    </div>
  );
}

export default Modal;

storiesOf()

  • 為元件新增 顯示名稱
    • Storybook 應用程式側欄上顯示的名稱.

add()

  • 可產生一個個的story
    • 第一個參數是側邊欄顯示名稱
    • 第二個參數是一個函式
    • 可回傳帶有props的story

addDecorator()

  • 包一個 style Wrapper 在stories外

6. stories component

import React from 'react';
import { storiesOf } from '@storybook/react';

import { task, actions } from './Task.stories';

import TaskList from './TaskList';

export const defaultTasks = [
  { ...task, id: '1', title: 'Task 1' },
  { ...task, id: '2', title: 'Task 2' },
  { ...task, id: '3', title: 'Task 3' },
  { ...task, id: '4', title: 'Task 4' },
  { ...task, id: '5', title: 'Task 5' },
  { ...task, id: '6', title: 'Task 6' },
];

export const withPinnedTasks = [
  ...defaultTasks.slice(0, 5),
  { id: '6', title: 'Task 6 (pinned)', state: 'TASK_PINNED' },
];

storiesOf('TaskList', module)
  .addDecorator(story => <div style={{ padding: '3rem' }}>{story()}</div>)
  .add('default', () => <TaskList tasks={defaultTasks} {...actions} />)
  .add('withPinnedTasks', () => <TaskList tasks={withPinnedTasks} {...actions} />)
  .add('loading', () => <TaskList loading tasks={[]} {...actions} />)
  .add('empty', () => <TaskList tasks={[]} {...actions} />)

DEMO 時間!

參考資料

storybook

By parkerhiphop

storybook

  • 319