React Testing Library で Material UI の TextField を取得する方法
はじめに
@testing-library/react で Material UI の TextField を取得する際、 label が設定されていても getByRole や getByLabelText で取得したときに label が正しく取得できません。

調べると inputProps を使って data-test-id を使う方法も出てきますが、テストのために data-test-id を指定するのは極力避けたく、他の方法を調査していました。
結論
-
labelを設定する - 一見不要でも
idを設定する -
getByRoleまたはgetByLabelTextで取得する- 一般的には
getByRoleが推奨されていますがtype="passwordの場合は使えません
- 一般的には
解説
Material UI の TextField コンポーネントを以下のように配置した場合
<TextField id="email" name="email" label="メールアドレス" />
実際には以下の DOM として展開されます。
<div class="MuiFormControl-root MuiTextField-root">
<label
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
data-shrink="false"
for="email"
id="email-label"
>
メールアドレス
</label>
<div class="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-formControl MuiInput-formControl">
<input
aria-invalid="false"
class="MuiInputBase-input MuiInput-input"
id="email"
name="email"
type="text"
value=""
/>
</div>
</div>
id="email" を消すと以下のようになります。
<div class="MuiFormControl-root MuiTextField-root">
<label
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated"
data-shrink="false"
>
メールアドレス
</label>
<div class="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-formControl MuiInput-formControl">
<input
aria-invalid="false"
class="MuiInputBase-input MuiInput-input"
name="email"
type="text"
value=""
/>
</div>
</div>
ここで注目したいのは <label> の for="email" という箇所です。
<label> タグには for に <input> の id を指定してあげるとその <input> に関連づけられるという仕様があります。
Material UI の TextField の場合、 id を設定すると for を指定してくれるようです。
よく見たらドキュメントの隅のほうに書いてありました。
If you are using the TextField component, you just have to provide a unique id.
TextField を使う場合、一見不要でも id をつけるのは癖にしたほうがよさそうです。
余談
@testing-library/react は最初はとっつきづらくて enzyme 使いたい〜〜となってしまいますが、慣れてくるとブラウザ上で操作するように直感的にテストが書けるなと感じてきました。
以下の記事にベストプラクティスが沢山まとめられているので、 @testing-library/react を使用している方は一読してみるとよさそうです。
Discussion