Styled components を使ったコンポーネントをテストする場合、どのスタイルが変更されたかの検知はできません。
例えば、下のような styled components で作成されたボタンを Jest の snapshot 機能 + react-testing-library でテストすることを考えてみます。
通常のボタンの状態と、props に isError
を渡すことでボタンの状態が変更されているかのテストです。
describe("button", () => { it("normal", () => { const { container } = render(<Button>ボタン</Button>); expect(container.firstChild).toMatchInlineSnapshot(` <button class="sc-bdVaJa dwVJQt" > ボタン </button> `); }); it("error", () => { const { container } = render(<Button isError={true}>ボタン</Button>); expect(container.firstChild).toMatchInlineSnapshot(` <button class="sc-bdVaJa ANkxh" > ボタン </button> `); }); });
snapshot で render された内容を見てみるとクラス名が dwVJQt
から ANkxh
に変わっています。
ここから normal
に適用されているスタイルとは違うスタイルがあたっていることがわかりますが、本当に期待しているスタイルが当たっているかまではこのテスト結果からはわかりません。
Jest Styled Components の利用
そこで、 Jest Styled Components を利用してみます
GitHub - styled-components/jest-styled-components: 🔧 💅 Jest utilities for Styled Components
さっそくテストを書き換えて結果を見ていきます。
describe("button", () => { it("normal", () => { const { container } = render(<Button>ボタン</Button>); expect(container.firstChild).toMatchInlineSnapshot(` .c0 { border: 2px solid white; } <button class="c0" > ボタン </button> `); }); it("error", () => { const { container } = render(<Button isError={true}>ボタン</Button>); expect(container.firstChild).toMatchInlineSnapshot(` .c0 { border: 2px solid tomato; } <button class="c0" > ボタン </button> `); }); });
適用されているスタイルがスナップショット内に表示されるようになりました。
他にもクラス名が c0
という文字列に置き換わっています。
これによって、クラス名の変更が差分として表出しなくなり、スタイルと HTML の差分だけに注視すれば良くなります。
導入方法
npm または yarn でプロジェクトに Jest Styled Components をインストールします。
$ npm install jest-styled-components --save-dev
テストファイル中で読み込みます。
import "jest-styled-components"
これで styled-components のスナップショットを作成した際に Jest Styled Components の利用 の項で解説したようなテスト結果を得られるようになります。
全体に Jest Styled Components を適用する
一つひとつに import して追加するのが面倒であれば jest.config.js
を使ってテスト実行前に読むこむ処理を追加します。
module.exports = { setupFilesAfterEnv: ["./jest.setup.js"], };
これでテスト実行前に setupFilesAfterEnv
で指定している ./jest.setup.js
が実行されるので、 jest.setup.jp
内で import する処理を追記しておきます。
一つひとつのテストで import しなくても Jest Styled Components を実行することができるようになります。
toHaveStyleRule
Jest Styled Components を適用すると Jest で toHaveStyleRule
という matcher が使えるようになります。
const { container } = renderer(<Button />) expect(container.firstChild).toHaveStyleRule("color", "tomato")
擬似クラス、 media query のスタイル
toHaveStyleRule
の第三引数を利用すると擬似クラスや media query の指定が可能です。
(現状は React のコンポーネントのみ可能)
const { container } = render(<Button isError={true}>ボタン</Button>); describe("button", () => { expect(container.firstChild).toHaveStyleRule("color", "tomato", { media: "(max-width:640px)", modifier: ":hover", }) })
別のコンポーネントに依存したスタイル
別の styled-component のスタイルをネストしている場合は、 modifier オプションで Styled Components の css helper を使います。
これで toHaveStyleRule
のテストが行なえます。
const Button = styled.button` color: white; ` const List = styled.div` ${Button} { margin: 1em; } ` describe("list", () => { it("リストにネストされたボタンはマージンが適用される", () => { const { container } = render(<List><Button /></List>) expect(container.firstChild).toHaveStyleRule("margin", "1em", { modifier: css`${Button}`, }) }) })