スタイルテスト

jest-styled-componentsモジュールを使うことで「このコンポーネントはcolororangeで持ってるはず」をテストできます。

使うにはスナップショットの時などと同じくjest-styled-componentsをただインポートすれば、toHaveStyleRuleというマッチャーが使えるようになります。

ここでは@testing-library/reactと共に使い方を見ていきます。

使い方

toHaveStyleRulesは styled-components のルートとなる要素に対して使用するマッチャーです。

基本

@testing-library/reactを使っているので軽く説明すると、以下のコードは`、

  1. queryByRoleによって<button>要素を取得
  2. その要素に対してマッチャー使用

をしています。

import React from "react";
import styled from "styled-components";
import { render } from "@testing-library/react";
import "jest-styled-components";

const Button = styled.button`
  color: orange;
`;

test("the color of the component is orange", () => {
  const renderResult = render(<Button />);

  expect(
    renderResult.queryByRole("button")
  ).toHaveStyleRule("color", "orange");
});

<button>要素に対しての#toHaveStyleRule("color", "orange")によって、この要素がcolor: orangeというスタイルを持っている事がテストできます。そしてこのテストはパスします。

またもし、色の具体地は重要ではなくcolorを持っていることが重要というような場合、Jest のexpectオブジェクトのexpect.anyなどは使えます。 例えば、以下のようにcolorに何かしらの色値が入ってることをテストできます。

expect(renderResult.queryByRole("button")).toHaveStyleRule(
  "color",
  expect.any(String)
);

スコープ使用なコンポーネントでテスト

スコープを使用して1つのstyled-componentsで複数の要素に対してスタイル付けする事があります。上記のコードをスコープ使用な形に書き換えました。
こちらはスタイルをbutton { }というネスト構造で書いてます。

import React from "react";
import styled from "styled-components";
import { render } from "@testing-library/react";
import "jest-styled-components";

const Button = styled(({ className }) => {
  return <button className={className} />;
})`
  button {
    color: orange;
  }
`;

test("the color of the component is orange", () => {
  const renderResult = render(<Button />);

  expect(
    renderResult.queryByRole("button")
  ).toHaveStyleRule("color", "orange", {
    modifier: "button"
  });
});

この場合は3つ目の引数にmodifierを持ったオブジェクトを渡します。ここへセレクタを渡すことで、深いネストのセレクタの要素のスタイルでも問題なくテストできます。

メディアクエリ持ちのテスト

レスポンシブなスタイルにも対応してます。下記はスマホではcolor: blue、PC ではcolor: orangeであることをテストしてます。

import React from "react";
import styled from "styled-components";
import { render } from "@testing-library/react";
import "jest-styled-components";

const Button = styled(({ className }) => {
  return <button className={className} />;
})`
  @media (max-width: 767px) {
    button {
      color: blue;
    }
  }

  @media (min-width: 768px) {
    button {
      color: orange;
    }
  }
`;

test("the color of the component is orange", () => {
  const renderResult = render(<Button />);
  const button = renderResult.queryByRole("button");

  expect(button).toHaveStyleRule("color", "blue", {
    media: "(max-width: 767px)",
    modifier: "button"
  });

  expect(button).toHaveStyleRule("color", "orange", {
    media: "(min-width: 768px)",
    modifier: "button"
  });
});

3つ目の引数のオブジェクトにmediaというプロパティを増やし、値を確認したいメディアクエリと同じ値にするだけです。

複雑なコンポーネントでテスト

ここでいう複雑なというのは、ネストしたセレクタにstyled-componentsを使ってるようなケースを指してます。例えば、

const Span = styled.span``;

const Button = styled.button`
  ${Span} {
    color: orange;
  }
`;

のようなケースです。全体像は以下です。

import React from "react";
import styled, { css } from "styled-components";
import { render } from "@testing-library/react";
import "jest-styled-components";

const Span = styled.span``;

const Button = styled(({ className }) => {
  return (
    <button className={className}>
      <Span />
    </button>
  );
})`
  ${Span} {
    color: orange;
  }
`;

test("the color of the component is orange", () => {
  const renderResult = render(<Button />);
  const button = renderResult.queryByRole("button");

  expect(button).toHaveStyleRule("color", "orange", {
    modifier: css`
      ${Span}
    `
  });
});

このようなケースもスコープ使用なコンポーネントのルート要素からmodifierを通してテストできます。その場合はstyled-componentsが提供するcssTagged template を用いてセレクタを書きます。

リポジトリ

上記の内容はこのリポジトリをローカルにgit cloneし、yarn && yarn testと叩くことで実際にテストを走らせれます。