Material-UIのレンダリングを確認するテストコードを書いてみた

　この記事では、私がはじめてreactのテストコードを書いた時に、詰まってしまった問題と、それを解決するためにとった対策について紹介しています。
　
###詰まってしまった問題
　react-testing-libraryの`.getByRole()`メソッドを使ってtype="password"の要素を取得しようとしたときに、テストコードのある部分でエラーになってしまいました。

###解決するためにとった対策

 単純ですが、`.getByRole()`以外のメソッドを使用することで、対象の要素を取得することができました。　

## この記事で前提としている環境

この記事は以下の環境を前提に書かれています。

    （１）material-uiをインストールしている。
    （２）react-testing-library　と Jest をインストールしている
    　　　※(2)は、npx create-react-app を実行するとデフォルトでインストールされます。
    （３）TypeScriptでコードが書かれている


## とりあえずテストコードを書いてみた

　ログイン画面を作ろうとして、以下のとおり、Material-UIを活用して、メールアドレスとパスワードの入力するコンポーネントを作りました。


```tsx:Auth.tsx

const Auth: React.FC = () => {
  const classes = useStyles();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

return (
    <>
      <FormControl className={classes.textField} variant="outlined">
        <InputLabel htmlFor="email">メールアドレス</InputLabel>
        <OutlinedInput
          className={classes.textField}
          value={email}
          onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
            setEmail(e.target.value);
          }}
          labelWidth={100}
        />
      </FormControl>
      <FormControl className={classes.textField} variant="outlined">
        <InputLabel htmlFor="password">パスワード</InputLabel>
        <OutlinedInput
          className={classes.textField}
          type="password"
          value={password}
          onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
            setPassword(e.target.value);
          }}
          labelWidth={80}
        />
      </FormControl>
    </>
  );

```
 ※解説に必要な箇所に絞って、ものすごく簡略化して書いています。

このコンポーネントに対し、以下のとおりテストコードを書きました。

```tsx:Auth.test.tsx
import React from "react";
import { render, screen } from "@testing-library/react";
import Auth from "./Auth";

describe("Rendering", () => {
  it("Should render the elements correctly", () => {
    render(<Auth />);
    expect(screen.getAllByRole("textbox")[0]).toBeTruthy();
    expect(screen.getByRole("textbox"))[1].toBeTruthy();
  });
});
```

　すると、以下の画像のように、type="password"のinput要素を取得しようとした際にエラーが発生してしまいました。

![スクリーンショット 2021-03-24 0.46.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589104/aa920f1d-cd79-9b7f-3e87-b91173bedd39.png)

## .getByRole()では、type= "password"の要素を取得することができない

以下のサイトで`.getByRole`で選択できるロールの一覧を確認してみたところ、.getByRole()では、type= "password"の要素を取得することができないことがわかりました。　
　https://github.com/A11yance/aria-query

## .getByTestIdを試してみる
 
　React-Testing-Libraryを使って、コンポーネントの要素がきちんとレンダリングされているか
確認するためには、さまざまな方法がありますが、今回はgetByTestIdを使用する方法を試してみました。

###① レンダリングの確認対象とする要素に`data-testid=""`というプロパティをつける
　※`id=""`という形ではない点に注意です!

```tsx:Auth.tsx

const Auth: React.FC = () => {
  const classes = useStyles();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

return (
    <>
      <FormControl className={classes.textField} variant="outlined">
        <InputLabel htmlFor="email">メールアドレス</InputLabel>
        <OutlinedInput
          data-testid="email"
          className={classes.textField}
          value={email}
          onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
            setEmail(e.target.value);
          }}
          labelWidth={100}
        />
      </FormControl>
      <FormControl className={classes.textField} variant="outlined">
        <InputLabel htmlFor="password">パスワード</InputLabel>
        <OutlinedInput
          data-testid="password"
          className={classes.textField}
          type="password"
          value={password}
          onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
            setPassword(e.target.value);
          }}
          labelWidth={80}
        />
      </FormControl>
    </>
  );

```

### ② `.getByTestId("")`を要素の選択条件としてテストコードを書く

```tsx:Auth.test.tsx
import React from "react";
import { render, screen } from "@testing-library/react";
import Auth from "./Auth";

describe("Rendering", () => {
  it("Should render the elements correctly", () => {
    render(<Auth />);
     expect(screen.getByTestId("email")).toBeTruthy();
     expect(screen.getByTestId("password")).toBeTruthy();
  });
});
```

  みたいな感じで。
  
他にもgetByRoleや getAllByrole、getByLabelTextなど、要素を選択するさまざまな条件があるので、いろいろ試してみると勉強になります。

##その他

　Auth.tsxやFeed.tsxみたいに、tsxファイルで作ったコンポーネントのテストコードは
必ずtsxファイルで書かないと、テストを実行したときエラーになるので、注意です!
自分はこのエラーで３日間ハマってしまいました ^^;


参考

*Udemyの教材　Reactソフトウェアテスト(Hooks+ReduxToolKit時代のモダンテスト手法)*
https://www.udemy.com/course/reacthooksreduxtoolkit/

*getByクエリの概要*
https://testing-library.com/docs/queries/about

*getByRole で選択できるロール一覧*
　https://github.com/A11yance/aria-query