React Testing Library で React Select をどうやってテストするんだってのはFAQらしく、Stack Overflowではサードパーティの部品までテストすんなMock使えというのがベストアンサーだったりして、まあそうかもねと思いつつも、ほじくってテスト書いたのでメモ。
React Select ではドロップダウンが閉じた状態ではoption要素がDOMに存在しないので、わざわざ↓キー入力してドロップダウンを開いてからクエリをかけるようなことをやりました。
option に test id を付与
まあこんなのがあるとして。
//import Select from "react-select"; <Select options={[ { label: "aaa", value: 1 }, { label: "bbb", value: 2 }, { label: "abc", value: 3 } ]} />
準備として、option要素に data-testid
を付与しておく。
詳しくは先日書いたreact-select:インクリメンタル検索で一致部分を強調表示を参照。
//import Select, { components } from "react-select"; <Select options={[ { label: "aaa", value: 1 }, { label: "bbb", value: 2 }, { label: "abc", value: 3 } ]} components={{ Option: (p) => ( <components.Option {...p}> <span data-testid="opt">{p.children}</span> </components.Option> ) }} />
input 要素にダウンキーを入力
React Select でドロップダウンを開くためには、input要素に対して↓キーとかを入力してやる。
input要素は getByRole("textbox")
でも拾ってこれるはずかな。
ここでは label が紐づいている想定として、 getByLabelText
でとってくる形で実装。
<label htmlFor="input1">選択</label> <Select inputId="input1" options={[ { label: "aaa", value: 1 }, { label: "bbb", value: 2 }, { label: "abc", value: 3 } ]} components={{ Option: (p) => ( <components.Option {...p}> <span data-testid="opt">{p.children}</span> </components.Option> ) }} />
//import { fireEvent, screen } from "@testing-library/react"; const DOWN_ARROW = { keyCode: 40 }; const input = screen.getByLabelText("選択"); fireEvent.keyDown(input, DOWN_ARROW);
option 要素を取得
↓キーを入力してから、ドロップダウンが開くまでに一瞬の待機が必要。
イケてないが雑に setTimeout
かけるものとする。
各option要素から表示文字列を集めるときはこんな感じ。
const DOWN_ARROW = { keyCode: 40 }; const ESC = { keyCode: 27 }; const input = screen.getByLabelText("選択"); fireEvent.keyDown(input, DOWN_ARROW); //簡易的にちょっとwait await new Promise((res) => setTimeout(res, 200)); const res = screen.queryAllByTestId("opt").map((o) => o.textContent); //必要あれば閉じる fireEvent.keyDown(input, ESC);
以上
コード全体はこちら