Skip to content

Playwrightでカバレッジレポートを出す

Published: at 16:46

TypeScript + Create React App + Playwrightでカバレッジレポートを出してみた。

サンプルアプリケーション

https://github.com/takaneko/fata-cra-playwright-coverage

テストを実行すると、jestで--collect-coverageオプションを付けた時のようにサマリーが出力される。

$ npm run test:e2e:coverage

Running 2 tests using 1 worker

  App.test.ts:39:1 Show initial page. (3s)
  App.test.ts:51:1 Input message and enter, push messages to table. (770ms)


  2 passed (8s)
---------------------|---------|----------|---------|---------|-------------------
File                 | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------------|---------|----------|---------|---------|-------------------
All files            |   86.48 |    81.81 |    87.5 |   86.48 |
 src                 |   72.22 |       60 |      75 |   72.22 |
  App.tsx            |   71.05 |      100 |   66.66 |   71.05 | 28-38
  index.tsx          |     100 |      100 |     100 |     100 |
  reportWebVitals.ts |      40 |    33.33 |     100 |      40 | 4-12
 src/components      |     100 |      100 |     100 |     100 |
  MessageForm.tsx    |     100 |      100 |     100 |     100 |
  Messages.tsx       |     100 |      100 |     100 |     100 |
---------------------|---------|----------|---------|---------|-------------------

HTMLレポートも一緒に出力している。

coverage/index.html

Playwright

E2Eテストフレームワークで、複数ブラウザでテスト出来る。 PWDEBUG=trueを指定した時のデバッグモードがめちゃくちゃわかりやすい。

Playwright Coverage

今はChromiumターゲット時のみカバレッジが取得できる。 ドキュメントの実装例をもとにサンプルアプリケーションでは、

  1. globalSetupでカバレッジディレクトリを掃除する
  2. test.beforeEachpage.coverage.startJSCoverageを実行する(headlessブラウザ上でカバレッジ計測する)
  3. test.afterEachpage.coverage.stopJSCoverageを実行してカバレッジJSONを書き出す
  4. globalTeardownでテストケースごとのカバレッジJSONを.nyc_output/out.jsonにマージする
  5. npm script(test:e2e:coverage)でE2Eテスト後にレポート出力するコマンドを実行する

という流れを実装した。(割と自前で実装しないといけないことが多い)

つまづいた点

v8ToIstanbulでv8のカバレッジをIstanbul形式に変換するとき、SourceMapの解決に失敗した。

発生したエラー

1) App.test.ts:43:1 › Show initial page. =========================================================

  Error: An error occurred while trying to read the map file at /Users/takaneko/Practices/cra-playwright-coverage/bundle.js.map
  Error: ENOENT: no such file or directory, open '/Users/takaneko/Practices/cra-playwright-coverage/bundle.js.map'

    28 |         // sourceMap: { sourcemap: sourcemapConverter.sourcemap },
    29 |       });
  > 30 |       await converter.load();
       |                       ^
    31 |       converter.applyCoverage(entry.functions);
    32 |
    33 |       // Save coverage JSON for each test.

      at readFromFileMap (/Users/takaneko/Practices/cra-playwright-coverage/node_modules/convert-source-map/index.js:40:11)
      at new Converter (/Users/takaneko/Practices/cra-playwright-coverage/node_modules/convert-source-map/index.js:47:32)
      at Object.exports.fromMapFileComment (/Users/takaneko/Practices/cra-playwright-coverage/node_modules/convert-source-map/index.js:110:10)
      at Object.exports.fromMapFileSource (/Users/takaneko/Practices/cra-playwright-coverage/node_modules/convert-source-map/index.js:122:22)
      at V8ToIstanbul.load (/Users/takaneko/Practices/cra-playwright-coverage/node_modules/v8-to-istanbul/lib/v8-to-istanbul.js:52:66)
      at /Users/takaneko/Practices/cra-playwright-coverage/tests/App.test.ts:30:23

v8-to-istanbulが利用しているconvert-source-mapでは、webpack-dev-serverが生成するbundle.jsのsourceMappingURLを解決できないのでエラーになっている。

bundle.jsのsourceMappingURL

//# sourceMappingURL=bundle.js.map

このSourceMapはwebpack-dev-serverのメモリ上にしかないので、GETリクエストで取得する必要がある。 v8-to-istanbulには SourceMapを指定するオプションがあるので、webpack-dev-serverから取得したSourceMapを指定することで解決した。

test.afterEachの実装

// Get source map file from webpack-dev-server
const sourceMapResponse = await request.get(`${entry.url}.map`);
const sourcemapConverter = fromJSON(await sourceMapResponse.text());

// Convert from V8 coverage to istanbul format
const converter = v8ToIstanbul("", 0, {
  source: entry.source,
  originalSource: "",
  // set sourceMap
  sourceMap: { sourcemap: sourcemapConverter.sourcemap },
});

感想

フロントアプリのE2EテストはRailsや素のjestよりカバレッジ取得が面倒臭い。 Istanbul(JSのカバレッジツール)について少し詳しくなった。

次回

Playwrightでheadlessブラウザ上のIndexedDBを扱うヘルパーを作りたい。

参考文献