더핑크퐁컴퍼니가 사내 백오피스의 테스트 코드를 `fireEvent` 에서 `userEvent` 로 옮기며 겪은 일을 정리한 글이다. BDT 와 IDT 의 차이에서 시작해, Antd 컴포넌트가 표준 HTML 요소를 쓰지 않아 생기는 문제와 그 mocking 과정의 삽질까지 담았다.
핵심 포인트- testing-library 는 BDT(행위 주도 테스트) 기반이다. 콘텐츠가 어떤 태그에 들어 있는지가 아니라 화면에 실제로 그려졌는지를 본다.
- `fireEvent.click` 은 click 이벤트만 발생시키지만, `userEvent.click` 은 element 의 tagName 을 확인한 뒤 실제 브라우저에서 함께 일어나는 이벤트까지 발생시킨다.
- 입력값 변경은 `change` 대신 `type` 을 쓴다. defaultValue 가 있으면 `fireEvent` 는 덮어쓰지만 `userEvent` 는 뒤에 덧붙이므로, 새 값만 넣으려면 `clear` 를 먼저 호출해야 한다.
- 저자는 이 동작이 더 정확하다고 본다. 유저는 input 의 값을 지운 적이 없기 때문이다.
- v14 부터 userEvent API 의 반환 타입이 Promise 로 바뀌어 비동기 테스트에서 await 를 걸 수 있게 됐다.
상세 정리- BDT 대 IDT: enzyme 같은 구현 주도 테스트는 "Hello My Test 가 div 안에 있는가" 를 보지만, testing-library 는 "Hello My Test 가 페이지에 그려졌는가" 를 본다. 유저에게는 태그 구조가 아니라 보이는지가 중요하기 때문이다.
- v14 주요 변경: `pointer` 의 `skipPointerEvents` 가 사라지고 `pointerEventsCheck: PointerEventsCheckLevel.Never` 로 대체됐으며, `upload` 의 `applyAccept` 기본값이 true 가 되고, `paste` 에 새 매개변수가 생겼으며, `setup` API 가 추가되고 `tab()` 의 `focusTrap` 옵션이 제거됐다.
- 문제 ① 클릭할 수 없는 요소: UI 라이브러리는 기능에 맞는 HTML 요소 대신 div·span 으로 모양과 기능을 흉내 내는 경우가 있다. Antd 의 select 는 `HTMLSelectElement` 가 아니라 div·span 이고, date picker 의 날짜 선택은 table 이다.
- date picker 테스트 절차는 input 클릭 → 시작 날짜 클릭 → 종료 날짜 선택 → start/end input 갱신이다. `fireEvent` 로는 mouseDown·click·change 를 다 써야 했다.
- `userEvent` 로 옮기면 mouseDown 같은 것을 신경 쓸 필요가 없어지지만, 선택한 태그가 `td` 라 "클릭할 수 있는 요소가 아니다" 는 에러가 난다.
- 해결은 CSS 속성을 바꾸는 것이 아니라 `pointerEventsCheck` 옵션을 쓰는 것이라고 짚는다.
- 문제 ② multiple select: `selectOptions` 는 select 태그에만 쓸 수 있어 Antd select 는 컴포넌트를 mocking 해야 한다. 이 API 는 누적 설계라 여러 번 호출하면 여러 개가 선택된다.
- 그런데 a 를 고르고 b 를 골랐는데 a 만 두 번 선택되는 현상이 났다. 원인을 못 찾아 mocking 코드를 화면에 그려 놓고 값이 바뀔 때마다 console 을 찍어 추적했다.
- 진짜 원인은 mocking 코드에 있었다. `value` 는 첫 번째로 선택한 옵션의 값만 주기 때문에, 다중 선택 상황에서 잘못된 값을 넘기고 있었다.
- 여기서 얻은 교훈을 "UI 라이브러리 테스트를 위해 컴포넌트를 mocking 할 때는 HTML 의 기본 특성을 잘 알아야 한다" 로 정리한다.
- 문제 ③ blur 테스트: 필수 입력 문구를 검증할 때 `fireEvent` 는 blur 를 직접 쏘면 되지만, `userEvent` 에서는 실제 구현대로 input 을 클릭한 뒤 아무 데나 다른 곳을 클릭하는 흐름으로 써야 한다.
- 마무리에서 커버리지 100%는 굳이 필요할까 싶지만 비즈니스 로직을 담당하는 부분의 테스트는 수고를 덜고 생산성을 높인다는 개인 의견을 남긴다.
왜 읽나Antd 처럼 표준 요소를 쓰지 않는 UI 라이브러리에서 testing-library 테스트를 옮기려는 개발자에게, 어디서 막히고 무엇을 mocking 해야 하는지 실제 사례로 보여준다.