Jest 테스트 코드 작성 시 겪었던 문제들

May 20, 2023

글을 작성하게 된 이유

  • test 코드 작성하면서 겪었던 문제들을 정리하고자 한다.

Image onLoad/onError 비동기 테스트

  • 기능 : Image 태그를 활용하여 이미지 크기를 구한다
  • flow :
    • Image를 생성한다.
    • Imagesrc를 설정한다.
    • onLoadonError를 테스트한다.
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;
  });
};
  • 테스트 코드
    • ImageMockImage로 대체한다.
    • MockImagesrc를 설정하면 path에 따라 onLoadonError가 호출된다.
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_ENVproduction이면 _blank로, development이면 _self로 설정한다.
<Link target={process.env.NODE_ENV === 'production' ? '_blank' : '_self'}>link</Link>
  • 테스트 코드
    • process.env.NODE_ENVOldEnv로 대체한다.
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");
    })
   
});

© 2023, Customized by Joon