Playwrightのレポート機能を調べてみた

Allureで作成したレポート。おそらく気軽にやるならこれが一番いい。

Playwrightで作成できるレポートを調べてみました。公式ドキュメントはPlaywright Test Reportersです。結論をいうと、簡単にファイル出力するだけならAllureが一番よかったです。

Listレポーター

シンプルな箇条書き形式。

npx playwright test ./tests/sample.spec.ts --reporter=list

Running 3 tests using 3 workers

  ✘  1 [Google Chrome] › sample.spec.ts:27:5 › faied test (30.0s)
  ✓  2 [Google Chrome] › sample.spec.ts:14:5 › get agile link (592ms)
  ✓  3 [Google Chrome] › sample.spec.ts:5:5 › has title (470ms)


  1) [Google Chrome] › sample.spec.ts:27:5 › faied test ────────────────────────────────────────────

    Test timeout of 30000ms exceeded.

    Error: locator.click: Test timeout of 30000ms exceeded.
    Call log:
      - waiting for locator('a').filter({ hasText: /^Non-existent element$/ })


      31 |
      32 |   // クリックできないところをクリック
    > 33 |   await page.locator('a', { hasText: /^Non-existent element$/, timeout: 1000 }).click();
         |                                                                  ^
      34 | });
      35 |

        at /Users/daipresents/Work/playwright/tests/sample.spec.ts:33:66

  1 failed
    [Google Chrome] › sample.spec.ts:27:5 › faied test ─────────────────────────────────────────────
  2 passed (30.6s)

以下のように設定すれば、ステップを設定してそれごとに出力もできる。

import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [['list', { printSteps: true }]],
});

Lineレポーター

Listよりシンプル。

npx playwright test ./tests/sample.spec.ts --reporter=line

Running 3 tests using 3 workers
  1) [Google Chrome] › sample.spec.ts:27:5 › faied test ────────────────────────────────────────────

    Test timeout of 30000ms exceeded.

    Error: locator.click: Test timeout of 30000ms exceeded.
    Call log:
      - waiting for locator('a').filter({ hasText: /^Non-existent element$/ })


      31 |
      32 |   // クリックできないところをクリック
    > 33 |   await page.locator('a', { hasText: /^Non-existent element$/ }).click();
         |                                                                  ^
      34 | });
      35 |

        at /Users/daipresents/Work/playwright/tests/sample.spec.ts:33:66

  1 failed
    [Google Chrome] › sample.spec.ts:27:5 › faied test ─────────────────────────────────────────────
  2 passed (30.5s)

Dotレポーター

あんまり便利に思ったことはないけど、わかりやすいっちゃわかりやすい。

npx playwright test ./tests/sample.spec.ts --reporter=dot 

Running 3 tests using 3 workers
··T

  1) [Google Chrome] › sample.spec.ts:27:5 › faied test ────────────────────────────────────────────

    Test timeout of 30000ms exceeded.

    Error: locator.click: Test timeout of 30000ms exceeded.
    Call log:
      - waiting for locator('a').filter({ hasText: /^Non-existent element$/ })


      31 |
      32 |   // クリックできないところをクリック
    > 33 |   await page.locator('a', { hasText: /^Non-existent element$/ }).click();
         |                                                                  ^
      34 | });
      35 |

        at /Users/daipresents/Work/playwright/tests/sample.spec.ts:33:66

  1 failed
    [Google Chrome] › sample.spec.ts:27:5 › faied test ─────────────────────────────────────────────
  2 passed (30.6s)

HTMLレポーター

基本これで十分デバッグできるけど、後に紹介するサードパーティーツールやサービスを使ったほうがきれいなレポートになる。

npx playwright test ./tests/sample.spec.ts --reporter=html

Running 3 tests using 3 workers
  1) [Google Chrome] › sample.spec.ts:27:5 › faied test ────────────────────────────────────────────

    Test timeout of 30000ms exceeded.

    Error: locator.click: Test timeout of 30000ms exceeded.
    Call log:
      - waiting for locator('a').filter({ hasText: /^Non-existent element$/ })


      31 |
      32 |   // クリックできないところをクリック
    > 33 |   await page.locator('a', { hasText: /^Non-existent element$/ }).click();
         |                                                                  ^
      34 | });
      35 |

        at /Users/daipresents/Work/playwright/tests/sample.spec.ts:33:66

  1 failed
    [Google Chrome] › sample.spec.ts:27:5 › faied test ─────────────────────────────────────────────
  2 passed (30.6s)

  Serving HTML report at http://localhost:9323. Press Ctrl+C to quit.

