Jaeilit

nextjs @svgr/webpack jest + @issue 해결 본문

TIL

nextjs @svgr/webpack jest + @issue 해결

Jaeilit 2023. 7. 21. 17:49
728x90
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.

@svg/webpack 으로 react compoent 로 svg 를 사용하고 있었는데 jest testing 하려니까 이런 에러가 발생했다.

에러 내용은 import 를 잘못했다는 내용이다.

 

첫번째 시도 - 구글링

@icons/ 경로로 tsconfig 에서 path 를 매핑해서 쓰고있었는데 이게 문젠가 싶어서 jest config 에서 moduleNameMapper 부분을 여러번 수정해봤지만 이건 아니였다.

 

tsconfig

 "paths": {
      "@/*": ["./src/*"],
      "@icons/*": ["./public/images/*"]
    }

jestconfig

 moduleNameMapper: {
	...,
    "^@icons/(.*)$": "<rootDir>/public/images/$1",
  },

 

두번째 시도 - git issue

svgr 레포에 git issue 를 찾아봤는데 나랑 똑같은 이슈를 겪는 사람들이 많았다.

https://github.com/gregberge/svgr/issues/83

 

Try to test component with React generated form svgr · Issue #83 · gregberge/svgr

Hi, I have a little problem with Jest tests runner. My simple component: import React from 'react'; import {ReactComponent as CloseIcon} from '../images/close.svg'; const CloseBubble = ({minimize})...

github.com

이슈에 대한 테스트를 한 다른 개발자의 글

https://github.com/gregberge/svgr/issues/83#issuecomment-1120763572

 

Try to test component with React generated form svgr · Issue #83 · gregberge/svgr

Hi, I have a little problem with Jest tests runner. My simple component: import React from 'react'; import {ReactComponent as CloseIcon} from '../images/close.svg'; const CloseBubble = ({minimize})...

github.com

 

차이

  // "\\.svg": "<rootDir>/__mocks__/svgrMock.tsx", // .svg 확장자 검색
    "^.+\\.(svg)$": "<rootDir>/__mocks__/svgrMock.tsx", // .svg 문자열을 검색

 

 

첫번째 정규식은 .svg 가 문자열이 포함되어있으면 검색이 가능하고

두번째 정규식은 ^ 문자열로 시작해서 .svg 라는 문자열로 끝나야해서 정확하게 .svg 파일을 검색하는 정규식이라고 할 수 있지만

 

정확히 왜 success/ fail 인지는 알지못했다.

 

첫번째 예상은 svgr 로 react-compoentns 로 변환했을 때는 브라우저에서 svg 태그로 변환되어있어서라고 생각했는데

저 두개의 정규식은 확장자를 검색하는 정규식이지 svg 태그는 검색하지 못하니 이 예상은 아니다.

 

두번째 예상은 svg 태그의 xmls 이라는 svg 태그 내부의 url같은 것인데 이것 또한 http://www.w3.org/2000/svg 이런식이기 때문에 저 두개의 정규식 어디에도 검색되지 못한다.

 

정확한 이유는 알지못했으나 일단 이슈는 해결되었다..



svg + r 의 조합으로 svg to react 라는 뜻으로

@svgr/webpack 는 빌드시에 svg 파일을 리액트 컴포넌트처럼 사용하게 도와준다.

 

https://react-svgr.com/docs/what-is-svgr/

 

SVGR - Transforms SVG into React Components. - SVGR

Transforms SVG into React Components.

react-svgr.com

 

jest.config.js

// jest.config.js

moduleNameMapper: {
	"\\.svg": "<rootDir>/__mocks__/svgrMock.tsx",
}

 

 

svg 파일을 처리하는 방법에 대해서 매핑을 해줘야한다.

Jest는 테스트할 때 일반적으로 모듈을 모킹(mocking)하여 테스트 환경을 구축합니다.

모킹은 특정 모듈의 실제 구현을 대체하여 테스트에 더 작합한 환경을 만들기 위해 사용됩니다.

 

예를들어 "\\.svg" 는 .svg 확장자를 가진 파일은 __mocks__/svgMock.tsx 을 모킹하라는 뜻이이다.

 

nextjs 공식문서에도 jest testing 관련하여 fileMock.js 를 활용하는 예제도 있습니다.

https://nextjs.org/docs/pages/building-your-application/optimizing/testing

 

Optimizing: Testing | Next.js

Cypress is a test runner used for End-to-End (E2E) and Component Testing. You can use create-next-app with the with-cypress example to quickly get started. Run Cypress for the first time to generate examples that use their recommended folder structure: You

nextjs.org

 

그럼 svgrMock.tsx 을 작성해보면 이렇게 svg component 를 모킹하게끔 작성할수있습니다.

import React, { SVGProps } from "react";

const SvgrMock = React.forwardRef<SVGSVGElement, SVGProps<SVGSVGElement>>(
  (props, ref) => <svg ref={ref} {...props} />
);

SvgrMock.displayName = "SvgrMock";

export const ReactComponent = SvgrMock;
export default SvgrMock;

 

사실 이렇게 작성하지 않고 

// export const ReactComponent = "span"; // tag name
// export default ReactComponent;

이렇게 작성하더라도 테스트는 통과한다.

 

여기 같은 경우는 ReactComponent 에 span 이 아닌 spansss 이런 없는 태그를 적으면 테스트는 통과하지만 에러를 내뱉게 된다.

그리고 디버깅에 <spanss/> 가 생긴걸 볼 수 있다. 이상한걸 모킹했다는 뜻이다.

모킹한다는건 진짜 객체를 가짜 객체로 대체한다는거고 위의 svgrMock.tsx 에 모킹할 가짜 객체를 정의하는건데,

 

첫번째는 svg 를, 두번째는 span 태그를 적어줬다.

이 svg 컴포넌트에 대한 더 상세한 테스트가 필요한 경우 모킹을 하더라도 svg 태그로 해주는게 맞다.

728x90