最近、フロントエンド界隈で人気上昇中のE2EテストフレームワークのCypressをTypeScript × React環境に導入したので、備忘録も兼ねて、TypeScript × ReactへのCypress導入方法をシェアしたいと思います。
Cypressについて
「Cypressって一体何?」という方は、公式サイトを含めた、下記の記事などをご参照ください。
本記事では、Cypress自体についてや、他のE2EテストフレームワークのTestCafeと比較した点などについてはあまり言及しません。
が、一応、トレンドに関しては、npm trendsで調べてみましたので、現時点(2018年1月26日)での結果をおまけ的に付けておきます。
実行環境
- Mac OS Sierra: v10.12.6
- node: v8.2.0
- npm: v5.3.0
TypeScript × React環境を作成
node.jsがインストールされていることが前提です。
create-react-app
を用いて、Reactアプリを構築します。
$ cd ~/
# TypeScriptによるReactアプリをmy-appディレクトリに作成
$ create-react-app my-app --scripts-version=react-scripts-ts
# アプリの起動を確認
$ cd my-app
$ npm start
アプリの起動まで確認できたら、Ctrl + C
でアプリを一旦、終了してください。
Cypressをインストール
公式ドキュメントに則り、上記で作成したプロジェクトにCypressをインストールします。
$ npm install cypress --save-dev
# Cypressの起動を確認
$ npx cypress open
Cypressの画面が立ち上がりますので、テストの対象としてexample_spec.js
をクリックして、テストを開始します。
テスト終了後、Ctrl + C
で、Cypressを一旦、終了します。
アプリの起動を再確認
続いて、npm start
でアプリを再起動しようとすると、次のようなコンパイルエラーが発生するかと思います。
Failed to compile.
/node_modules/@types/jest/index.d.ts
(18,13): Duplicate identifier 'beforeEach'.
これはインストールした型定義ファイルのところで問題が発生しているので、型定義ファイルのチェックを無視する設定を行います。
(もしくは、次のようなエラーが発生した場合には、npm install
で、外部パッケージをインストールし直してからnpm start
を実行してください)
sh: react-scripts-ts: command not found
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn
npm ERR! my-app@0.1.0 start: `react-scripts-ts start`
npm ERR! spawn ENOENT
npm ERR!
npm ERR! Failed at the my-app@0.1.0 start script.
型定義ファイルのチェックを無視する設定に変更
コンパイルエラーを確認できたら、tsconfig.jsonをエディタで開き、"skipLibCheck": true,
をcompilerOptions
に追加して保存します。
"compilerOptions": {
...
"skipLibCheck": true,
...
"skipLibCheck": true
の設定は、全ての型定義ファイル(.d.ts)の整合性チェックを行わないようにするオプションなので、次のリンク先で、Cypressの中の人がコメントされている通り、「理想的ではない」とされています。が、「結局のところオススメの解決策だ。」みたいに言われています。
Confirmed, it was skipLibCheck I added to get around Jest "Set" problem. Ok, so the recommended solution is ultimately
{
"compilerOptions": {
"skipLibCheck": true
}
}
in the root tsconfig.json file. Not ideal, but it is hard or impossible to make globals work without clashing.
参考:Possible type definition conflict on @types/chai
取り敢えず、これでもう一度、npm start
でアプリを起動し、コンパイルエラーが発生しないことを確認します。
コンパイルエラーが発生しないことを確認できたら、Ctrl + C
でアプリを終了してください。
テストコードをJSからTSに変更
ここまでで、/cypress/integration
以下に存在するテストコードが、
JSファイルのままで良ければこれで終わりですが、TypeScript環境なので、やはりTSファイルとしてテストコードを書いていきたいところです。
試しに、サンプルのテストファイル(/cypress/integration/example_spec.js)の拡張子を.js
から.ts
に変更し、ついでに次の内容でサンプルのテストコードを上書きし、簡略化して保存します。
describe('Kitchen Sink', function () {
it('.should() - assert that <title> is correct', function () {
cy.visit('https://example.cypress.io');
cy.title().should('include', 'Kitchen Sink');
});
});
しかし、この状態でアプリを再起動しようとすると、次のようなエラーが発生するかと思います。
Failed to compile.
/cypress/integration/example_spec.ts
(17,5): Cannot find name 'cy'.
これはTypeScriptのコンパイル時において、example_spec.ts
に書かれているテストコードで、インストールされた型定義ファイル(/node_modules/cypress/types/index.d.ts
)から、CypressのAPIにアクセスするための定数cy
を読み込んで使おうとしますが、型定義ファイルが参照できず、cy
が見つからないことでエラーになってしまっています。
こちらのエラーを回避するためには、型定義ファイルもコンパイルの対象に含めるようにします。
TypeScriptのコンパイル設定を変更
プロジェクトルートに存在するtsconfig.json
をエディタで開き、compilerOptionsに並ぶ形で、include
(コンパイルに含めるもの)とexclude
(コンパイルに含めないもの)の設定を追加変更します。
create-react-app
でアプリを作成した場合は、デフォルトでexclude
にnode_modules
が指定されてしまっているので、コメントアウトまたは削除で、指定から外しておきます。
{
"compilerOptions": {
...
},
"include": [
"node_modules/cypress/types/*.ts",
"cypress/*/*.ts"
],
"exclude": [
// "node_modules",
...
]
}
設定を保存し、アプリを再起動します。
アプリの再起動が確認できたら、アプリを終了し、npx cypress open
で、Cypressの起動〜テスト実行も確認します。
これで無事に、TypeScriptで書いたテストコードでCypressが動くようになるはず、です。
ここまでのコードは、次の場所に置いてあります。
git clone後、プロジェクトルートに移動してnpm install
でパッケージをインストールすると、アプリの起動〜Cypressのテストが実行可能です。
今後は、このような面倒くさい設定をしなくてもTypeScriptでテストが書けるように、TypeScriptのサポートを厚くしてくれることをCypressに期待しています。