hacomono TECH BLOG

フィットネスクラブ・スクールなど施設・店舗のための会員管理・予約・決済システム「hacomono」 開発チームの技術ブログ

Storybook の interaction test で動作する jest にカスタムマッチャーを追加する

こんにちは。フロントエンドのテックリードのみゅーとんです。

Storybook の公式で紹介されていますが (リンク)、Storybook の play 関数を使用して、 コンポーネントのテストを視覚的に行うことができます。

テストコードは基本的にフロントエンドのテストフレームワークの Jest を用いますが、 Storybook 上で動かす前提の環境では、 Jest の設定を Storybook 側が隠蔽しているため、 かゆいところに手が届かないのが現状かなと思います。

今回は、 Storybook の Interaction Test 上で動作する Jest にカスタムマッチャーを追加する方法を紹介します。

解説しないこと

  • Storybook について
  • Jest について
  • カスタムマッチャーについて、及び実装方法

TL;DR

3行で。

  • ブラウザで確認するには expect.extend.storybook/preview.js(ts) に記載すればよい
  • Storybook Test Runner を使う場合でも対応できる
  • Jest のプラグインライブラリをそのまま導入することはできないので注意が必要

対応方法

カスタムマッチャーを定義する方法は、Jest単体の場合と同様に、 expect.extend を使用するだけで簡単に実装できます。 Jest 単体の場合との相違点として、 @storybook/jest を import して expect を取得する必要があります。

ブラウザで確認する場合は、 .storybook/preview.js(ts) に以下を追加すればOKです。

// .storybook/preview.ts
import { expect } from '@storybook/jest'

expect.extend({
  isVisible(received: HTMLElement): jest.CustomMatcherResult {
        // ここに内容を記載 
  }
})

Storybook Test Runner を使用する場合

上記の対応をすることで、 Storybook Test Runner を実行した際にも、同様にカスタムマッチャーが登録されます。

TypeScript で Type Safe にする方法

TypeScriptを使用している場合、追加で型定義を行うことで、テストの実装を Type Safeにすることができます。この記述方法は Jest 本来のカスタムマッチャーを追加する際と同じです。

declare global {
  namespace jest {
    interface Matcher<R> {
      isVisible(): R
    }
  }
}

Jest プラグインを導入したい場合

本来 Jest では、 expect 等のオブジェクトは global に存在しており、プラグインはそれを前提としているため、 Jest プラグインをそのまま導入する方法は現在のところありません。

プラグインを導入する場合は、プラグインがエクスポートするマッチャーを直接インポートして、expect.extend で登録する必要があります。

以下は、 @testing-library/jest-dom をインポートする場合の例です。

import { expect } from '@storybook/jest'
import * as matchers from '@testing-library/jest-dom/dist/matchers'

expect.extend(omit(matchers, ['__esModule']))

まとめ

@testing-library/jest-dom は、 isVisible 等の DOM に関するテスト向けのカスタムマッチャーが多く追加されるため、どうしても使いたかったことが、本記事の背景としてありました。

なんとかして導入できたことで、今後もよりいっそうフロントエンドのテストの実装も充実していけることでしょう。