🔖

React Testing Libraryにチャレンジします 1(現在進行形)

2021/03/27に公開

こんにちは。

最近YoutubeにてAmplifyの動画をあげているのでぜひ見てください。

https://www.youtube.com/watch?v=hRuZi-78aoM&t=92s

して、

今回はこちらの動画を見ていて思ったわけです。

https://www.youtube.com/watch?v=DX73uXs3xGU

テストって大事だなと。

そんなこんなでReact Testing Libraryにチャレンジした記事になります。

感想文を書いているのでマサカリは歓迎します。

こういうところが間違っているなどの指摘の場合は根拠も添えていただけますとわかりやすいですが、

根拠はあなたが探してください、ただ私は間違っていることをしてきしたまでです。は精神的に疲れるのでやめてくださいね。

対象

駆け出しエンジニア

中級者や上級者はブラウザバックです。

Render.test

まずはReactがレンダリングされた時にどの要素がレンダリングされるのかをチェックすることができるようです

一つずつ見ていくと

例えば次のようなjsのファイルがあったとします

import React from "react";

const Render = () => {
  return (
    <div>
      <h1>React Testing Library Lesson</h1>
      <input type="text" />
      <button>ClickA</button>
      <button>ClickB</button>
      <p>Matsumoto Kazumasa</p>
      <span data-testid="kazumasa">@React</span>
    </div>
  );
};

export default Render;

そして次に対応するテストはこちらです。

import React from "react";
import { render, screen } from "@testing-library/react";
import Render from "./Render";

describe("Rendering", () => {
  it("Matsumoto Kazumasa Should render all the elements correctly", () => {
    render(<Render />);
    expect(screen.getByRole("heading")).toBeTruthy();
    expect(screen.getByRole("textbox")).toBeTruthy();
    expect(screen.getAllByRole("button")[0]).toBeTruthy();
    expect(screen.getAllByRole("button")[1]).toBeTruthy();
    expect(screen.getByText("Matsumoto Kazumasa")).toBeTruthy();
    expect(screen.queryByText("Matsumoto Kiyokazu")).toBeNull();
    expect(screen.getByTestId("kazumasa")).toBeTruthy();
  });
});

describeとかitとかexpectとか何?

まずdescribeですが
これはテストの一つの区切りと認識しています。
何をテストするのか?みたいな認識でいいのかなと思います。
例えば美味しいお寿司を食べたいとか

次にitですが
これはその区切りを達成するためのタスクを分けていくのかと思います
店を決めて
ルートを調べて
車で移動して
みたいなお寿司を食べるために必要なタスクをある程度の大きさで区切る形になるかと思います。

で最後にexpectで
お店を決めるサイトが動くか?
検索結果は正常に出るか?
ガソリンは入っているか?
GoogleMapは正確か?
みたいなitのテストを達成すべき内容が記載されるといった認識です

階層化することで管理しやすくなると思っているのか?
それとも長い歴史で階層化をずっとしてきた人類は階層管理するように脳が進化しているのか?
それは不明ですが、階層管理をしたいんだなぁとぐらいで思っておきます!!

renderとgetByRoleとtoBeTruthy

describe("Rendering", () => {
  it("Matsumoto Kazumasa Should render all the elements correctly", () => {
    render(<Render />);
    expect(screen.getByRole("heading")).toBeTruthy();
    expect(screen.getByRole("textbox")).toBeTruthy();
    expect(screen.getAllByRole("button")[0]).toBeTruthy();
    expect(screen.getAllByRole("button")[1]).toBeTruthy();
    expect(screen.getByText("Matsumoto Kazumasa")).toBeTruthy();
    expect(screen.queryByText("Matsumoto Kiyokazu")).toBeNull();
    expect(screen.getByTestId("kazumasa")).toBeTruthy();
  });
});

とあります。
この

render(<Render />);

はテスティングライブラリがインポートしたファイルを描画してくれるらしいです(ローカル環境で)

つまり見えているものと同じものが仮想的に描画されていると考えるべきなのか、人間が見えているものと同じバイナリコードが作成されているのかは不明ですが、

おそらくおんなじものがあるということだけわかっていればいいのかなと思いました

次にscreenとありますが、これはレンダリングされたスクリーン画面と思っています。

その画面の中のgetByRole("heading")がタグの役割をしているみたいです。

expect(screen.getByRole("heading")).toBeTruthy();

で先程のコードには

<h1>React Testing Library Lesson</h1>

とあったので
あ〜headingタグがあるなという認識です。

以下は対応表らしいです。

これを見ながら

ボタンとかあるな

inputタグあるな

とか確認できるみたいです。

https://github.com/A11yance/aria-query

toBeTruthy()

はありますと聞かれている部分をコードした認識です。

以下の訳し方があっているかは不明ですが、現在はこのように認識しています。

expect(screen.getByRole("heading")).toBeTruthy();
~か?レンダーで描画したスクリーンの中にheading要素のタグは。あります

でその通りの場合はPASSとなってそれ以外の場合はFailedになる感じですね。

getAllByRole

expect(screen.getAllByRole("button")[0]).toBeTruthy();

これはレンダリングされたスクリーンの中から次のタグ要素を全て探すで〜〜

みたいな認識でいます。

先ほどはボタンを二つほど作ったので2個あるよみたいな形になるのかなと認識しています。

<button>ClickA</button>
<button>ClickB</button>
expect(screen.getAllByRole("button")[0]).toBeTruthy();
expect(screen.getAllByRole("button")[1]).toBeTruthy();

getByText

これはこのテキストを探します

expect(screen.getByText("Matsumoto Kazumasa")).toBeTruthy();

今までと違うのはタグではなく
タグで囲まれた中のテキストを探すということです。

これはどういう時に使うのかな?とイメージしたわけです。

例えばものすごく言葉の表現にこだわるアプリケーションを開発したとしましょう。

そうすると
「正しい日本語を使用しましょう」
「適切な日本語を使用しているか確認してください」

みたいな要件があるわけです。

そういった要件に対応できるのがこのgetByTextになるわけです。

もっと具体的には

法律の引用が間違っていないかとかテストできます。
目視面倒ですよね?

そういった時にいいのかな?とは思います。(プライバシーポリシーとか)

toBeNull

queryByTextはレンダリングした中から探すらしいです。
getとqueryの違いがよくわかりませんが、queryにしたほうがいいみたいです。

expect(screen.queryByText("Matsumoto Kiyokazu")).toBeNull();

toBeNullはありませんという形になります。

用途としては例えば
・差別的な表現を含んでいないか?
・暴力的な表現が含まれていないか?

をチェックすることができるのかな?と思います。

expect(screen.queryByText("Matsumoto Kiyokazu")).toBeNull();

このコードを書いてMatsumoto Kiyokazuの部分を変更するだけでそのコードが含まれていないかをチェックできるのであれば結構コストも安く済みますよね。と思いました。(現在のアプリ開発でそこまで気にしている人はあんまり見たことないですが僕の見ている世界が狭いだけなので、他のところではこういったテストは重要視されているのでしょう。目指せSDGs)

getByTestId

タグの中にdata-testidを埋め込むことができるそうです。

<span data-testid="kazumasa">@React</span>
expect(screen.getByTestId("kazumasa")).toBeTruthy();

こうすることによってこの埋め込んだタグが入っているかどうかのテストができるみたいです。

ただtestidとタグを紐ずけるリストを作成する必要がありますが、
どのタグにどういったことを入れるのかテストコードにすることで共有しやすいのかなとは思いました。

... 続く

Discussion