レポートを開くときはnpx playwright show-report を叩く。

HTMLレポートのサンプル
失敗したタイミングでスクリーンショットも追加可能。

BLOBレポーター

コンソールの出力は特に変化なし。ただし、テストに関係する情報(Chromeなどが取得しているネットワーク情報など)を集めたBLOBファイルをZip形式で出力してくれる(場所:blob-report/report.zip)。レポートとしてみるというより、このデータを材料として使って別ツールやサービスでレポートを作るイメージ。

npx playwright test ./tests/sample.spec.ts --reporter=blob

Running 3 tests using 3 workers
  1) [Google Chrome] › sample.spec.ts:27:5 › faied test ────────────────────────────────────────────

    Test timeout of 30000ms exceeded.

    Error: locator.click: Test timeout of 30000ms exceeded.
    Call log:
      - waiting for locator('a').filter({ hasText: /^Non-existent element$/ })


      31 |
      32 |   // クリックできないところをクリック
    > 33 |   await page.locator('a', { hasText: /^Non-existent element$/ }).click();
         |                                                                  ^
      34 | });
      35 |

        at /Users/daipresents/Work/playwright/tests/sample.spec.ts:33:66

  1 failed
    [Google Chrome] › sample.spec.ts:27:5 › faied test ─────────────────────────────────────────────
  2 passed (30.6s)

JSONレポーター

これも結果データを加工したいときに使えそう。

