자바스크립트는 비동기 함수가 자주 사용된다. 만약 비동기 함수를 일반적으로 테스트한다면 해당 테스트 수트가 완료되기전에 테스트는 종료되고 다음 테스트 수트가 실행된다
test('async', () => {
setTimeout(() => {
console.log('async')
}, 1000)
})
test('sync', () => {
console.log('sync')
})
위의 테스트 코드를 실행하면 문제 없이 통과한다. 하지만 1초후 비동기로 실행된 함수가 실행되면서 Cannot log after tests are done. Did you forget to wait for something async in your test?
라는 에러메세지가 나타난다.
위의 예제는 값 검증이 없기 때문에 성공했지만 만약 값을 받아 검증한다면 비동기 함수에서 프로미스 객체가 반환되기 때문에 테스트가 실패할 것이다
이런 문제를 막기위해 비동기 테스트를 위한 몇가지 방법이 있다
// fetchData
test('the data is peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});
프로미스가 reject
된다면 테스트가 실패한다. 단 프로미스를 반환하도록 해야 실패함을 인지한다.
프로미스를 사용할 경우 프로미스 객체를 반환해야만 제대로 작동하므로 여러개의 비동기 함수를 테스트하게 된다면 사용하기 어렵다. 이러한 경우 테스트 콜백을 aync
함수로 만들고 await
키워드를 통해 비동기 함수가 완료되길 기다릴 수 있다.
test('the data is peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
expect.assertions(1);
try {
await fetchData();
} catch (e) {
expect(e).toMatch('error');
}
});
expect()
함수의 인자로 비동기 함수를 넘길 경우 비동기 함수를 기다리기 위해 resolves, rejects
를 매처로 사용한다. 단 이 방법 또한 테스트 콜백 내에서 반환해야만 제대로 작동한다
마찬가지로 async 테스트 콜백 내에서 await 키워드와 같이 사용하는 것도 가능하다
// sync
test('the data is peanut butter', () => {
return expect(fetchData()).resolves.toBe('peanut butter');
});
test('the fetch fails with an error', () => {
return expect(fetchData()).rejects.toMatch('error');
});
// async
test('the data is peanut butter', async () => {
await expect(fetchData()).resolves.toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
await expect(fetchData()).rejects.toMatch('error');
});
공식 문서 참조