Merv-Local + Playwright guide

Introduction

Playwright Test is an end-to-end framework for modern web apps. Merv-Local adds rich HTML/JSON reports, a run dashboard, and Java-style plugin steps on top of your existing Playwright project via the merv-client npm package.

You will learn
  • How to install and configure merv-client
  • What gets created under your report folder
  • How to run tests and open the Merv dashboard
  • How to keep import from '@playwright/test' (Option A)
  • How to add data, validation, and info rows in reports

Installing merv-client

From your Playwright project root (where package.json and playwright.config live), add the package:

npm install -D merv-client

merv-client expects @playwright/test ≥ 1.40.0 as a peer dependency. Use Node.js versions supported by your Playwright release.

What’s installed

Merv does not replace Playwright. After you configure the reporter and run tests, each execution creates a timestamped folder under merv.report.folder:

merv-reports/ index.html # Dashboard (all runs) merv-index-data.json # Polled by live dashboard 15-05-2026 14-23-41 Merv-Report/ json/merv-report.json # Suite + testcase data html/merv-report.html # Final suite report html/merv-report-live.html # Live report during run screenshots/ # Step images

playwright.config stays your central Playwright configuration (browsers, timeouts, projects). Add one reporter entry for Merv alongside list or the built-in HTML reporter — use ['merv-client/playwright-reporter', {}] (see Register the reporter).

Testcase tags are filled automatically: any @word in the test title becomes a tag (e.g. Verify Login @login with @abc@login, @abc). When the title or Playwright project name contains chromium, the browser tag chrome is added for consolidated and KPI filters.

Configure merv.properties

Create merv.properties next to package.json. The reporter and test wrapper read it from the project root (or an ancestor directory).

Minimal configuration

merv.local=true
merv.regression_suite=Playwright Regression
merv.report.folder=./merv-reports/

Common properties

Property Role
merv.report.folder Root for timestamped run folders.
merv.regression_suite Suite title in JSON and HTML.
merv.screenshot=true Viewport PNG after major Playwright actions and after each expect() matcher (requires wrapped test / expect from merv-client/playwright-test).
merv.debug=true Include hooks, fixtures, and all test.step categories in the report.
merv.report.extra_step_types Surface tagged test.step types when debug is off.
merv.plugin_assertion_soft=true Record failed plugin validations without failing the Playwright test.

Register the reporter

In playwright.config.js or playwright.config.ts, register Merv in the reporter array using the dedicated subpath merv-client/playwright-reporter — not the root merv-client package. Playwright loads config before your tests run; the subpath loads only the reporter entry point and avoids pulling in the wrapped test shim (which can trigger “Requiring @playwright/test second time” warnings).

Reporter entry (required)

reporter: [
  ['list'],
  ['merv-client/playwright-reporter', {}],
],

Full playwright.config example

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

export default defineConfig({
  testDir: './tests',
  reporter: [
    ['list'],
    ['merv-client/playwright-reporter', {}],
  ],
  use: {
    // baseURL, trace, screenshot, …
  },
});
Do: ['merv-client/playwright-reporter', {}] in reporter: [].
Don’t: import … from 'merv-client' in playwright.config to register the reporter — use the subpath string only.

Running your tests

Run from the directory that contains merv.properties. By default Playwright runs headless; Merv writes JSON and refreshes reports as tests complete.

npx playwright test
Tips: See the browser: npx playwright test --headed. Run one file: npx playwright test tests/example.spec.js. Open UI mode: npx playwright test --ui.

With only the reporter registered, you can keep import { test, expect } from '@playwright/test' — the report shows Playwright API and expect steps. For plugin steps and screenshots, use the wrapped test (see below).

Viewing Merv reports

After a run, reports live under {merv.report.folder} (for example ./merv-reports/). Open these paths through a local web server — not by double-clicking HTML in the file manager (file://).

Open with a web server

Merv-Local reports load JSON, charts, and screenshots with fetch. Browsers often block that on file:// URLs. Use your IDE’s built-in static server (or any local HTTP server) so the address bar shows http://localhost:….

  1. Install the Live Server extension (search Live Server in the Extensions view).
  2. In the Explorer, open your report folder (for example merv-reports/).
  3. Right-click index.html and choose Open with Live Server (or click Go Live in the status bar when that folder is the workspace root).
  4. Your browser opens something like http://127.0.0.1:5500/merv-reports/index.html — use that URL for the dashboard.
  5. For one run: open {runFolder}/html/merv-report.html or merv-report-live.html via the same server (from the dashboard links or by pasting the path after the Live Server host).
Tip: While tests run, keep merv-report-live.html open on Live Server. Merv blocks Live Server’s full-page reload when JSON changes; the live page and dashboard update in place instead of flashing a full refresh.

Other editors and CI

Any local static server works: for example npx serve merv-reports or python3 -m http.server --directory merv-reports, then open http://localhost:…/index.html. In CI, publish the merv-reports folder as an artifact and serve it from your pipeline’s report viewer or object storage with HTTP access.

Keep import from '@playwright/test'

Recommended for large suites: keep Playwright-style imports, but resolve them to Merv’s wrapped test via a one-time bridge (Option A). Pick your project language below.

  1. Create tests/support/playwright-test-bridge.js:
    export * from 'merv-client/playwright-test';
  2. Add jsconfig.json at the project root (strict JSON — no // comments):
    {
      "compilerOptions": {
        "baseUrl": ".",
        "allowJs": true,
        "checkJs": false,
        "paths": {
          "@playwright/test": ["./tests/support/playwright-test-bridge.js"]
        }
      },
      "include": [
        "playwright.config.js",
        "tests/**/*.js",
        "tests/support/**/*.js"
      ]
    }
  3. Add package.json imports (required for .js at runtime):
    {
      "type": "module",
      "imports": {
        "@playwright/test": "./tests/support/playwright-test-bridge.js"
      }
    }
  4. Import everything from @playwright/test in specs — including MervPlaywrightHandler:
    import { expect, test, MervPlaywrightHandler } from '@playwright/test';
  5. Verify: npx playwright test --list, then npm test.
Tip: Do not mix import { test } from '@playwright/test' with import { MervPlaywrightHandler } from 'merv-client' — plugin steps and screenshots need a single import source.

playwright.config still registers merv-client/playwright-reporter in reporter: [] — do not import the reporter from root merv-client in config.

Writing plugin steps

Use MervPlaywrightHandler with Playwright’s testInfo to add explicit rows merged into the same testcase as Playwright steps.

import { expect, test, MervPlaywrightHandler } from '@playwright/test';

test('checkout', async ({ page }, testInfo) => {
  const merv = new MervPlaywrightHandler(testInfo);

  await merv.data('Request', JSON.stringify({ sku: 'SKU-1' }));
  await merv.validation('Cart total', '$42.00', '$42.00', true);
  await merv.info('Environment: staging');

  await page.goto('/cart');
  await expect(page.getByRole('heading')).toBeVisible();
});
Method Role
data(name, testdata, screenshot?) TEST_DATA row. Pass true last for a viewport PNG.
validation(name, expected?, actual?, screenshot?) ASSERTION row. Pass true last for a viewport PNG.
info(text) Info / prerequisite row.

Configuration

Debug mode

By default each testcase shows Playwright API actions and expect steps. To include hooks, fixtures, and every test.step category:

merv.debug=true

Screenshots

Per plugin step — pass true as the last argument:

await merv.data('Order Id', '12349893', true);
await merv.validation('Status', '200', '200', true);

After Playwright actions and expect() — optional, in merv.properties:

merv.screenshot=true

Captures a viewport PNG after each locator/page action and after each expect matcher (pass or fail). Requires wrapped test and expect from merv-client/playwright-test (Option A or direct import).

Soft plugin failure

Record a failed validation in the report without failing the Playwright test:

merv.plugin_assertion_soft=true

MervReport (explicit)

Use MervReport when you want the same folder layout and JSON contract without registering the Playwright reporter — for scripts or hand-built testcase rows.

Setup

  1. Keep merv.properties at the project root.
  2. import { MervReport } from 'merv-client';
  3. const report = MervReport.open(); — creates a new run folder.

Report object

const report = MervReport.open();
report.createTest('Login API', 'POST /auth with valid user');
await report.validation('Status code', '200', '200');
report.finalize();

Step object

Each step row in JSON includes teststepName, stepType, status, optional expected / actual, testdata, screenshots, and errorMessage when applicable.

Troubleshooting

Issue What to check
No reports under merv.report.folder ['merv-client/playwright-reporter', {}] in config; merv.properties on disk; run from project root.
Plugin steps missing Import wrapped test (Option A or merv-client/playwright-test); import MervPlaywrightHandler from the same source.
data(…, true) has no screenshot Rebuild merv-client; use wrapped test; call after page exists.
Option A not applied Add package.json imports; valid jsconfig.json (no comments).

What’s next

← Back to Documentation