npx playwright test ./tests/sample.spec.ts --reporter=json
{
  "config": {
    "configFile": "/Users/daipresents/Work/playwright/playwright.config.ts",
    "rootDir": "/Users/daipresents/Work/playwright/tests",
    "forbidOnly": false,
    "fullyParallel": true,
    "globalSetup": null,
    "globalTeardown": null,
    "globalTimeout": 0,
    "grep": {},
    "grepInvert": null,
    "maxFailures": 0,
    "metadata": {
      "actualWorkers": 3
    },
    "preserveOutput": "always",
    "reporter": [
      [
        "json"
      ]
    ],
    "reportSlowTests": {
      "max": 5,
      "threshold": 15000
    },
    "quiet": false,
    "projects": [
      {
        "outputDir": "/Users/daipresents/Work/playwright/test-results",
        "repeatEach": 1,
        "retries": 0,
        "id": "Google Chrome",
        "name": "Google Chrome",
        "testDir": "/Users/daipresents/Work/playwright/tests",
        "testIgnore": [],
        "testMatch": [
          "**/*.@(spec|test).?(c|m)[jt]s?(x)"
        ],
        "timeout": 30000
      }
    ],
    "shard": null,
    "updateSnapshots": "missing",
    "version": "1.41.1",
    "workers": 5,
    "webServer": null
  },
  "suites": [
    {
      "title": "sample.spec.ts",
      "file": "sample.spec.ts",
      "column": 0,
      "line": 0,
      "specs": [
        {
          "title": "has title",
          "ok": true,
          "tags": [],
          "tests": [
            {
              "timeout": 30000,
              "annotations": [],
              "expectedStatus": "passed",
              "projectId": "Google Chrome",
              "projectName": "Google Chrome",
              "results": [
                {
                  "workerIndex": 0,
                  "status": "passed",
                  "duration": 463,
                  "errors": [],
                  "stdout": [],
                  "stderr": [],
                  "retry": 0,
                  "startTime": "2024-02-21T07:50:52.556Z",
                  "attachments": []
                }
              ],
              "status": "expected"
            }
          ],
          "id": "b92766bcf73bd5c029a8-aceec34c6ede2bf0c566",
          "file": "sample.spec.ts",
          "line": 5,
          "column": 5
        },
        {
          "title": "get agile link",
          "ok": true,
          "tags": [],
          "tests": [
            {
              "timeout": 30000,
              "annotations": [],
              "expectedStatus": "passed",
              "projectId": "Google Chrome",
              "projectName": "Google Chrome",
              "results": [
                {
                  "workerIndex": 1,
                  "status": "passed",
                  "duration": 587,
                  "errors": [],
                  "stdout": [],
                  "stderr": [],
                  "retry": 0,
                  "startTime": "2024-02-21T07:50:52.556Z",
                  "attachments": []
                }
              ],
              "status": "expected"
            }
          ],
          "id": "b92766bcf73bd5c029a8-d15b4972ea9764541107",
          "file": "sample.spec.ts",
          "line": 14,
          "column": 5
        },
        {
          "title": "faied test",
          "ok": false,
          "tags": [],
          "tests": [
            {
              "timeout": 30000,
              "annotations": [],
              "expectedStatus": "passed",
              "projectId": "Google Chrome",
              "projectName": "Google Chrome",
              "results": [
                {
                  "workerIndex": 2,
                  "status": "timedOut",
                  "duration": 30000,
                  "error": {
                    "message": "\u001b[31mTest timeout of 30000ms exceeded.\u001b[39m"
                  },
                  "errors": [
                    {
                      "message": "\u001b[31mTest timeout of 30000ms exceeded.\u001b[39m"
                    },
                    {
                      "location": {
                        "file": "/Users/daipresents/Work/playwright/tests/sample.spec.ts",
                        "column": 66,
                        "line": 33
                      },
                      "message": "Error: locator.click: Test timeout of 30000ms exceeded.\nCall log:\n  \u001b[2m- waiting for locator('a').filter({ hasText: /^Non-existent element$/ })\u001b[22m\n\n\n\u001b[0m \u001b[90m 31 |\u001b[39m\u001b[0m\n\u001b[0m \u001b[90m 32 |\u001b[39m   \u001b[90m// クリックできないところをクリック\u001b[39m\u001b[0m\n\u001b[0m\u001b[31m\u001b[1m>\u001b[22m\u001b[39m\u001b[90m 33 |\u001b[39m   \u001b[36mawait\u001b[39m page\u001b[33m.\u001b[39mlocator(\u001b[32m'a'\u001b[39m\u001b[33m,\u001b[39m { hasText\u001b[33m:\u001b[39m \u001b[35m/^Non-existent element$/\u001b[39m })\u001b[33m.\u001b[39mclick()\u001b[33m;\u001b[39m\u001b[0m\n\u001b[0m \u001b[90m    |\u001b[39m                                                                  \u001b[31m\u001b[1m^\u001b[22m\u001b[39m\u001b[0m\n\u001b[0m \u001b[90m 34 |\u001b[39m })\u001b[33m;\u001b[39m\u001b[0m\n\u001b[0m \u001b[90m 35 |\u001b[39m\u001b[0m\n\n\u001b[2m    at /Users/daipresents/Work/playwright/tests/sample.spec.ts:33:66\u001b[22m"
                    }
                  ],
                  "stdout": [],
                  "stderr": [],
                  "retry": 0,
                  "startTime": "2024-02-21T07:50:52.556Z",
                  "attachments": []
                }
              ],
              "status": "unexpected"
            }
          ],
          "id": "b92766bcf73bd5c029a8-c164d0bddc9f214bc244",
          "file": "sample.spec.ts",
          "line": 27,
          "column": 5
        }
      ]
    }
  ],
  "errors": [],
  "stats": {
    "startTime": "2024-02-21T07:50:52.330Z",
    "duration": 30590.01,
    "expected": 2,
    "skipped": 0,
    "unexpected": 1,
    "flaky": 0
  }
}

JUnitレポーター

JUnitで使われるXML形式はJenkinsなど様々な場所で活用できるフォーマット。

npx playwright test ./tests/sample.spec.ts --reporter=junit
<testsuites id="" name="" tests="3" failures="1" skipped="0" errors="0" time="30.754874">
<testsuite name="sample.spec.ts" timestamp="2024-02-21T11:48:21.690Z" hostname="Google Chrome" tests="3" failures="1" skipped="0" time="32.084" errors="0">
<testcase name="has title" classname="sample.spec.ts" time="0.512">
</testcase>
<testcase name="get agile link" classname="sample.spec.ts" time="1.572">
</testcase>
<testcase name="faied test" classname="sample.spec.ts" time="30">
<failure message="sample.spec.ts:29:5 faied test" type="FAILURE">
<![CDATA[  [Google Chrome] › sample.spec.ts:29:5 › faied test ───────────────────────────────────────────────

    Test timeout of 30000ms exceeded.

    Error: locator.click: Test timeout of 30000ms exceeded.
    Call log:
      - waiting for locator('a').filter({ hasText: /^Non-existent element$/ })


      33 |
      34 |   // クリックできないところをクリック
    > 35 |   await page.locator('a', { hasText: /^Non-existent element$/ }).click();
         |                                                                  ^
      36 | });
      37 |

        at /Users/daipresents/Work/playwright/tests/sample.spec.ts:35:66

    attachment #1: screenshot (image/png) ──────────────────────────────────────────────────────────
    test-results/sample-faied-test-Google-Chrome/failure.png
    ────────────────────────────────────────────────────────────────────────────────────────────────
]]>
</failure>
<system-out>
<![CDATA[
[[ATTACHMENT|../test-results/sample-faied-test-Google-Chrome/failure.png]]
]]>
</system-out>
</testcase>
</testsuite>
</testsuites>

