- 게시일
Next.js + Jest에서 ES Module 패키지 사용하기
date
Oct 14, 2023
slug
nextjs-jest에서-es-module-패키지-사용하기
status
Published
tags
Next.js
Jest
summary
Next.js에서 Jest ES Module 오류 해결
type
Post
발단
ES Module 패키지를 사용하는 컴포넌트의 테스트를 작성하면서 다음과 같은 오류가 발생했다.
FAIL src/components/Input/Input.test.tsx ● Test suite failed to run Jest encountered an unexpected token Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax. Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration. By default "node_modules" folder is ignored by transformers. Here's what you can do: • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it. • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config. • If you need a custom transformation specify a "transform" option in your config. • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option. You'll find more details and examples of these config options in the docs: https://jestjs.io/docs/configuration For information about custom transformations, see: https://jestjs.io/docs/code-transformation Details: <...>/node_modules/.pnpm/[email protected]/node_modules/nanoid/index.browser.js:1 ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export { urlAlphabet } from './url-alphabet/index.js' ^^^^^^ SyntaxError: Unexpected token 'export'
Jest와 ES Module
Jest는 ESM 옵션을 따로 설정하지 않으면 CommonJS로 동작한다. 따라서 ES Module을 사용하는 코드를 CommonJS로 transpile해야한다.
그러나 기본 설정으로
node_modules
는 transpile되지 않으며, transpile하려면 transformIgnorePatterns
설정을 수정해야 한다.시도 1. transformIgnorePatterns
추가
// jest.config.ts import nextJest from 'next/jest'; import type { Config } from 'jest'; const createJestConfig = nextJest({ // Provide the path to your Next.js app to load next.config.js and .env files in your test environment dir: './', }); const esmModules = ['nanoid']; // Add any custom config to be passed to Jest const config: Config = { // Add more setup options before each test is run // setupFilesAfterEnv: ['<rootDir>/jest.setup.js'], testEnvironment: 'jest-environment-jsdom', transformIgnorePatterns: [ `node_modules/(?!(?:.pnpm/)?(${esmModules.join('|')}))`, ], }; // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async export default createJestConfig(config);
위와 같이
transformIgnorePatterns
를 추가해도 동일한 오류가 발생했다.next/jest
의 동작
Next.js 12부터 다음 사항을 포함하여 자동으로 Jest를 구성하는
next/jest
를 제공한다.- SWC를 사용한 transform 설정
- 스타일시트(
.css
,.module.css
,.scss
,.module.scss
), 이미지 import,next/font
자동 모킹
.env
와.env
의 모든 variant를process.env
로 불러오기
- test resolving 및 transform에서
node_modules
무시
- test resolving에서
.next
무시
- SWC transform을 활성화하는 플래그를 위해
next.config.js
불러오기
따라서 내부적으로
node_modules
를 어떻게 제외하는지 확인해보았다.// ... export default function nextJest(options: { dir?: string } = {}) { // createJestConfig return ( customJestConfig?: | Config.InitialProjectOptions | (() => Promise<Config.InitialProjectOptions>) ) => { // Function that is provided as the module.exports of jest.config.js // Will be called and awaited by Jest return async (): Promise<Config.InitialProjectOptions> => { // ... // Ensure provided async config is supported const resolvedJestConfig = (typeof customJestConfig === 'function' ? await customJestConfig() : customJestConfig) ?? {} const transpiled = (nextConfig?.transpilePackages ?? []).join('|') // ... return { ...resolvedJestConfig, // ... transformIgnorePatterns: [ // To match Next.js behavior node_modules is not transformed, only `transpiledPackages` ...(transpiled ? [ `/node_modules/(?!.pnpm)(?!(${transpiled})/)`, `/node_modules/.pnpm/(?!(${transpiled.replace( /\//g, '\\+' )})@)`, ] : ['/node_modules/']), // CSS modules are mocked so they don't need to be transformed '^.+\\.module\\.(css|sass|scss)$', // Custom config can append to transformIgnorePatterns but not modify it // This is to ensure `node_modules` and .module.css/sass/scss are always excluded ...(resolvedJestConfig.transformIgnorePatterns || []), ], // ... } } } }
첫 번째로,
transformIgnorePatterns
가장 앞에 /node_modules/
가 존재하기 때문에 뒤에 패키지를 포함하는 패턴을 추가하더라도 계속 무시된다는 것을 확인할 수 있었다.두 번째로,
next.config.js
에서 transpilePackages
를 가져와서 transformIgnorePatterns
에 추가해준다는 것을 확인할 수 있었다.시도 2. next.config.js
에 transpilePackages
추가
// next.config.js /** @type {import('next').NextConfig} */ const nextConfig = { // ... transpilePackages: ['nanoid'], }; module.exports = nextConfig;
위와 같이
transpilePackages
에 문제가 되는 패키지의 이름을 추가해주었고 테스트가 제대로 동작하는 것을 확인할 수 있었다.> jest -u PASS src/components/Button/Button.test.tsx PASS src/components/Input/Input.test.tsx PASS src/components/Modal/Modal.test.tsx PASS src/components/Spinner/Spinner.test.tsx PASS src/components/Navbar/Navbar.test.tsx PASS src/components/Link/Link.test.tsx Test Suites: 6 passed, 6 total Tests: 34 passed, 34 total Snapshots: 0 total Time: 1.342 s