7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

node v18 で導入された global fetch を jsdom 環境下の jest で利用する方法

Last updated at Posted at 2023-04-26

背景

  • Node.js v18 で global fetch API が実験的に導入された
  • これにより jest 等 Node.js のランタイムで fetch API を利用する際に node-fetch 等の外部ライブラリを導入する必要がなくなった
  • しかし通常 React のテスト等で用いる jsdom 環境で利用するにはいくつか苦労があったのでまとめておく

jest のバージョンを確認

Node.js のバージョンが v18 以降であっても jest のバージョンが v28 未満だと fetch API を利用できない。
https://jestjs.io/blog/2022/04/25/jest-28#all-nodejs-globals

package.json で jest のバージョンを ^28 以上に指定して npm install または yarn install を実行することで、期待するバージョンの jest をインストールすることができる。

jsdom 環境を拡張

jsdom とは

前提として、ブラウザ上で動作する JavaScript は、生の JavaScript に加えてブラウザ操作用の API を利用可能な環境になっている。
この独自の API はブラウザに実装された機能なので、純粋な JavaScript には含まれていない。従ってブラウザ上では利用できるけど Node.js 上では利用できないオブジェクト等が多く存在する。

しかし、そのままではブラウザ向けに実装した各種コードを Jest 等の Node.js ランタイムでテストしたい時などに不便である。
そこで Node.js のランタイム上でブラウザ独自の API を利用できるように、同じ動きをシミュレートできるような実装を提供してくれるのが jsdom である。

jest からは jest.config.js 内で下記のように設定することで jsdom の実装を global に反映している。

testEnvironment: "jest-environment-jsdom"

ところが、この jest-environment-jsdom が global オブジェクトを差し替えているために、 Node.js v18 で導入された global fetch が差し替え後の global に反映されておらず、実際に fetch を利用しようとすると ReferenceError: fetch is not defined というエラーが発生することになる。

jsdom 環境を拡張する

jest のドキュメントによれば、 testEnvironment は自作できるらしい。

You can create your own module that will be used for setting up the test environment. The module must export a class with setup, teardown and getVmContext methods. You can also pass variables from this module to your test suites by assigning them to this.global object – this will make them available in your test suites as global variables. The constructor is passed globalConfig and projectConfig as its first argument, and testEnvironmentContext as its second.

これを利用して、このコメントで提案されている方法を試してみる。

FixJSDOMEnvironment.ts
import JSDOMEnvironment from "jest-environment-jsdom";

// https://github.com/facebook/jest/blob/v29.4.3/website/versioned_docs/version-29.4/Configuration.md#testenvironment-string
export default class FixJSDOMEnvironment extends JSDOMEnvironment {
  constructor(...args: ConstructorParameters<typeof JSDOMEnvironment>) {
    super(...args);

    // FIXME https://github.com/jsdom/jsdom/issues/1724
    if (!this.global.fetch) {
      this.global.fetch = fetch;
      this.global.Headers = Headers;
      this.global.Request = Request;
      this.global.Response = Response;
    }
  }
}
jest.config.ts
{
  "testEnvironment": "./FixJSDOMEnvironment.ts"
}

この状態で jest を実行することで、無事に node-fetch の polyfill なしで Node.js 標準の fetch API を利用することができた。

MSW の Node.js v18 対応

無事に Node.js 標準の fetch API を利用することができたものの、別の問題として API のモックに利用している MSW が Node.js v18 に対応しておらず、 API アクセスをモックできないことが分かった。

公式の issue を見ると、2023年1月時点では対応の意思こそあるもののメンテナが忙しくて作業できていないという悲痛なコメントが見られる。
https://github.com/mswjs/msw/issues/1388#issuecomment-1401706972

結論

以上より、まだ Experimental な Node.js 純正の fetch API にこだわるよりも、 jsdom や MSW の対応が完了するまでは今まで通り node-fetch による polyfill に頼った方が良さそうに思った。
(MSW を使っていないプロジェクトなら問題ないかもしれないが、そこは各々で判断してほしい。)

jest.setup.js
// 今まで通りの polyfill
import "isomorphic-fetch"

参考

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?