Custom report — hand-built suites, tests & steps

Introduction

Use a custom report when your automation is not wired through Cucumber, Cucumber-js, TestNG, JUnit, or the Playwright reporter — but you still want MERV suites, testcases, plugin-style steps, validation rows, test data, info lines, and screenshots in the same HTML dashboard or Merv App.

You will learn
  • How to open a report session and create testcases manually
  • How to add info, testdata, and validation steps
  • How to attach screenshots and files
  • Java (MervClient), JavaScript, and TypeScript (MervReport) examples

When to use a custom report

JavaScript / TypeScript packages: custom reports need only npm install merv-client. Install merv-client-playwright for Playwright Test, or merv-client-cucumber for Cucumber-js — not for hand-built MervReport scripts.

Automated setup (doctor)

For JavaScript / TypeScript projects, install core and run the core doctor. It creates or fills missing merv.* keys and a sample custom-report script without wiping unrelated settings.

npm install merv-client
npx merv-client doctor setup
npx merv-client doctor setup --typescript

Then run the generated script (or your own) and open the dashboard with npx merv show-report. Prefer manual setup below for full control.

Manual setup

Skip doctor and configure by hand: add merv.properties, then follow the language examples (Java / JS / TS) to call MervReport.open() (or Java MervClient) yourself.

merv.properties

Place merv.properties at the project root (directory you run from).

Sample Configuration (Merv-Local)

merv.local=true
merv.report.folder=./merv-reports/
merv.regression_suite=Custom Report Suite
merv.emailable.html=false

Download sample merv.properties

Common properties

Property Role
merv.local true — Merv-Local: write HTML/JSON reports on disk under merv.report.folder (no cloud API).
false — Merv-Server: send suites, cases, and steps to the MERV cloud API (set merv.server, API key, and hierarchy as well).
merv.report.folder Root for timestamped run folders and index.html dashboard.
merv.regression_suite Suite title in JSON and HTML.
merv.execution.parallel true — parallel workers share one suite folder safely.
false — single-threaded run (default for scripts).
merv.emailable.html true — write interactive emailable-report.html when the suite finishes (doctor defaults to false). See Share, Download & emailable.

Sample Configuration (Merv-Server)

merv.local=false
merv.server=https://merv.online/api/v1
merv.api_key=merv_your_api_key
merv.parent_hierarchy=your-hierarchy-uuid
merv.regression_suite=Custom Report Suite

Server setup: Merv-Server user guide. MervReport (npm) reads the same file for local or server mode.

API overview

Action JavaScript / TypeScript (MervReport) Java (MervClient — server mode)
Open session / suite await MervReport.open() MervClient.fromConfig() + createTestSuite(...)
Start testcase await report.createTest(name, desc) client.createTestCase(...)
Info / prerequisite await report.info(text) Step with prereq / information type
Test data await report.testdata(name, data) createTestStep with testdata
Validation await report.validation(name, expected, actual) createTestStep with expected / actual
Screenshot validation(..., true) or MervExplicitLocalReport client.uploadFile(stepId, file, ...)
Finish await report.finalize() updateTestCaseStatus(...) + close client
Local disk from Java: hand-built on-disk reports use MervReport in the npm merv-client package (JavaScript or TypeScript tabs below). From pure Java without a test runner, use Merv-Server with MervClient, or run a small Node script with MervReport for local HTML.

Examples by language

After the JS client split, custom reports use only merv-client (core). You do not install merv-client-playwright or merv-client-cucumber for this path. Those packages are for Playwright Test and Cucumber-js adapters.

Each tab shows a full custom-report flow: open suite → create test → add steps → finalize.

Use MervClient from any JVM app (main, Spring job, Gradle task) when merv.local=false. No Cucumber, TestNG, or JUnit required.

Maven dependency

<dependency>
  <groupId>io.github.techelliiptica</groupId>
  <artifactId>merv-client-api</artifactId>
  <version>4.0.22</version>
</dependency>

Custom report script

import org.teche.merv.client.MervClient;
import org.teche.merv.client.dto.*;
import org.teche.merv.client.exception.MervClientException;
import org.teche.merv.client.utils.MervSuiteBootstrap;
import org.teche.merv.client.utils.TestCaseBuilder;
import org.teche.merv.client.utils.TestStepBuilder;

import java.io.File;
import java.util.Properties;
import java.util.UUID;

