여기서 말하는 unit test 는 하나의 컴포넌트를 대상으로 하는 테스트라고 생각하면 된다.
integration test 는 여러 컴포넌트의 인터렉션을 통해 하는 테스트를 의미한다.
e2e 테스트는 시뮬레이션의 느낌
react-testing-library
테스트를 위해 test 블록에서 해야하는 것들
테스트를 위한 컴포넌트를 렌더링한다.
렌더링 된 컴포넌트왕 상호작용하기 위한 요소를 찾는다.
인터렉팅을 한다. (원인을 만든다)
3번의 결과를 테스팅한다. (Assert)
screen 객체를 이용해 렌더링 된 요소에 접근하자
screen 객체를 이용하면 렌더링 된 화면에 직접적으로 접근할 수 있게 된다.
이렇게 접근해서 테스트 원하는 요소를 불러온 뒤 작업을 하면 됨. Screen 에는 요소를 선택하는 많은 함수가 있는데 아래의 규칙을 따른다. 대부분의 경우에는 get 을 이용한다. 만약 비동기를 사용해야한다면 find 를 사용하자.
priority
테스트를 시작하자
컴포넌트를 테스트할 때는 일반적으로 __test__ 라는 이름을 갖는 폴더를 각 컴포넌트에 만들어준다. 그리고 해당 폴더에서 테스트 파일을 만든다.
테스트 파일은 아래처럼 작성하면 된다. 아래의 예시는 get~, find~, query~, 등의 screen 의 메서드를 이용해 요소를 잡아온다. 주목할건 test-id 를 이용해 잡아오는 예시. 이 예시가 자주 사용되는지는 모르겠지만 확실히 유용하다는걸 알겠다.
import { render, screen } from '@testing-library/react';
import Header from '../Header';
it('should render same text passed into title prop', async () => {
render(<Header title='My Header' />);
const headeringElement = screen.getByText(/My header/i);
expect(headeringElement).toBeInTheDocument();
});
it('same text passed into title prop', async () => {
render(<Header title='My Header' />);
// NOTE: 두 번째 {} 는 옵션이다. heading 에 해당하는 2개의 요소가 찾아져서 원래는 실패해야하는데
// NOTE: 조건으로 My Header를 갖는 헤딩만 찾고 하나만 선택되서 실패하지 않는다.
const headeringElement = screen.getByRole('heading', { name: 'My Header' });
expect(headeringElement).toBeInTheDocument();
});
it('getBy TestId', () => {
render(<Header title='My Header' />);
const headerElement = screen.getByTestId('header-1');
expect(headerElement).toBeInTheDocument();
});
// NOTE: findBy 를 사용하기 위해서는 await 를 사용해야만한다.
it('findBy TestId', async () => {
render(<Header title='My Header' />);
const headerElement = await screen.findByTestId('header-1');
expect(headerElement).toBeInTheDocument();
});
// NOTE: 존재하지 않는걸 테스트 할 때 사용하는 경우가 많음
it('queryBy TestId', async () => {
render(<Header title='My Header' />);
const headerElement = await screen.queryByText(/dogs/i);
expect(headerElement).not.toBeInTheDocument();
});
// NOTE: getAllBy
// NOTE: 그 결과가 array가 된다.
it('getAllNy', async () => {
render(<Header title='My Header' />);
const headerElement = screen.getAllByRole('heading');
expect(headerElement.length).toBe(2);
});
react-router-dom 과 같이 사용할 때 에러
테스트를 작성할 때 아주 기본적인 테스트인데도 이렇게 에러가 나는 경우가 있다. 왜 그럴까?
이유는 위의 에러에 잘 나와있다. Link 컴포넌트는 react-router-dom 에서 제공하고 해당 컴포넌트를 사용하기 위해서는 Router 의 하위에서만 사용할 수 있는데 우리는 TodoFooter 라는 컴포넌트를 isolation 하기 위해 밖으로 뺴서 사용하기 떄문이다 .즉 Router 의 하위에서 TodoFooter 를 테스트하고 있지 않기 때문이다.
import React from 'react'
import "./TodoFooter.css"
import { Link } from "react-router-dom"
function TodoFooter({
numberOfIncompleteTasks
}) {
return (
<div className="todo-footer">
<p>{numberOfIncompleteTasks} {numberOfIncompleteTasks === 1 ? "task" : "tasks"} left</p>
<Link to="/followers">Followers</Link>
</div>
)
}
export default TodoFooter
TodoFooter 의 코드. 내부에서 Link 를 사용하고 있는걸 알 수 있다.
이제 해결 방법에 대한 실마리는 나왔다. TodoFooter 를 Router 의 하위 컴포넌트로 만든 다음에 테스트를 하면 된다!!