Report Playwright results as they run
@plune-ai/playwright is a Playwright reporter: it sends results to the Plune platform while
the suite runs, instead of parsing a report afterwards.
v0.2.2no runtime depsNode ≥ 20
-
Install it beside the Playwright you already have:
Terminal window npm install --save-dev @plune-ai/playwrightnpx plune login # from @plune-ai/cli — saves your API token -
Add it as a reporter:
playwright.config.ts import { defineConfig } from "@playwright/test";export default defineConfig({reporter: [["list"], ["@plune-ai/playwright"]],});
That is the whole setup. Everything below is for cases the default does not cover.
In CI, without editing the config
Section titled “In CI, without editing the config”A committed config cannot know the run key of a job that does not exist yet, so the environment fills in what the file left out — and anything set in the file wins.
env: PLUNE_TOKEN: ${{ secrets.PLUNE_TOKEN }} PLUNE_RUN: ${{ github.run_id }}-${{ github.run_attempt }} PLUNE_ENV: staging PLUNE_LABELS: smoke,nightly| Variable | What it does |
|---|---|
PLUNE_TOKEN | the API token, so a CI job need not run plune login |
PLUNE_RUN | the shared run key — every process with the same value lands in one run |
PLUNE_API_URL | which deployment to report to |
PLUNE_SHARED_RUN | this process is one of several — do not close the run |
PLUNE_PROCEED | the job closes the run itself, later |
PLUNE_BATCH_SIZE | results per request (default 100, max 500) |
PLUNE_RUN_TITLE · PLUNE_ENV · PLUNE_LABELS | what the run is called, where it ran, how it is marked |
PLUNE_CREATE | offer tests Plune has no case for to the review queue |
Flags are read by value, not by presence: PLUNE_PROCEED=0 in a matrix cell means off, not on.
Sharding
Section titled “Sharding”Give every shard the same key and they land in one run rather than one run each:
env: PLUNE_RUN: ${{ github.run_id }}-${{ github.run_attempt }} PLUNE_SHARED_RUN: "1"The Playwright test id is stable across shards and merges, which is what makes the same test in shard 3 of 8 resolve to the same case it resolved to yesterday.
How a result finds its case
Section titled “How a result finds its case”First match wins:
-
A
PluneIdannotation — names the case outright.test("rejects a negative quantity",{ annotation: { type: "PluneId", description: "tc-1a2b" } },async ({ page }) => { /* … */ }); -
A
@P<id>token in the title — the same statement, where you can read it in the report. No space after@P:@Ptc-1a2b. -
An
application/plune.metadata+jsonattachment — for a fixture that knows the id, or a key from another tool:{"keys": [{"kind": "qase", "value": "Q-9"}]}. -
The Playwright test id — stable across shards.
-
File and title path —
cart.spec.ts#cart#rejects a negative quantity.
A result that matches no case is not sent and not invented. A made-up id would write into some
other test’s history, which is worse than a gap; the run summary counts them instead. To turn those
into proposals, set PLUNE_CREATE=1 — they reach the
review queue and wait for a person.
When Plune is unreachable
Section titled “When Plune is unreachable”Nothing is lost and nothing fails. An unreachable platform, a refused token or an already-closed run
all append the batch to .plune/pending-results.jsonl, print one line saying so, and let your suite
exit with its own code. Your tests do not depend on our uptime.
What it deliberately does not decide
Section titled “What it deliberately does not decide”The status. Playwright’s own word — passed, failed, timedOut, interrupted, skipped — goes
to Plune as-is, and the project maps it. So your team can decide a timeout counts as broken
(the default) or as something else, and change its mind, without waiting for a release of this
package.