アレについて記す

AngularでStoryshotsを動かす

Posted on January 29, 2020 at 21:00 (JST)

AngularでStoryshotsを動かすまでの方法をメモとして残す。

今回作成したコード: angular-storyshots-sample/mono-app

動作環境

OS: macOS Mojave ver. 10.14.6
Node: v12.14.0
@angular/cli: 9.0.0-rc.10
jest-preset-angular: 8.0.0
@storybook/angular: 5.3.9

StorybookとStoryshotsの概要

Storybook

UIコンポーネントを開発するのに便利なツール。
コンポーネントカタログ作成のため導入するケースも多い。

Storyshots

Jestのsnapshot testingを、Storybookで作成したファイルをもとに行うためのアドオン。
※ レンダリング結果の画像比較を行うには別途puppeteer等と連動させる仕組みが必要。本記事では取り扱わない。

Angularプロジェクトへの導入

手順概要

  1. Angularプロジェクト作成
  2. Storybookを導入
  3. Jestを導入
  4. Storyshotsを導入

1. Angularプロジェクト作成

$ ng new sample --style=scss --strict
$ cd sample

2. Storybookを導入

下記コマンド実行により必要なライブラリのインストールと設定系/サンプルファイルの追加、およびpackage.jsonへstorybook実行用のscriptが追記が行われる。

$ npx -p @storybook/cli sb init --type angular

$ npm run storybookhttp://localhost:6006/にコンポーネントカタログが表示できる。

3. Jestを導入

下記コマンドによりJestのインストール、およびKarma用設定ファイルの削除などが行われる。

$ npx ng add @briebug/jest-schematic

$ npm run testを実行するとJestでテストが実行されることが確認できます。

4. Storyshotsを導入

4-1. storyshotsアドオンをインストール。

$ npm install --save-dev @storybook/addon-storyshots

4-2. src/storyshots.test.tsファイルを追加し、下記を記述。

import initStoryshots from '@storybook/addon-storyshots';

initStoryshots();

4-3. package.jsonへjest-preset-angularのファイルを正しく参照させるための設定を追記。

  "jest": {
    ...
    "moduleNameMapper": {
      ...
      "jest-preset-angular/(.*)": "<rootDir>/node_modules/jest-preset-angular/build/$1"
    },
    ....

$ npm testでテストを実行すると通常のテストの後にStoryshotsが動き、src/__snapshots__/storyshots.test.ts.snapが生成される。

適用例

Bulma(CSS framework)を利用したComponentを作成し、Storyshotsを利用する。

まず、bulmaをインストール

$ npm install --save bulma

angular.jsonにnode_modulesディレクトリ下からcssを読み込む設定を追記(2箇所)

"styles": [
  "src/styles.scss",
  "node_modules/bulma/css/bulma.css"
],

Notificationコンポーネントをcliで追加

$ ng g component elements/notification

notification.component.tsを下記に書き換え

import {Component, EventEmitter, OnInit, Output} from '@angular/core';

@Component({
  selector: 'app-notification',
  templateUrl: './notification.component.html',
  styleUrls: ['./notification.component.scss']
})
export class NotificationComponent {

  @Output() closed = new EventEmitter();

  constructor() { }

  close() {
    this.closed.emit();
  }
}

notification.component.htmlを下記に書き換え

<div class="notification is-primary">
  <button class="delete" (click)="close()"></button>
  <ng-content></ng-content>
</div>

notification.component.spec.tsnotification.component.stories.tsにリネームし、下記に書き換え

import {action} from '@storybook/addon-actions';
import {NotificationComponent} from './notification.component';
import {storiesOf} from '@storybook/angular';

storiesOf('Notification', module)
  .add('content', () => ({
    moduleMetadata: {
      declarations: [NotificationComponent],
    },
    template: `<app-notification>Hello world!</app-notification>`,
  }))
  .add('event', () => ({
    component: NotificationComponent,
    props: {
      closed: action('Clicked!'),
    },
  }));

$ npm run storybookでカタログを立ち上げ確認。
$ npm run testでstoryshotsが動いていることを確認。
notification.component.htmlを少し変更し、再度テストを実行すると下記のように差分が表示される。

 FAIL  src/storyshots.test.ts (6.097s)
  ● Storyshots › Notification › content

    expect(received).toMatchSnapshot()

    Snapshot name: `Storyshots Notification content 1`

    - Snapshot  - 1
    + Received  + 1

    @@ -4,11 +4,11 @@
        target={[Function ViewContainerRef_]}
      >
        <ng-component>
          <app-notification>
            <div
    -         class="notification is-primary"
    +         class="notification"
            >
              <button
                class="delete"
              />
              Hello world!


遭遇したエラー

package.jsonへsetupJestを見つけるための設定(手順:4-3)を追加しないと、下記エラーが発生する。

$ npm test
 PASS  src/app/app.component.spec.ts
 FAIL  src/storyshots.test.ts
  ● Test suite failed to run

    Cannot find module 'jest-preset-angular/setupJest' from 'loader.js'


以上。


参考URL