2
3

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.

Next.js + TypeScript + Jestで単体テスト環境を構築

Last updated at Posted at 2022-07-05

概要

  • 「Next.js」+「TypeScript」でのフロントエンド開発環境に向けて、Jestを使った単体テスをの設定を記載します。
  • 特に、DOMコンポーネントのテスト向けに、「React Testing Library」を使った設定を記載します。
  • 同様の設定に関する有用な記事は数多く、二番煎じどころではないが、バージョンや使うライブラリの組み合わせによってハマるポイントも多そうだったので、実際に直面したエラーとその解決策も載せておきます。

前提

  • 環境
    • next.js: v.12.1.X
    • typescript: v.4.7.X
    • jest: v.28.1.X

テスト対象となるコードを用意する

以下のコードをサンプルとして用意してみた。

// src/components/Sample.tsx

import emailRegex from 'email-regex';

export const EmailForm = () => {
    const form = useForm({
        initialValues: { email: '' },
        validate: { email: (value) => emailRegex({exact: true}).test(value)? null : 'failed.' }
    });
    return (
        <form onSubmit={form.onSubmit((values) => console.log(values)}>
            <TextInput {...form.getInputProps('email')}/>
            <Button type="submit">
                Push
            </Button>
        </form>
    )
}

また、テストコードは以下のようなものを用意

// src/components/Sample.spec.tsx
import { render, screen } from "@testing-library/react";
import { EmailForm } from "./specs/Sample";

it('changes the class when hovered', () => {
	render(<EmailForm />);
    screen.debug();
});

レンダリングしたHTMLを確認するだけのテスト。実際には想定しているタグが含まれているか?などをチェックすることになると思います。


基本編

パッケージインストール

こちらの記事を参考に、必要なパッケージのインストールと、設定ファイルの用意をします。
同時に、「React Testing Library」のパッケージもインストールしておきます。

yarn add --dev jest @types/jest ts-jest @testing-library/react

config設定

Jestのコンフィグを設定します。
jest.config.jsファイルを作成し、以下の設定を記述します。

// jest.config.js
module.exports = {
    preset: 'ts-jest',
    globals: {
        'ts-jest': {
            tsconfig: './tsconfig.test.json'
        }
    }
}

すでに存在している(はずの)tsconfig.jsonに代わって、テスト用のtsconfig.test.jsonを読み込みます。
tsconfig.test.jsonは以下の通り。

// tsconfig.test.json
{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "jsx": "react-jsx"
    }
}

ここで大事なポイントは、デフォルトのtsconfig.jsoncompilerOptionsパラメータを上書きすることです。具体的には、"fsx": "preserve"となっている部分を"jsx": "react-jsx"に置き換えます。

ドキュメントによると、

  • preserveは、Babel等によるトランスパイル処理が行われることを前提に、出力の一部が、JSXフォーマットになる方式。
  • react-jsxは、React v.17から導入された変換方式に従って、JSXフォーマットをJSで解釈可能なフォーマットに変換する方式。

この設定を入れないと、テスト実行環境で、JSXを解釈できずに、下記のようなエラーが出るはず。

SyntaxError: Unexpected token '<'

ここで yarn jest が通れば設定はおしまい


SyntaxError: Unexpected token 'export'が発生した場合

こちらの記事によると、ts-jestはESModuleに対応していないとのこと。
そして、導入したライブラリの中にESModuleで提供されているパッケージがあると、そのままではJest上でimportできないようです。

そのため、このようなエラーが出たときは、babel-jestを使った変換を指示してあげる必要があります。

パッケージインストール

babelを使った変換に必要なパッケージをインストールします。

yarn add --dev babel-jest @babel/preset-env @babel/plugin-transform-modules-commonjs

config設定

babelのコンフィグを設定します。
babel.config.jsファイルを作成し、以下の設定を記述します。

// babel.config.js
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          node: 'current',
        },
      }
    ]
  ],
  plugins: [
    '@babel/plugin-transform-modules-commonjs',
  ]
}

Jestのコンフィグを修正します。
jest.config.jsを下記のように修正します。

// jest.config.js
module.exports = {
    transform: {
        '\\.jsx?$': 'babel-jest',
        '\\.tsx?$': 'ts-jest'
    },
	transformIgnorePatterns: [
        '/node_modules/(?!email-regex)'
	],
    globals: {
        'ts-jest': {
            tsconfig: './tsconfig.test.json'
        }
    }
}

ここで大事なポイントは、transformIgnorePatternsとして、エラーが発生しているESModuleライブラリを変換対象に加えている点です。
否定先読み表現 (?!hoge) を使って、該当する名前に合致するライブラリ 以外 を変換対象外としています。

今回は、email-regexが該当しているため、上記のような書き方をしています。ここは環境に合わせて変更してください。

この設定を入れないと、ESModuleを変換してくれないため、以下のエラーが発生し、正しくimportできないことがわかる。

SyntaxError: Unexpected token 'export'

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.が発生した場合

テスト環境の指定の修正が必要になります。デフォルトのままだとNode.jsとなっていますが、これを jest-environment-jsdom に変更します。

パッケージインストール

jest-environment-jsdomをインストールします。

yarn add --dev jest-environment-jsdom

config設定

Jestのコンフィグを修正します。
jest.config.jsを下記のように修正します。

// jest.config.js
module.exports = {
    transform: {
        '\\.jsx?$': 'babel-jest',
        '\\.tsx?$': 'ts-jest'
    },
	transformIgnorePatterns: [
        '/node_modules/(?!email-regex)'
	],
    testEnvironment: 'jsdom',
    globals: {
        'ts-jest': {
            tsconfig: './tsconfig.test.json'
        }
    }
}

babelにより、Next.jsのSWCが無効化されて困った場合

babel.config.jsonを利用した際、Next.jsのSWCが無効化され、トランスパイルが思った通りに動かないことがあります。

トランスパイルが走った際に、以下のように、TypeScriptが正しく解釈できなかったことによるエラーが出ます。

info  - Disabled SWC as replacement for Babel because of custom Babel configuration "babel.config.js" https://nextjs.org/docs/messages/swc-disabled
info  - Using external babel configuration from /workspace/babel.config.js
wait  - compiling...
error - ./src/component/index.tsx:15:33
Syntax error: Unexpected token, expected ","
...

このような場合、

  1. babel.config.jsonのファイル名変更
    1. このままだと、自動的に読み込まれてbabelを利用したトランスパイル処理が走ってしまう。そこで、名前を、babel.config.my.jsonなどに変えてあげる
  2. jest.config.jsonのtransformオプションを追加
    1. jest用のconfigの中で、configFileを追加
    2. configFile には、上記名前変更したbabel用configファイルを指定
// jest.config.js
module.exports = {
  transform: {
    '\\.jsx?$': ['babel-jest', { 'configFile': './babel.config.my.js' }],
    '\\.tsx?$': 'ts-jest'
  },
  transformIgnorePatterns: [
    '/node_modules/(?!email-regex)'
  ],
  testEnvironment: 'jsdom',
  globals: {
    'ts-jest': {
      tsconfig: './tsconfig.test.json'
    }
  }
}

これで動く(はず)


おしまい

あとはyarn jestを実行すればテストが動きました。

# yarn jest
yarn run v1.22.19
$ /workspace/node_modules/.bin/jest
 PASS  src/components/Sample.spec.tsx (37.822 s)
  ✓ changes the class when hovered (184 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        42.163 s
Ran all test suites.
Done in 48.51s.

2
3
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
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?