StoryBook for React#3複雑な構成部品の作成(データレコーダ、ユニットテストの欠点)

30228 ワード

一言:下図のように、コードの位置に一致する状態を表示すると実行できないので不便です.

components/TaskList.tsx

import React from 'react';
import Task, { TaskProp } from './Task';
type TaskListProps = {
  tasks: TaskProp[];
  loading: string;
  onPinTask: (id: number) => void;
  onArchiveTask: (id: number) => void;
};
export default function TaskList({ tasks, loading, onPinTask, onArchiveTask }: TaskListProps) {
  const events = {
    onPinTask,
    onArchiveTask,
  };
  if (loading) {
    return <div>loading</div>;
  }
  if (tasks.length === 0) {
    return <div>아무것도 없음</div>;
  }
  return (
    <div className='list-items'>
      {tasks.map(task => {
        return <Task id={task.id} task={task} {...events} />;
      })}
    </div>
  );
}

components/TaskList.stories.js


レコーダを使用して任意のレコードを提供します.ストーリーを隠す.スタイルを提供する場合にも使用できますが、contextやredoxを使用する場合にステータスを伝える場合にも使用できます.
import React from 'react';
import TaskList from './TaskList';
import * as TaskStories from './Task.stories';
export default {
  component: TaskList,
  title: 'TaskList',
  decorators: [story => <div style={{ paddingLeft: '20px' }}>{story()}</div>],
};
const Template = args => <TaskList {...args} />;
export const Default = Template.bind({});
Default.args = {
  tasks: [
    { ...TaskStories.Default.args.task, id: 1, title: 'Task1' },
    { ...TaskStories.Default.args.task, id: 2, title: 'Task2' },
    { ...TaskStories.Default.args.task, id: 3, title: 'Task3' },
    { ...TaskStories.Default.args.task, id: 4, title: 'Task4' },
    { ...TaskStories.Default.args.task, id: 5, title: 'Task5' },
  ],
};
export const WithPinnedTasks = Template.bind({});
WithPinnedTasks.args = {
  tasks: [...Default.args.tasks.slice(0, 5), { id: 6, title: '6 pinned', state: 'TASK_PINNED' }],
};
export const Loading = Template.bind({});
Loading.args = {
  tasks: [],
  loading: true,
};
export const Empty = Template.blnd({});
Empty.args = {
  ...Loading.args,
  loading: false,
};

TaskListをより詳細に実施する場合、以下の操作を行うことができる。


TaskList.tsx

import React from 'react';
import Task, { TaskProp } from './Task';
export type TaskListProps = {
  tasks: TaskProp[];
  loading: boolean;
  onPinTask: (id: number) => void;
  onArchiveTask: (id: number) => void;
};
export default function TaskList({ tasks, loading, onPinTask, onArchiveTask }: TaskListProps) {
  const events = {
    onPinTask,
    onArchiveTask,
  };
  const LoadingRow = (
    <div className='loading-item'>
      <span className='glow-checkbox' />
      <span className='glow-text'>
        <span>Loading</span> <span>cool</span> <span>state</span>
      </span>
    </div>
  );
  if (loading) {
    return (
      <div className='list-items'>
        {LoadingRow}
        {LoadingRow}
        {LoadingRow}
        {LoadingRow}
        {LoadingRow}
        {LoadingRow}
      </div>
    );
  }
  if (tasks.length === 0) {
    return (
      <div className='list-items'>
        <div className='wrapper-message'>
          <span className='icon-check' />
          <div className='title-message'>You have no tasks</div>
          <div className='subtitle-message'>Sit back and relax</div>
        </div>
      </div>
    );
  }
  const taskInOrder = [
    ...tasks.filter(task => task.state === 'TASK_PINNED'),
    ...tasks.filter(task => task.state !== 'TASK_PINNED'),
  ];
  return (
    <div className='list-items'>
      {taskInOrder.map(task => {
        return <Task id={task.id} task={task} {...events} />;
      })}
    </div>
  );
}

Jestを使用してユニットテストを行うこともできます。


機能性の問題は良いですが、後の視覚回帰テスト(?)直訳したテストを行います.単位テストでは、更新時に追跡も困難になります.テストコードを更新し続けます.
👏 しかし,物語本でいう視覚回帰テストには,変更前後の部分が視覚的に示されているため,非常に有用である可能性がある.