サードパーティーレポーター

Playwrightはサードパーティーツールを使ってレポート生成できる。

Allure

ダウンロード数を見る限り一番人気に見える。

  1. Link

インストール方法は以下。

# For Mac
brew install allure

# Windows is here: https://allurereport.org/docs/gettingstarted-installation/#install-via-scoop-for-windows

# Install package
npm i -D @playwright/test allure-playwright

実行してレポート生成して開く。 レポートはデフォルトallure-resultsに生成される。

npx playwright test ./tests/sample.spec.ts --reporter=allure-playwright
allure generate ./allure-results --clean && allure open ./allure-report

Allureを使ってスクリーンショットを取る場合は以下のように書く。

import { allure } from "allure-playwright";

test('has title', async ({ page }) => {
  ...

  // Take a screenshot
  await allure.attachment("basic-page-screen", await page.screenshot(), {
    contentType: "image/png",
  });

  ...
});

レポートのイメージは以下。

SaaSなどの利用をのぞいた場合、見た目はAllureが一番わかり易い。
エラー時のスクリーンショットもばっちり。これだけでデバッグが捗りそう。

Currents

レポーティングサービスなので調べず。

  1. Link

Monocart

Allureと比べると派手さがない。

  1. Link

インストールは以下のように簡単。

npm i -D monocart-reporter

以下のように実行してレポートを開く。

npx playwright test ./tests/sample.spec.ts --reporter=monocart-reporter
[MR] generating report data ...
[MR] generating test report ...
[MR] Test Report
┌─────────────┬────────────────────┐
│ Tests       │ 3                  │
│ ├ Passed    │ 2 (66.7%)          │
│ ├ Flaky     │ 0 (0.0%)           │
│ ├ Skipped   │ 0 (0.0%)           │
│ └ Failed    │ 1 (33.3%)          │
│ Steps       │ 38                 │
│ Suites      │ 1                  │
│ ├ Projects  │ 1                  │
│ ├ Files     │ 1                  │
│ ├ Describes │ 0                  │
│ └ Shards    │ 0                  │
│ Retries     │ 0                  │
│ Errors      │ 2                  │
│ Logs        │ 0                  │
│ Attachments │ 0                  │
│ Artifacts   │ 0                  │
│ Playwright  │ v1.41.2            │
│ Date        │ 2024/2/21 17:38:43 │
│ Duration    │ 31.7s              │
└─────────────┴────────────────────┘
[MR] html report: test-results/report.html (json: test-results/report.json)
[MR] view report: npx monocart show-report test-results/report.html

# Open the report.
npx monocart show-report test-results/report.html

レポートは以下のようになる。

ReportPortal

AIを使って解析してくれるサービス。Dockerでセルフホストできるらしいのでまたの機会に調べたい。

  1. Link

Serenty/JS

オープンソースの受け入れテストフレームワーク。

  1. Link: https://serenity-js.org/handbook/test-runners/playwright-test/

Testmo

テスト管理ツールサービスのレポーティング機能に繋げられるらしい。自動テストと手動テストの管理が便利そう。

  1. Link: https://github.com/jonasclaes/playwright-testmo-reporter

Testomat.io

こちらもテスト管理サービス。

  1. Link:

Tesults

こちらもテスト管理サービス。管理サービスがレポーティング機能を提供する形が流行っている模様。

  1. Link

“Playwrightのレポート機能を調べてみた” への 1 件のフィードバック

  1. […] ReportPortalは自動テスト結果の分析や、リアルタイムモニタリングを行うサービス。AIを活用したダッシュボードを簡単に作成できる。こういったレポート作成はPlaywrightだとAllureで十分だけど、作成したレポートをどこにホスティングするか設計する必要がある。その点、こういったダッシュボードサービスを使えば、パーマリンクが作成されるので、そのURLをみんなで共有すればいい。 […]

    いいね

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください