TypeScriptでもJest+Enzyme

TypeScriptの4つめ。

Lintができたらテストもちゃんとやっとく。最近覚えたJestそしてEnzymeでやります。

$ yarn add jest enzyme react-test-renderer ts-jest @types/jest -D

jestとenzymeを加える他に、@types/jestが必須です。必須ではないですが@types/enzymeも加えておいたほうが今後にはより良いですがとりあえず加えなくても動きます。react-test-rendererはenzymeのpeerDependenciesなため。

// package.jsonの一部
    "scripts": {
        "test": "jest"
    },
    "jest": {
        "moduleFileExtensions": ["ts", "tsx", "js"],
        "transform": {
            "^.+\\.(ts|tsx)$": "./node_modules/ts-jest/preprocessor.js"
        },
        "testMatch": [
            "**/__tests__/*Test.(ts|tsx)"
        ]
    },

package.jsonにscripts.testを追加するのとjestエントリを書きます。jest.moduleFileExtensionsはtsとtsxに加えて、たとえJSでテストを書かずともjsを加えなければなりません。これも裏で処理パイプの中で.jsが出てきてそれらを解決できなくなるのを避けるためです。webpackのresolveと同様な感じ。

transformerでts-jestを設定しています。TypeScriptファイルのトランスパイルを行うのを下記URLのように自分でコード書くのもOKなようですが、ts-jsonはより重厚なことをしています。

https://github.com/facebook/jest/blob/master/examples/typescript/preprocessor.js

// tsconfig.json
{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "jsx": "react",
        "lib": ["es6", "dom"],
        "types": ["jest"]
    }
}

@types/jestを入れ、tsconfig.jsonのcompilerOptions.typesにその型情報を読み込む設定をしないと、Jestテスト中で書くdescribeとtestの両グローバル関数が名前解決できません。またcompilerOptions.libにes6とdomを追加します。これはTypeScriptのコンパイラオプションのページ、

https://www.typescriptlang.org/docs/handbook/compiler-options.html

ここの、–libスイッチの説明にある、

  • Note: If –lib is not specified a default library is injected. The default library injected is:
    • For –target ES5: DOM,ES5,ScriptHost
    • For –target ES6: DOM,ES6,DOM.Iterable,ScriptHost

これがぶつかります。ブラウザで動かすからES5をターゲットとしてるため、Nodeで動かすJestテストやLint実行では問題が起きるということ。前にBabel環境でHMRをやるときにも似たようなことがありましたね(似て非なるのですが)。Babelではモジュール機能をON/OFFにするために面倒なことがありましたが、こちらはトランスパイル時にリンク(?)する標準モジュールの選択でということ。

// /components/__tests__/HelloTest.tsx
import * as React from 'react';
import { shallow } from 'enzyme';
import { Hello } from '../Hello';

describe('HelloComponent', () => {
    test('<Hello TypeScript>', () => {
        const hello = shallow(<Hello compiler="TypeScript" framework="React" />);
        expect(hello.find('h1').text()).toBe('Hello from TypeScript and React!');
    });

    test('<Hello JavaScript>', () => {
        const hello = shallow(<Hello framework="React" />);
        expect(hello.find('h1').text()).toBe('Hello from JavaScript and React!');
    });
});

テストはEnzymeのshallowでシンプルに書いてみました。$yarn testと、これもまたyarn run testのショートハンドが用意されています。

f:id:masataka_k:20170906080833p:plain

AtomはテストのGUIを入れてないから地味。WebStormには素敵なUIがあります。