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.
- How to open a report session and create testcases manually
- How to add
info,testdata, andvalidationsteps - How to attach screenshots and files
- Java (
MervClient), JavaScript, and TypeScript (MervReport) examples
When to use a custom report
- Standalone scripts, CLI tools, or batch jobs that run checks outside a test framework
- Prototypes and spikes before adopting a full Cucumber / Playwright integration
- Hybrid pipelines that already have pass/fail logic but need MERV HTML or cloud storage
- Microservice or API checks where you control suite/test/step structure in code
merv.properties
Place merv.properties at the project root (directory you run from).
Merv-Local (on-disk HTML)
merv.local=true
merv.report.folder=./merv-reports/
merv.regression_suite=Custom Report Suite
merv.execution.parallel=false
Merv-Server (cloud)
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 |
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
Each tab shows a full custom-report flow: open suite → create test → add steps → attach screenshot → 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.techelliptica</groupId>
<artifactId>merv-client-api</artifactId>
<version>4.0.0</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.
Install
npm install merv-client
Custom report script (scripts/custom-report.mjs)
import { MervReport, MervReportFile } from 'merv-client';
const report = await MervReport.open();
await report.createTest(
'Checkout API',
'POST /checkout with valid cart'
);
await report.info('Using staging tenant STG-42');
await report.testdata(
'Request body',
JSON.stringify({ cartId: 'cart-991', currency: 'USD' })
);
// Attach a file as test data (read from disk)
await report.testdata(
'Payload file',
new MervReportFile('./fixtures/checkout-payload.json')
);
await report.validation('HTTP status', '200', '200');
// Optional: capture screenshot when a Playwright page is bound
await report.validation('Page title', 'Checkout', 'Checkout', true);
await report.finalize();
console.log('Report written under merv.report.folder');
Run: node scripts/custom-report.mjs from the project root (where merv.properties lives).
Install
npm install merv-client
npm install -D typescript tsx
Custom report script (scripts/custom-report.ts)
import { MervReport, MervReportFile } from 'merv-client';
async function runCustomReport(): Promise<void> {
const report = await MervReport.open();
await report.createTest(
'Checkout API',
'POST /checkout with valid cart',
);
await report.info('Using staging tenant STG-42');
await report.testdata(
'Request body',
JSON.stringify({ cartId: 'cart-991', currency: 'USD' }),
);
await report.testdata(
'Payload file',
new MervReportFile('./fixtures/checkout-payload.json'),
);
await report.validation('HTTP status', '200', '200');
await report.validation('Page title', 'Checkout', 'Checkout', true);
await report.finalize();
}
runCustomReport().catch((err: unknown) => {
console.error(err);
process.exit(1);
});
Run: npx tsx scripts/custom-report.ts
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.setPage(page),
validation(step, expected, actual, true) captures a viewport PNG into the run folder (local) or uploads it (server).
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
- Merv-Local — open
{merv.report.folder}/index.htmlvia a local web server (see open dashboard) - Merv-Server — browse suites at merv.online/app
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(). |
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
- Merv-Local documentation — dashboard,
merv.properties, framework picker - Merv-Server guide — account, API key, hierarchy ID
- Playwright guide — reporter vs explicit
MervReport - API documentation — REST endpoints used by
MervClient
MERV