Jest - msw와 jest 오류 해결
📌시작하며
vitest에서 jest로 이동하면서 한 번에 모든 테스트 파일을 옮기면 복잡할 듯 해 한 파일씩 옮겨보고, 테스트가 통과하는지 살펴보는 시간을 가졌다. 한참을 괴롭게했던(…) clipboard에 복사하는 테스트가 무사히 통과 된 이후, vitest에서 진행한 MSW mocking 관련 테스트를 옮겨왔는데 아니나 다를까! 여기서도 오류가 발생했다.😑…
✅UI 테스트 흐름
해당 테스트의 전체적인 흐름은 다음과 같다.
- 데이터가 Fetch 되며, 성공과 실패 상황을 테스트 한다.
- 이때 사전에 Fetch endpoint와 data를 MSW mocking 해둔다.
jest.setup.ts
에 msw와 관련된 teardown을 설정한다.
이미 작성은 전부 되어있었기 때문에 vitest에서 jest로 변경해야 하는 사항만 변경해주고 테스트를 실행했다. 그런데…
🧨에러 발생
💥Cannot find module ‘msw/node’
Cannot find module ‘msw/node’
😲 vitest에서 제대로 실행되던 msw를 갑자기 찾을 수 없다고? 콕 찝어서 msw/node가 없다고 설명하기에 msw/browser를 한 번 시도했으나 이것도 해결되지 않았는데, 이 부분은 msw의 깃허브 이슈에서 해결방법을 찾았다.
참고로 아래의 기본 설정은 Next js에서 jest 설정 기본 튜토리얼에 제공되는 설정을 따랐다.
1
2
3
4
5
6
7
8
9
10
11
const config: Config = {
coverageProvider: "v8",
testEnvironmentOptions: {
customExportConditions: [""],
},
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/$1",
"^@/types/(.*)$": "<rootDir>/types/$1",
},
}
왜 오류가 발생하는지에 대한 설명도 있었는데, 정리해보자면 이 오류는 JSDOM이 테스트 환경에서 브라우저용 코드를 잘못 사용해서 발생한다고 한다.
MSW의 경우 msw/node
와 msw/browser
처럼 사용 환경이 구분되어 있는데, JSDOM은 브라우저 환경처럼 동작하려고 하면서, 브라우저용 코드를 무조건 사용하려고 한다. 하지만 JSDOM은 실제 브라우저가 아니라 Node.js에서 실행되기 때문에, 브라우저 전용 코드를 강제로 사용하면 제대로 동작하지 않아 테스트가 실패하게 되는 것이다.
따라서, 해결 을 위해서는 JSDOM이 브라우저 코드를 사용하려고 하는 기본 동작 을 막야아 한다는 것이다.
이제 문제가 해결되었을 거라 생각했으나… 두번째 에러를 마주하게 되었다.
💥ReferenceError: Response / Request / TextEncoder is not defined
ReferenceError: Response is not defined
문제를 해결하기 위해 스택 오버플로우를 뒤적여 보았고, 제안되는 방안 여럿을 사용해보았다.
1
2
jest.setup.ts
import "cross-fetch/polyfill"
ReferenceError: TextEncoder is not defined
1
2
3
4
5
6
import { ArrayBuffer, TextDecoder, TextEncoder, Uint8Array } from "util"
global.TextEncoder = TextEncoder
global.TextDecoder = TextDecoder
global.ArrayBuffer = ArrayBuffer
global.Uint8Array = Uint8Array
그런데 방법을 하나씩 시도했을 때 문제가 해결되는 것이 아니라 Response, Request, TextEncoder is not defined 만 나와 이걸 어떻게 해결하면 좋을까 하다..
✅해결
공식문서의 해결법으로 오류가 해결되었다!
1
npm i jest-fixed-jsdom
1
2
3
4
5
6
7
8
9
10
11
12
const config: Config = {
coverageProvider: "v8",
testEnvironment: "jest-fixed-jsdom",✨
testEnvironmentOptions: {
customExportConditions: [""],
},
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/$1",
"^@/types/(.*)$": "<rootDir>/types/$1",
},
}
왜 이 오류가 발생했는지 설명하는 부분을 살펴보자.
jest-environment-jsdom
을 사용하면 JSDOM이 Node.js의 기본 내장 API를 브라우저용 대체(polyfill)로 바꾸기 때문에 Node.js 전역(global) 객체를 사용하는 테스트에서 오류가 발생할 수 있다. 따라서 대체 환경인 jest-fixed-jsdom
을 사용해 Node.js 기본 API를 복원해야 한다.
하지만, Jest와 JSDOM 자체의 제약 때문에 이 방법이 완벽한 해결책은 아니며, 이런 제한이 부담스럽다면 Vitest 같은 최신 테스트 프레임워크로 전환을 고려할 수 있다고 안내한다. (Vitest는 Node.js 전역 객체 문제 없이 ESM(모듈 시스템)을 기본 지원한다.)
이러한 이유로 내가 Vitest를 사용했을 때는 이러한 문제가 발생하지 않았던 것으로 보인다.🙄
Vitest를 사용하면서 Test 실행 환경 (VS Code Extension, Browser 환경 등)에 불안정성을 느끼고 불편함을 느껴 Jest로 왔더니 Jest 공식문서에서 대놓고 이러한 이유로 Vitest 전환을 고려할 수 있다고 안내하다니 (…) 테스트 라이브러리를 선택하는 것이 정말 쉬운일이 아니구나 싶다…
😎마무리
사실 공식문서를 가장 먼저 찾아본 것이 아니라 stack overflow나 블로그 글을 먼저 찾아봤다. 외국어 글도 많이 읽어봤는데 왜 공식문서에 해당 문제를 해결하는 법을 안내할거라곤 생각을 못했는지…😱 덕분에 시간이 다소 소요되었지만 어쨌든 문제가 해결되었고, 테스트도 무사히 통과해서 다행이다!😎
그리고, 드디어 기존에 작성했던 모든 vitest 파일을 jest로 변환하는데 성공했다. 테스트도 작성하고, storybook도 작성하면서 스스로 정말 많은 것을 배웠다는 생각이 든다. 오류가 발생할 때는 꽤 많은 시간을 소요해 오류를 해결하면서 힘들기도 했지만 그래도 무사히 이번 개인 프로젝트를 마무리했고, 조금은 성장한 나에게 박수를 보낸다. 🤗🤗🤗
🗂️참고 사이트
- https://github.com/mswjs/msw/issues/1786
- https://stackoverflow.com/questions/77544876/referenceerror-response-is-not-defined-with-msw-node-vitest
- https://mswjs.io/docs/migrations/1.x-to-2.x/#frequent-issues
- https://stackoverflow.com/questions/77358809/referenceerror-textencoder-is-not-defined-during-test-running-with-jest-and-msw
- https://stackoverflow.com/questions/57712235/referenceerror-textencoder-is-not-defined-when-running-react-scripts-test