- 리액트 컴포넌트를 테스트 할 때 주로 어떠한 결과가 화면상에 잘 타나났는지 어떠한 이벤트 혹이 함수가 호출 됐을 때 원하는 업데이트가 잘 반영이 되는지를 확인
- 이를 수행하는 가장 기본적 방법은 react-dom/test-utils 안에 들어있는 유틸 함수 사용
- 컴포넌트의 내부 기능을 자주 접근
- props와 state 확인
- 컴포넌트의 내장 메서드 직접 호출
-
렌더링 결과에 조금 더 집중
- DOM에 대해서 신경 더 씀
- 컴포넌트 인스턴스 무시
-
어떠한 이벤트가 발생했을 때 화면에 원하는 변화가 생겼는 지 확인용
-
모든 테스트를 DOM 위주로 진행
-
컴포넌트의 props나 state를 조회하는 일은 없음
컴포넌트 리펙토링
주로 내부 구조, 네이밍은 많이 바뀔 수 있지만
실제 작동 방식은 크게 바뀌지 않음
- 위의 이유로 인해서 컴포넌트 기능이 똑같이 작동한다면 내부 구현 방식이 많이 바뀌어도 테스트를 통과시키도록 설계
yarn add @testing-library/react @testing-library/jest-dom yarn add @types/jest jest-dom은 jest 확장 DOM에 관련된 matcher 추가
- DOM 시뮬레이션을 위한 JSDOM 이라는 도구를 사용하여 document.body에 리액트 컴포넌트를 렌더링 함
- clean-up-after-each를 불러오면 각 테스트 케이스가 끝날 때 마다 기존에 가상의 화면에 남아있는 UI 정리
- jest-dom/extend-expect를 불러와서 jest에서 DOM 관련 matcher를 사용 할 수 있게 해줌
- 렌더링된 결과가 이전에 렌더링한 결과와 일치하는지 확인하는 작업
- 컴포넌트가 렌더링 됐을 때 이 스냅샷과 일치하지 않으면 테스트가 실패함
- 스냅샷을 업데이트 하고 싶다면 테스트가 실행되고 있는 콘솔창에서
- press u
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Profile> matches snapshot 1`] = `
<div>
<div>
<b>
ww8007
</b>
<span>
(
장동현
)
</span>
</div>
</div>
`;
-
render 함수를 실행하고 나면 그 결과물 안에는 다양한 쿼리 함수들이 존재
-
이들은 react-testing-library 기반인
- dom-testing-library에서 지원하는 함수들
-
Variant와 Queries의 조합으로 네이밍이 이루어짐
- getBy
- getBy*로 시작하는 쿼리는 조건에 일치하는 DOM 엘리먼트 하나를 선택
- 없으면 에러 throw
- getAllBy
- getAllBy* 로 시작하는 쿼리는 조건에 일치하는 DOM 엘리먼트 여러개를 선택
- 하나도 조건에 일치하지 않는다면 에러 throw
- queryBy
- queryBy* 로 시작하는 쿼리는 조건에 일치하는 DOM 엘리먼트 하나를 선택
- 없다해도 에러를 발생키지 않음
- queryAllBy
- queryAllBy* 로 시작하는 쿼리는 조건에 일치하는 DOM 엘리먼트 여러개를 선택
- 존재하지 않더라도 에러를 내뿜지 않음
- findBy
- findBy* 로 시작하는 쿼리는 조건에 일치하는 DOM 엘리먼트가 하나가 나타날 때 까지 기다렸다가 해당 DOM을 선택하는 Promise 반환
- 기본 timeout 4500ms -> 4.5초 이후에도 나타나지 않으면 에러 발생
- findAllBy
- findBy* 로 시작하는 쿼리는 조건에 일치하는 DOM 여러개가 나타날 때 까지 기다렸다가 해당 DOM을 선택하는 Promise 반환
- 기본 timeout 4500ms -> 4.5초 이후에도 나타나지 않으면 에러 발생
-
ByLabelText
- label이 있는 input의 label 내용으로 input을 선택
<label for="username-input">아이디</label> <input id="username-input" /> const inputNode = getByLabelText('아이디');
-
ByPlaceholder
- placeholder 값으로 input 및 textarea 선택
<input placeholder="아이디" />; const inputNode = getByPlaceholderText("아이디");
-
ByText
- 엘리먼트가 가지고 있는 텍스트 값으로 DOM을 선택
<div>Hello World!</div>; const div = getByText("Hello World!");
-
ByAltText
- alt 속성을 가지고 있는 엘리먼트(주로 img)를 선택
<img src="/awesome.png" alt="awesome image" />; const imgAwesome = getByAltText("awesome image");
-
ByTitle
-
ByTitle 은 title 속성을 가지고 있는 DOM 혹은 title 엘리먼트를 지니고있는 SVG 를 선택 할 때 사용합니다.
-
title 속성은 html 에서 툴팁을 보여줘야 하는 상황에 사용하곤 합니다.
<p> <span title="React">리액트</span>는 짱 멋진 라이브러리다. </p> <svg> <title>Delete</title> <g><path/></g> </svg> const spanReact = getByTitle('React'); const svgDelete = getByTitle('Delete');
-
-
ByDisplayValue
- ByDisplayValue 는 input, textarea, select 가 지니고 있는 현재 값을 가지고 엘리먼트를 선택합니다.
<input value="text" />; const input = getByDisplayValue("text");
-
ByRole
- 특정 role 값을 지니고 있는 엘리먼트 선택
<span role="button">삭제</span>; const spanRemove = getByRole("button");
-
ByTestId
- 다른 방법을 통해서 선택을 못하는 경우 사용
- 특정 DOM에서 직접 test 할 때 사용할 id를 달아서 선택하는 것
<div data-testid="commondiv">흔한 div</div>; const commonDiv = getByTestId("commondiv");
- 위와같이 엄청나게 많은 쿼리가 있다.
- 메뉴얼에서는 아래와 같이 우선순위를 따라서 사용하는 것을 권장
- getByLabelText
- getByPlaceholderText
- getByText
- getByDisplayValue
- getByAltText
- getByTitle
- getByRole
- getByTestId
- DOM의 querySelector 를 사용가능하지만 이것 보다는 data-testid 를 설정하는 것이 좋음
- fireEvent() 함수
- 이벤트를 발생 시켜주는 특징이 있다.
fireEvent.이벤트 이름(DOM, 이벤트객체);
- click 이벤트의 경우에는 이벤트 객체를 따로 넣어주지 않아도 된지만
- change 이벤트의 경우에는 다음과 같이 넣어줘야함
fireEvent.change(myInput, { target: { value: "hello world" } });