かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Jest × React Testing Library × msw で fetch を使ってるコンポーネントのテストでエラーになった

Next.js の getStaticProps 内で fetch を使っているページコンポーネントを Jest × React Testing Library × msw でテストしようとしたら ReferenceError: fetch is not defined になった

環境

  • node.js 18.16.0
  • Next.js 13.4.12
  • React 18.2.0
  • TypeScript 5.1.6
  • jest 26.6.3
  • @testing-library/react 14.0.0
  • @testing-library/jest-dom 5.17.0
  • msw 1.2.3

ReferenceError: fetch is not defined の発生

/src/pages/blog.tsx

type BlogPageProps = {
  posts: PostInterface[];
};
export default function BlogPage({ posts }: BlogPageProps) {
  // 略
};

export const getStaticProps: GetStaticProps = async () => {
  const res = await fetch(new URL(API_PATH));
  const posts = await res.json();
  return {
    props: { posts }
  };
};

node.js v18 からは node 環境でも fetch が使えるはずで、このページの画面の表示は問題なくできているがテストでは ReferenceError: fetch is not defined のエラーになってしまう状況

$ jest --env=jsdom --verbose

FAIL  src/__tests__/BlogPage.test.tsx

ReferenceError: fetch is not defined
      23 | export const getStaticProps: GetStaticProps = async () => {
    > 24 |   const res = await fetch(new URL(API_PATH));
         |               ^
      25 |   const posts = await res.json();
      26 |
      27 |   return {

Jest で fetch を使うには polyfil が必要

fetch is not available in Node, which is where Jest is running your tests. Is it an experimental browser technology.
You will need to polyfill the behaviour if you want to make actual http calls, or mock fetch to simulate network requests.
cf. Fetch do not work on Jest · Issue #2071 · jestjs/jest · GitHub

 

Jest tests run in Node.js, although they execute your components that may use window.fetch. How this works usually is testing environment polyfills fetch for you (i.e. with node-fetch, whatwg-fetch, or any other compatible polyfills). Most of the frameworks like CRA come with that polyfill built-in, so you rarely pay attention that you need it.
cf. ReferenceError: fetch is not defined · Issue #686 · mswjs/msw · GitHub

polyfill を調べていると node-fetch, whatwg-fetch, cross-fetch の3つが有名っぽかった

cross-fetch vs node-fetch vs whatwg-fetch

node-fetch, cross-fetch は TypeScript で whatwg-fetchJavaScript
node-fetch が最も利用されているが最終更新が 4年前だったので、最近も開発されている cross-fetch を使うことにした

$ npm i -D cross-fetch

テストファイルに cross-fetch を import する

/src/__tests__/BlogPage.test.tsx

import 'cross-fetch/polyfill';

//  略

テストファイルには import 'cross-fetch/polyfill'; を追加するだけで他には何も変更していないが、これでテストを実行すると問題なく fetch 部分が通り正しくテストが実行されるようになった

$ npm run test
…
PASS  src/__tests__/BlogPage.text.tsx

node.js でも fetch が使えるようになっているはずだから大丈夫だろうと思っていたが、Jest 起因でエラーになってしまうのは予期してなかった。
polyfill の中身とかはちゃんと確認していないが Jest を使ったテストで ReferenceError: fetch is not defined になる場合は polyfill を使えば解決する。(本当はライブラリの中身をちゃんと確認したほうが良いのだが)
fetch が実行されるコンポーネントのテストの度に import 'cross-fetch/polyfill'; を書くのは少し面倒なので、テスト時に必ずインポートする設定ファイルのようにしてしまっても良いかもしれない

おわり


[参考]