글을 작성하게 된 이유
- test 코드 작성하면서 겪었던 문제들을 정리하고자 한다.
Image onLoad/onError 비동기 테스트
- 기능 : Image 태그를 활용하여 이미지 크기를 구한다
- flow :
Image
를 생성한다.
Image
의 src
를 설정한다.
onLoad
와 onError
를 테스트한다.
const getImageSize = (url: string): Promise<ImageSize> => {
return new Promise((resolve, reject) => {
const img = new Image();
const handleImageLoad = () => {
const { width, height } = img;
resolve({ width, height });
};
const handleError = (err: ErrorEvent) => {
reject(new Error("invalid url"));
};
img.addEventListener("load", handleImageLoad);
img.addEventListener("error", handleError);
img.src = url;
});
};
- 테스트 코드
Image
를 MockImage
로 대체한다.
MockImage
의 src
를 설정하면 path에 따라 onLoad
와 onError
가 호출된다.
const MOCK_IMAGE_SIZE = { width: 100, height: 100 };
const InvalidUrlError = new Error("invalid url");
class MockImage {
onload: (() => void) | null = null;
onerror: (() => void) | null = null;
width = 0;
height = 0;
set src(url: string) {
if (url === "invalid-url") {
this.triggerError();
return;
}
this.triggerLoad();
}
addEventListener(event: string, callback: () => void) {
if (event === "error") {
this.onerror = callback;
return;
}
this.onload = callback;
}
triggerLoad() {
this.width = MOCK_IMAGE_SIZE.width;
this.height = MOCK_IMAGE_SIZE.height;
this.onload?.();
}
triggerError() {
this.onerror?.();
}
}
global.Image = MockImage as unknown as typeof Image;
describe("getImage", () => {
it("image에 src를 넣으면 width와 height를 반환한다.", async () => {
const size = await getImageSize("valid-url");
expect(size).toEqual(MOCK_IMAGE_SIZE);
});
it("invalid한 url을 넣으면 에러를 반환한다.", async () => {
try {
await getImageSize("invalid-url");
} catch (err) {
expect(err).toEqual(InvalidUrlError);
}
});
});
ENV 테스트
- 기능 : Prod 환경에서는 새창을 띄우고, Dev 환경에서는 현재창에서 띄운다.
- flow :
process.env.NODE_ENV
를 사용하여 환경변수를 확인한다.
process.env.NODE_ENV
가 production
이면 _blank
로, development
이면 _self
로 설정한다.
<Link target={process.env.NODE_ENV === 'production' ? '_blank' : '_self'}>link</Link>
- 테스트 코드
process.env.NODE_ENV
를 OldEnv
로 대체한다.
describe('link', () => {
it("production", () => {
const oldEnv = process.env.NODE_ENV;
process.env = {
...process.env,
NODE_ENV: 'production'
}
const { getByText } = render(<Link />);
expect(getByText("Link")).toHaveAttribute("target", "_blank");
})
it("development", () => {
const oldEnv = process.env.NODE_ENV;
process.env = {
...process.env,
NODE_ENV: 'development'
}
const { getByText } = render(<Link />);
expect(getByText("Link")).toHaveAttribute("target", "_self");
})
});