skip to content

In Playwright, how do you run one suite with several reporters at once and give each its own options?

level: juniorimportance: must knowfreq 72%

answer

  1. One run, several outputs
  2. The config value is not just a string
  3. Each entry carries its own settings
  4. Name plus options object per entry
  5. Command line form drops the options

basics

~20 s

Set the reporter config option to an array of entries, each a reporter name plus an options object - for example list, junit with an outputFile, and html. The command line --reporter takes comma-separated names but carries no options.

solid answer

~40 s

Playwright's `reporter` option accepts either a single name or an array of `[name, options]` entries, and every entry runs against the same run. A typical CI setup is `[['list'], ['junit', { outputFile: 'results/junit.xml' }], ['html', { open: 'never' }]]`: one readable terminal stream plus two artifacts. Only the array form can carry options, so `reporter: 'junit'` leaves the XML on stdout. Keep exactly one terminal reporter in the list - `list`, `line` and `dot` all write to stdout and interleave badly. The `--reporter` flag accepts a comma-separated list such as `--reporter=line,json`, but it replaces the configured reporters entirely and cannot pass options, so file reporters then fall back to their environment variables or to stdout.

code

typescript · 11 lines
typescript
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [
    ['list'],
    ['junit', { outputFile: 'results/payroll-junit.xml' }],
    ['json', { outputFile: 'results/payroll.json' }],
    ['html', { outputFolder: 'results/html', open: 'never' }],
  ],
});

go deeper

for a junior

Remember the shape: reporter takes an array, and each entry is a reporter name optionally followed by an options object. One terminal reporter plus one file reporter covers almost every run.

for a middle

Explain that options only exist in the array form, that the command line flag replaces rather than extends the configured list, and that a file reporter with no output file falls back to stdout.

for a senior

Decide what each pipeline stage actually consumes - XML for the CI test tab, an HTML folder for humans - and make sure every artifact lands in a path the job archives.

for a principal

Own the cost side. Each extra reporter is another artifact to store and another format someone must keep parsing, so standardise one terminal and one machine format across suites instead of per-team invention.

## What the `reporter` option accepts Playwright's `reporter` option in `playwright.config.ts` is either a single reporter name (`reporter: 'line'`) or an **array of entries**, where each entry is itself an array of `[name, options]`. Every entry in that array watches the same run and receives the same events, so one command can stream progress into the job log while writing an XML file and an HTML folder for whatever reads them afterwards. Nothing has to be run twice, and the built-ins do not conflict with each other as long as only one of them is writing progress to the terminal. ## Options exist in the array form only - `reporter: 'junit'` is legal but takes no options, so the JUnit reporter has no `outputFile` and writes its XML to stdout, tangled into whatever else is printing. - `reporter: [['junit', { outputFile: 'results/junit.xml' }]]` is the form that configures a built-in from the config file — note the nested array even for a single entry. - The same entry shape names your own module: `['./payroll-reporter.ts', { threshold: 5 }]`, and the options object is handed to that class's constructor. - Options are per entry, never global; two `html` entries would need two different `outputFolder` values. ## Where each built-in sends its output | Reporter | Output | Common options | | --- | --- | --- | | `list` | one line per test in the terminal | `printSteps` | | `line` | a single updating line, failures as they occur | — | | `dot` | one character per test | — | | `html` | a folder of files, `playwright-report` by default | `outputFolder`, `open` | | `json` | one JSON document, stdout unless `outputFile` | `outputFile` | | `junit` | JUnit XML, stdout unless `outputFile` | `outputFile` | | `blob` | a zipped archive of the run under `blob-report` | `outputDir`, `fileName` | | `github` | GitHub Actions annotations for failures | — | | `null` | nothing at all | — | ## Keep exactly one reporter on the terminal Two progress reporters both write to stdout, so `[['list'], ['dot']]` interleaves two streams into a log nobody can read. The arrangement that works is one terminal reporter for the human reading the job output, plus as many file-writing reporters as the pipeline actually consumes. A file reporter with no output file falls back to stdout, which is the usual reason a CI job ends with JUnit XML spliced through the progress lines. ## Overriding from the command line 1. `--reporter=dot` replaces whatever the config sets, for that invocation only — it does not add to the configured list. 2. It accepts a comma-separated list, so `--reporter=line,json` runs both. 3. It cannot carry options. Anything that needs a path then falls back to an environment variable — `PLAYWRIGHT_JUNIT_OUTPUT_NAME`, `PLAYWRIGHT_JSON_OUTPUT_NAME`, `PLAYWRIGHT_HTML_OUTPUT_DIR` — or accepts stdout. ## Choosing the set for a payroll regression job Pick reporters by consumer, not by taste. For a large payroll suite running in CI that usually means: - one terminal reporter so the job log is readable at all; - `junit` with an `outputFile` under a path the job archives, because that is what most CI systems parse into a test tab; - `html` with `open: 'never'` into its own folder, for the engineer who has to look at a failure; - `json` only when something downstream genuinely parses it — otherwise it is a second copy of data nobody reads; - `null` in the rare job that only cares about the exit code, such as a warm-up run. The array is also where a bespoke reporter joins in without displacing the others: list it alongside `list` and `html`, and all three run on the same events.

  • What happens to the JUnit and JSON reporters if you pass --reporter=junit,json on the command line instead of configuring them?
    The flag replaces the config's reporter list and carries no options, so neither has an `outputFile` and both write to stdout - two documents interleaved in one stream. If you must drive them from the command line, set `PLAYWRIGHT_JUNIT_OUTPUT_NAME` and `PLAYWRIGHT_JSON_OUTPUT_NAME` so each writes to a file instead.
  • Can you list two terminal reporters, such as list and dot, in the same reporter array?
    Nothing stops you and both will run, but both write to stdout, so you get two interleaved progress streams that are harder to read than either alone. Keep one stdio reporter and add file-writing ones beside it. A custom reporter that does not print should return `false` from `printsToStdio()` so Playwright knows it may add its own output.

saying these in an interview costs you the question

  • Thinks only one reporter can be active per run
  • Tries to pass reporter options through the --reporter flag
  • Believes --reporter adds to the configured reporters instead of replacing them
  • Expects JUnit XML on disk without an outputFile or its environment variable
  • Assumes the html reporter also produces machine-readable XML for CI