fireEventではなくuser-eventを使う
実際のインタラクションで生じるような複数のeventを全て発火させる ref ユーザの操作自体をmockした感じ
ユーザが何らかのアクションを起こしたときに、複数のEventが生じることはよくある
例えば、「fieldに文字を入力する」という動作をするとき、生じているeventは
inputのonChangeだけではなく、
inputにfocusするだとか、
keyboardを押下するだとか、
いくつかのeventが複合的に生じている
差が生じる例
以下のようなComponentをテストする
code:ts
function InputComponent() {
return (
<div onKeyDown={e => e.preventDefault()}>
<input value={value} onChange={e => setValue(e.target.value)} />
</div>
);
}
間違えて、inputの親でkey down操作をブロックする操作を書いてしまっている
inputの内容を書き換えられないので「入力できる」というテストではfailしてほしい
fireEventで以下の様に書くとpassしてしまう
code:ts
test('fireEvent example', async () => {
render(<InputComponent />);
const input = screen.getByRole('textbox');
fireEvent.change(input, { target: { value: 'new value' } });
expect(input).toHaveValue('new value');
});
user-eventを使うとちゃんとfailする
code:ts
test('userEvent example', async () => {
const user = userEvent.setup()
render(<InputComponent />);
const input = screen.getByRole('textbox');
await user.type(input, 'new value');
expect(input).toHaveValue('new value');
});
user-eventはまだ挙動を正しく再現しきれていないケースがある
と、docsに書かれている
テストの内容を敢えて絞りたい、というケースはありそうmrsekut.icon
生じるeventが複合的すぎると、1つのtest caseの中で、複数の振る舞いをチェックすることになってしまう
多機能なInput Componentを作った際に、個々のeventに対してunit testingしたい場合など
逆に、そうでない場合は、普通にuser-event使えば良いと思う
まあ、特にE2Eの場合は、ほぼ必ずuser-eventの方が適していそう
パフォーマンス観点
これもtest caseの話と近い
明らかにuser-eventの方が処理内容が多いので、fireEventと比較すると、動作が重くなる
多量の入力を与えて個々の機能をテストしたい際に、要らん箇所のテスト処理に重くなるのは避けたい
でも、これもまあほぼ問題になることはないだろうし、問題になってから検討すれば良い話だろうmrsekut.icon
「簡潔に書ける」というの理由として微妙では?
fireEventは別にact()で包む必要はない
本題とはあまり関係ないが、差が生じる別の例
input内の内容を書き換えるときに、初期値が"default"としたときに
fireEventで以下のように書くと、
fireEvent.change(input, { target: { value: 'new value' } });
fieldの内容は"new value"になる
user-eventで以下の様に書くと
await userEvent.type(input, 'new value');
fieldの内容は"defaultnew value"になる
そうだね、って感じだけど、書き換えていく機会があるとちょいハマりしそう