c9u11

Next.js + Jest + SVGR 환경 설정

현재 상황

우선 프로젝트의 환경 설정에서 2가지를 도입했다.

  • Next.js
  • Jest

모꼬지 사이드 프로젝트 진행을 위해 프로젝트 설정 후 이제 막 로그인 페이지를 개발하는 중이었다.

로그인 페이지에는 입력한 비밀번호를 확인하기 위한 비밀번호 표시 버튼이 존재한다. 작은 SVG로 되어있다.

SVG를 적용했을 때부터 문제가 생겼고 이 후 테스트를 했을 때는 구글 여기저기를 찾아보며 고생을 했다.

  1. Next.js에서 SVG를 Import 할 때 생기는 문제
  2. Jest를 사용할 때 SVG를 Import하면 테스트가 제대로 이루어지지않는 문제

Next.js에서 SVG 사용하기

https://react-svgr.com/docs/next/

나는 SVG를 사용하기 위해 SVGR이라는 라이브러리를 사용했다.

Img로 넣는 방법도 있었고 svg를 URL로 넣는 방법도 있었지만 특정 상황에 따라 svg의 fill을 사용하여 색상을 변경하고싶었다. 그러면 동일한 형태의 색상만 다른 아이콘을 두 번 호출하지 않아도 되기 때문에 억지로 사용을 해보려 했다.

여러 블로그를 확인하다 찾은 내용이라 공식 문서와 조금 다르다. 어떤 부분이 왜 다른지는 확인을 해봐야겠다.

Install

npm i -D @svgr/webpack

next.config.mjs

compiler 부분은 styled components 사용을 위한 코드다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  compiler: {
    styledComponents: true,
  },
  webpack: (config) => {
    config.module.rules.push({
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    });

    return config;
  },
};

export default nextConfig;

page.tsx

SVG를 그대로 가져와 컴포넌트 형태로 사용하고 색상 등 옵션을 변경할 수 있어 편하다.

import Link from "next/link";
import EyeSVG from "./svgs/eye.svg";

export default function Home() {
  return (
    <div>
      <h1>Home</h1>
      <Link href="/login">login</Link>
      <EyeSVG fill="#000" />
    </div>
  );
}

SVGR과 Jest 사용하기

https://react-svgr.com/docs/jest/

친절하게 공식 문서로 작성되어있다. 하지만 Configure 부분에서 잘못 설정하여 디버깅 시간이 길어졌다. 뭐든지 정확하게 알아보고 해야겠다.

__mocks__/svg.js

이 부분은 공식 문서와 다르게 아래와 같이 설정하는 것이 좋은 것 같다.

공식 문서와 동일하게 작성하면 SvgrURL Warning이 나타난다.

export const ReactComponent = "div";
const SvgUrl = () => "svgrurl";
export default SvgUrl;

jest.config.ts

나를 가장 힘들게 한 파일이다.

공식 문서에서는 module.exports로 나와 있는데 그 하위에 있는 moduleNameMapper를 아래 파일의 config에 넣으면 될 거라는 생각으로 작성했었다. 그게 그 위치가 맞는지 확인도 하지 않고 내 감으로 진행한 거다.

https://github.com/vercel/next.js/discussions/58948

여기저기 뒤져보니 위 링크 최하단에 누군가 아주 친절하게 자신의 모든 파일을 작성해 줬다. 덕분에 나는 에러를 해결했고 드디어 Jest를 사용해 볼 수 있었다.

import type { Config } from "jest";
import nextJest from "next/jest.js";

const createJestConfig = nextJest({
  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
  dir: "./"
});

// Add any custom config to be passed to Jest
const config: Config = {
  coverageProvider: "v8",
  testEnvironment: "jsdom"
  // Add more setup options before each test is run
  // setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
};
const jestConfigWithOverrides = async () => {
  const configFn = createJestConfig(config);
  const res = await configFn();

  res.moduleNameMapper = {
    // We cannot depend on the exact key used by Next.js
    // so we inject an SVG key higher up on the mapping tree
    "\\.svg": "<rootDir>/__mocks__/svg.js",
    ...res.moduleNameMapper
  };

  return res;
};
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
export default jestConfigWithOverrides;