public class CustomMervReport {
  public static void main(String[] args) throws Exception {
    try (MervClient client = MervClient.fromConfig()) {
      Properties props = new Properties();
      props.load(new java.io.FileInputStream("merv.properties"));

      UUID suiteId = MervSuiteBootstrap.resolveSuiteId(
          client, props, "Custom Report Suite");

      TestCaseResponse testCase = client.createTestCase(
          TestCaseBuilder.create()
              .testcaseName("Checkout API")
              .description("POST /checkout with valid cart")
              .testSuiteId(suiteId)
              .status(TestCaseStatus.INPROGRESS)
              .build());

      UUID caseId = testCase.getId();

      // Info / prerequisite step
      client.createTestStep(TestStepBuilder.create()
          .testcaseId(caseId)
          .teststepName("Environment")
          .stepType("information")
          .prereq("Using staging tenant STG-42")
          .status("PASSED")
          .build());

      // Test data step
      TestStepResponse dataStep = client.createTestStep(
          TestStepBuilder.create()
              .testcaseId(caseId)
              .teststepName("Request body")
              .stepType("testdata")
              .testdata("{\"cartId\":\"cart-991\",\"currency\":\"USD\"}")
              .status("PASSED")
              .build());

      // Validation step
      TestStepResponse validationStep = client.createTestStep(
          TestStepBuilder.create()
              .testcaseId(caseId)
              .teststepName("HTTP status")
              .stepType("assertion")
              .expected("200")
              .actual("200")
              .status("PASSED")
              .build());

      // Screenshot attachment on a step
      client.uploadFile(validationStep.getId(),
          new File("screenshots/checkout-response.png"),
          "Checkout response UI");

      client.updateTestCaseStatus(caseId, TestCaseStatus.PASSED);
    }
  }
}

Run from the directory that contains merv.properties. Results appear in the Merv App.

Step types

Method JSON stepType Shown in HTML as
info(...) PREREQUISITE / information Info / prerequisite row
testdata(...) TEST_DATA Test data block (inline text or file preview)
validation(...) ASSERTION Expected vs actual; fails testcase when values differ

Call createTest once per logical testcase. Add as many steps as you need before starting the next test or calling finalize().

Screenshots & file attachments

JavaScript / TypeScript — Playwright page bound

When a Playwright page is bound via MervPlaywright.setAutomationToolObject(AutomationTool.PLAYWRIGHT, page) (from merv-client), validation(step, expected, actual, true) captures a viewport PNG into the run folder (local) or uploads it (server). You may use the playwright package for the browser without installing merv-client-playwright.

import { chromium } from 'playwright';
import { AutomationTool, MervPlaywright, MervReport } from 'merv-client';

const browser = await chromium.launch();
const page = await browser.newPage();
MervPlaywright.setAutomationToolObject(AutomationTool.PLAYWRIGHT, page);

const report = await MervReport.open();
await report.createTest('UI check', 'Home');
await page.goto('https://example.com');
await report.validation('Title', 'Example Domain', await page.title(), true);
await report.finalize();

MervPlaywright.clear();
await browser.close();

JavaScript / TypeScript — copy PNG from disk (local)

For scripts without Playwright, use the lower-level MervExplicitLocalReport API:

import { MervExplicitLocalReport } from 'merv-client';

const run = MervExplicitLocalReport.open();
const shot = run.copyScreenshotFromFile('/tmp/checkout.png', 'checkout-step');

run.addTestCase({
  testcaseName: 'Checkout flow',
  status: 'PASSED',
  startTime: new Date().toISOString(),
  endTime: new Date().toISOString(),
  executionMachine: 'ci-runner-01',
  testSteps: [{
    teststepName: 'Confirm order',
    stepType: 'ASSERTION',
    status: 'PASSED',
    expected: 'Order confirmed',
    actual: 'Order confirmed',
    screenshots: shot ? [shot] : [],
  }],
});
run.finalize();

Java — server upload

After createTestStep, call client.uploadFile(stepId, file, description) to attach PNG or other files to that step in the Merv App.

View reports

Troubleshooting

Issue What to check
Call createTest before adding steps Invoke createTest(name, desc) before info / testdata / validation.
No folder under merv.report.folder merv.local=true; run script from project root; call finalize().
Live dashboard empty until finalize() Use a merv-client build that auto-persists after each step (local JSON + index). Still call finalize() at the end to mark the run completed and write the final HTML/zip. For the cloud App, set merv.local=false — suite/cases/steps stream as you call createTest / info / testdata / validation.
Java fromConfig() fails merv.local=false, valid merv.server, and merv.api_key (or username/password).
Screenshot skipped in MervReport validation(..., true) needs a bound Playwright page, or use MervExplicitLocalReport.copyScreenshotFromFile.

What’s next

← Back to documentation