ReferenceError: Request is not defined
例えば、React Routerが使われたコードをjestでテストすると、タイトルのエラーが発生すると思います。
原因としては、下記になります。
issue自体も7年前にopenになってますし、RequestやFetch_APIもそんな新しい感じがしないので、jsdom、ちょっと大丈夫かなっていう感じは少しします。
↑のissue内にも対応方法がいろいろ載ってますが、
React Routerのドキュメントにもヒントが載ってます。
jest実行時に、whatwg-fetchをpolyfillとして、加えてあげれば良さそうです。
ただ、↑を見ると、node.jsがv18以降だとpolyfillが必要無いような書かれ方になってますが、Testing Libraryあたりと一緒にテストする場合は、v18以降だったとしても、jsdomを使う関係で必要になります。
さらに細かく調べる
そもそもどんなコードで発生するエラーかというと、
こんな↓コードがあった場合に、
import { Link } from "react-router-dom";
export default function Hello() {
return (
<>
<div>Hello</div>
<Link to="/home?page=hoge">Click me</Link>
</>
)
}
こんなテストコード↓があったとして、
import {render, screen} from '@testing-library/react'
import '@testing-library/jest-dom'
import Hello from '../hello'
import { createMemoryRouter, RouteObject, RouterProvider } from 'react-router-dom'
test('loads and displays greeting', async () => {
const FAKE_EVENT = { name: "test event" };
const routes: RouteObject[] = [
{
path: "/",
element: <Hello />,
loader: () => FAKE_EVENT, // ← ここがあるかないかで変わる
}
];
const router = createMemoryRouter(routes, {
initialEntries: ["/"],
initialIndex: 1,
});
// ARRANGE
render(<RouterProvider router={router} />)
// ACT
const e = await screen.findByText('Hello')
expect(e).toBeTruthy()
})
実行すると、表題のようなエラーが発生します。
$ yarn test src/routes/__test__/hello.test.tsx
yarn run v1.22.22
$ jest src/routes/__test__/hello.test.tsx
FAIL src/routes/__test__/hello.test.tsx
✕ loads and displays greeting (1026 ms)
● loads and displays greeting
ReferenceError: Request is not defined
17 | ];
18 |
> 19 | const router = createMemoryRouter(routes, {
| ^
20 | initialEntries: ["/"],
21 | initialIndex: 1,
22 | });
at createClientSideRequest (node_modules/@remix-run/router/router.ts:5056:3)
at createClientSideRequest (node_modules/@remix-run/router/router.ts:1551:19)
at Object.startNavigation [as initialize] (node_modules/@remix-run/router/router.ts:1100:7)
at initialize (node_modules/react-router/index.ts:322:6)
at src/routes/__test__/hello.test.tsx:19:36
at src/routes/__test__/hello.test.tsx:8:71
at Object.<anonymous>.__awaiter (src/routes/__test__/hello.test.tsx:4:12)
at Object.<anonymous> (src/routes/__test__/hello.test.tsx:8:48)
↑で発生した行数とちょっと違いますが、github上だと下記のあたりになるかと思います。
本当に、Requestが使われてます。ちなみに、jsdomじゃなくて、デフォルトのnodeの場合は
jestのデフォルトの実行環境は、nodeですが、例えば、jest.config.jsをこんな感じで設定すると思います。
/** @type {import('ts-jest').JestConfigWithTsJest} **/
export default {
testEnvironment: "node",
transform: {
"^.+.tsx?$": ["ts-jest",{}],
},
setupFiles: ['<rootDir>/setupJest.ts'],
};
そして、さっきのhello.test.tsx
をテストすると
$ yarn test src/routes/__test__/hello.test.tsx
yarn run v1.22.22
$ jest src/routes/__test__/hello.test.tsx
FAIL src/routes/__test__/hello.test.tsx
✕ loads and displays greeting (13 ms)
● loads and displays greeting
The error below may be caused by using the wrong test environment, see https://jestjs.io/docs/configuration#testenvironment-string.
Consider using the "jsdom" test environment.
ReferenceError: document is not defined
23 |
24 | // ARRANGE
> 25 | render(<RouterProvider router={router} />)
| ^
26 |
27 | // ACT
28 | const e = await screen.findByText('Hello')
at render (node_modules/@testing-library/react/dist/pure.js:239:5)
at src/routes/__test__/hello.test.tsx:25:9
at src/routes/__test__/hello.test.tsx:8:71
at Object.<anonymous>.__awaiter (src/routes/__test__/hello.test.tsx:4:12)
at Object.<anonymous> (src/routes/__test__/hello.test.tsx:8:48)
こんなエラーが発生します。
nodeの環境だと、documentが実装されてないんですね。
深くは調べてないですが、そりゃそうかなという気がします。
逆に、nodeでは、v18以降で、Requestは実装されているらしいので、こんな↓感じのテストコードが成功します。
test('Request exists', () => {
const r = new Request('https://example.com')
expect(r).toBeTruthy()
})
ここまでで使用したコードは下記に置いてあります。
ここまでのところで発生しているエラーが発生しないコードになっています。jsdomの最新版でもダメなの?
issueが閉じられてないので、ダメだと思うんですが、念の為調べてみました。
※そもそもjsdom自体を詳細に調べてみたかった。
jestを使う場合は、jest-environment-jsdomを経由して使うと思いますが、バージョンが若干古かったです。
現時点の最新版はここでした。
なので、新しいディレクトリを作成して、yarn addなどして、下記のようにプロジェクトを作りました。
そして下記のようなコードを実行すると
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const dom = new JSDOM(`<body>
<div id="content"></div>
<script>new Request();</script>
</body>`, { runScripts: "dangerously" });
こんな感じでエラーが発生するのでやっぱりダメみたいです。
jsdom-practice$ node request.js
Error: Uncaught [ReferenceError: Request is not defined]
Discussion