개인적으로 제일 재미없어 하는 테스트
프론트엔드 개발의 경우 테스트의 의미를 크게 못 느끼고 있는데, 테스트 좀 잘 하라고 그래서 강의를 들으면서 정리해본다^.^ 귀찮은걸 맨날 시키는게 회사지 뭐.
참조 강의 - Udemy: React Testing Library and Jest: The Complete Guide
https://www.udemy.com/course/react-testing-library-and-jest/learn/
const element = screen.getByRole('listitem');
expect(element).toBeInTheDocument();
const element = screen.queryByRole('listitem');
expect(element).not.toBeInTheDocument();
function fakeFetchColors() {
return Promise.resolve(
['red', 'green', 'blue']
);
}
function LoadColor() {
const [colors, setColors] = useState([]);
useEffect(() => {
fakeFetchColors().then(c=> setColors(c));
}, []);
const renderedColors = colors.map(color => {
return <li key={color}>{color}</li>
}
}
test('findBy or findAllBy when data fetching', async () => {
render(<LoadColor />)
// const els = screen.getAllByRole('listitem');
// 에러! fetch해서 데이터를 가져오는 경우엔 에러가 남.
const els = screen.findAllByRole('listitem');
// 베리 굿!
expect(els).toHaveLength(3);
요소를 찾기 힘들 때 자주 사용하는 방식
- data-testid
const rows = within(screen.getByTestId('users')).getAllByRole('row')
tr을 찾고 있음
- querySelector
const {container} = render();
const table = container.querySelector('table');
const rows = container.querySelectorAll('tbody tr');
예제
1) textbox에 값을 넣고 button을 클릭하는 경우
render(<UserForm onUserAdd={() => {}} />
const nameInput = screen.getByRole('textbox', {name: /name/i} );
const emailInput = screen.getByRole('textbox', {name: /email/i });
const button = screen.getByRole('button');
user.click(nameInput);
user.keyboard('jane');
user.click(emailInput);
user.keyboard('jane@jane.com');
user.click(button);
2) element가 여러개인 경우에는 aria-label or name을 사용하면 편함. ex. button 여러개
<label>Email</label>
<input />
<label>Search</label>
<input />
//<button>sign in</button>
//<button>sign out</button>
<button aria-label="sign in"><svg /></button>
<button aria-label="sign out"><svg /></button>
test('버튼들이 있는지 확인', () => {
render(<test />
const signInButton = screen.getByRole('button', {
name: /sign in/i // i는 대소문자 구별없이 찾기 위해
});
const signOutButton = screen.getByRole('button', {
name: /sign out/i // i는 대소문자 구별없이 찾기 위해
});
expect(signInButton).toBeInTheDocument();
expect(signOutButton).toBeInTheDocument();
});
3) getby, queryby, findby 비교: 없는 요소(ex.textbox)를 찾고자 하면?
test('없는 요소 찾으려고 할때 테스트', async () =>
{
render(<colorList />)
expect(() => screen.getByRole('textbox')).toThrow();
expect(() => screen.queryByRole('textbox')).toEqual(null);
// 만약 textbox가 두개 이상있는데 위 처럼 써주면 throw error임. toThrow로 써줘야함
let errorThrown = false;
try {
await screen.findByRole('textbox');
} catch(err) {
errorThrown = true;
}
expect(errorThrown).toEqual(true);
});
4) getby, queryby, findby 비교: 있는 요소(ex.textbox)를 찾고자 하면?
test('있는 요소 찾으려고 할때 테스트', async () =>
{
render(<colorList />)
expect(screen.getByRole('list')).toBeInTheDocument();
expect(screen.queryByRole('list')).toBeInTheDocument();
expect(await screen.findByRole('list')).toBeInTheDocument();
});
5) getAllBy, queryAllBy, findAllBy 비교
test('AllBy 테스트', async () =>
{
render(<colorList />)
//listitem은 li를 의미하는 것
expect(screen.getAllByRole('listitem')).toHaveLength(3);
expect(screen.queryAllByRole('list')).toHaveLength(3);
expect(await screen.findAllByRole('list')).toHaveLength(3);
});
6) 다이나믹한 value 인 경우? RegExp사용하여 테스트
test('Displays information about the repository', () => {
const repository = {
language: 'Javascript',
stargazers_count: 5,
forks: 30,
open_issues: 1
}
render(<RepositoriesSummary repository={repository} />);
const language = screen.getByText('Javascript');
const stars = screen.getByText(5);
const forks = screen.getByText('30 Forks');
const open_issues = screen.getByText('1 issues need help');
expect(language).toBeInTheDocument();
expect(stars).toBeInTheDocument();
expect(forks).toBeInTheDocument();
expect(open_issues).toBeInTheDocument();
for (let key in repository) {
const value = repository[key];
const element = screen.getByText(new RegExp(value));
expect(element).toBeInTheDocument();
}
});
좋은 글이네요. 공유해주셔서 감사합니다.