Jest와 React Testing library 연습하기
0. Create React App 의 내장 테스팅 기능
- "@testing-library/jest-dom" : jest의 matcher 사용 가능케 해줌
- "@testing-library/react" (
React Testing Library
) : ReactDom 을 기반으로 render, screen 등의 함수로 React 테스팅을 지원 - "@testing-library/user-event" : input, click 등 유저 입력 기능을 지원
- jest와 유사한 test runner, jest-dom 등
- react scripts 덕분에 npm run test 실행시 watch 모드가 적용됨
1. 테스트 작성 프로세스
- src/tests 폴더 내에 작성
- 컴포넌트명.test.jsx(tsx) 형태로
- ex) input element가 화면에 잘 그려지는지?
2. Query
element를 찾기 위한 함수 (rtl 에서 제공)
- screen.getByRole()
- textbox 탐색할 때 2번째 인수로 { name: /레이블명/i } 이렇게 하여
레이블
탐색 가능 - id 또는 name 어트리뷰트로 찾는 것이 아님!
- textbox 탐색할 때 2번째 인수로 { name: /레이블명/i } 이렇게 하여
- screen.findAllByDisplayValue()
- 등등
1가지 이상의 결과를 받을 때는 All 키워드를 사용해야 한다 (아니면 에러 발생)
- query와 매칭되는 DOM node를 반환
- 결과가 없거나 1가지 이상의 결과가 있다면 에러를 반환
- 여러개의 결과를 받으려면 getAllBy... 를 사용
- getBy와 똑같은데 query 결과가 없으면 null 반환
- 매칭 결과가 있으면 resolve
- (기본값 1000ms) 이후에도 없으면 reject 되는 promise를 반환
- 따라서 프로미스를 받기 위해 test 콜백함수에 async/await를 써준다
ByRole, ByText ... 어떤 기준에 따라 찾을 것인지
- 매개변수로
문자열
또는정규식
을 받는다
- aria-role 을 기반으로 찾음
- label text를 기반으로 찾음
- placeholder text를 기반으로 찾음
- element가 보유한 텍스트로 찾음
- element의 현재값으로 찾음
- alt 어트리뷰트로 찾음
- title 어트리뷰트로 찾음
- data-testid 어트리뷰트로 찾음
3. Matcher
무엇을 테스트(비교)할지 정해주는 함수
- expect(element).toBeInTheDocument() : 화면에 element가 있는지
- expect(element).toHaveClass() : className 을 갖고 있는지
- expect(value).toHaveLength(숫자) : 배열이 특정 길이인지
- expect(value).toEqual(value) : 특정 값인지
- matcher는 expect(x) 다음의 matcher(y, z, ...) 이런 형태로 호출된다
- x (received) : matching 여부를 탐색할 element or value
- y, z (expected) : 검사할 때 활용할 매개변수
- 최종 반환값은 { pass: Boolean, message: () => String } 객체이다
- pass 가 true이면 매칭이 잘 됐음을 의미한다
- message 에는 메세지를 리턴하는 콜백 함수를 할당한다
- custom matcher를 만들고 사용하기 전에 expect().extends({ 커스텀매쳐 }) 이렇게 추가해주면 된다
4. 유저의 인터랙션 시뮬레이션하기
user 로 import 하여 클릭, 키보드 등 입력을 시뮬레이션
- user.click(클릭할 엘리먼트)
- user.keyboard(타이핑할 텍스트)
- test 함수 내의 콜백 앞에 async 를 붙여주고
- user 함수 앞에는 await 을 붙여준다!
5. testing-playground 사용하기
jest 실행중인 터미널에서 testing-playground 외부 링크 제공
- 외부링크에서 테스트의 마크업 및 엘리먼트를 찾기위한 쿼리를 확인할 수 있어서 매우 편리
- 마크업 수정해보는 것도 가능
6. element 찾는 방법 2가지
element | aria role |
---|---|
thead | rowgroup |
tbody | rowgroup |
tr | row |
th | columnheader |
td | cell |
쿼리함수나 matcher를 오랫동안 찾는거 시간낭비...
data-testid
또는 container.querySelector()
를 이용!
엘리먼트에 어트리뷰트로 부여
data-testid="users" 이렇게!
그런데 좋은 방법은 아님, 왜냐면 코드베이스에 직접 추가해야하기 때문
rtl은 div (기본값) 을 만들고 그 안에 document.body 를 넣는다. 즉, test 내에서 렌더링하는 컴포넌트는 div로 래핑된다
div 대신 다른 element로 래핑할 수 있다
const table = document.createElement('table')
const {container} = render(<TableBody {...props} />, {
// TableBody 컴포넌트를 table element로 래핑
container: document.body.appendChild(table),
})
이후 container.querySelector()를 사용하여 선택자로 원하는 노드들을 찾으면 된다
7. beforeEach 로 불필요한 중복 줄이기
- 개별 테스트 실행전에 실행 (테스트 파일 최상단)
- test() 처럼 jest에 기본 내장되어 전역에서 사용 가능
- RTL에서는 beforeEach 내부에서 render 함수 사용 불가
- 대신 helper 함수 이용 (최상단에 위치)
src/__tests__
폴더 확인
- npm start
- npm run test