Reporters
Tapsmith includes a reporter system inspired by Playwright. Reporters receive lifecycle events during a test run and produce output in various formats.
Configuration
Section titled “Configuration”Configure reporters in tapsmith.config.ts:
import { defineConfig } from "tapsmith";
export default defineConfig({ // Single reporter reporter: "list",
// Reporter with options reporter: ["json", { outputFile: "results.json" }],
// Multiple reporters reporter: ["list", ["json", { outputFile: "results.json" }]],});Default: When reporter is not set, Tapsmith uses the list reporter everywhere, including CI. Set reporter: 'dot' explicitly if you prefer the compact one-character-per-test output in CI. The github reporter is automatically added when running in GitHub Actions.
Built-in reporters
Section titled “Built-in reporters”| Reporter | Description | Default |
|---|---|---|
list | Detailed per-test output with status, name, and duration | All runs |
line | Concise single-line output, overwrites previous line | — |
dot | Minimal output: one character per test (· / F / ×) | — |
json | Structured JSON file with full test data | — |
junit | JUnit XML for CI system ingestion | — |
html | Self-contained interactive HTML report | — |
github | GitHub Actions annotations on failures | Auto in GH Actions |
blob | Serialized data for shard merging | — |
Reporter options
Section titled “Reporter options”json
| Option | Type | Default |
|---|---|---|
outputFile | string | "tapsmith-results/results.json" |
junit
| Option | Type | Default |
|---|---|---|
outputFile | string | "tapsmith-results/results.xml" |
html
| Option | Type | Default |
|---|---|---|
outputFolder | string | "tapsmith-report" |
open | "always" | "never" | "on-failure" | "on-failure" |
blob
| Option | Type | Default |
|---|---|---|
outputDir | string | "blob-report" |
Custom reporters
Section titled “Custom reporters”Implement the TapsmithReporter interface:
import type { TapsmithReporter, FullResult } from "tapsmith";import type { TestResult } from "tapsmith";
class MyReporter implements TapsmithReporter { onRunStart(config, fileCount) { console.log(`Running ${fileCount} test files`); }
onTestEnd(test: TestResult) { console.log(`${test.status}: ${test.fullName}`); }
onRunEnd(result: FullResult) { console.log(`Done in ${result.duration}ms`); }}
export default MyReporter;Use by path in config:
export default defineConfig({ reporter: [["./my-reporter.ts", {}]],});TapsmithReporter interface
Section titled “TapsmithReporter interface”All types are importable from "tapsmith":
import type { TapsmithReporter, FullResult, TapsmithConfig, TestResult, SuiteResult,} from "tapsmith";interface TapsmithReporter { onRunStart?(config: TapsmithConfig, fileCount: number): void; onTestFileStart?(filePath: string): void; onTestStart?(fullName: string, filePath?: string): void; onTestEnd?(test: TestResult): void; onTestFileEnd?(filePath: string, results: TestResult[]): void; onTestFileRetry?(filePath: string, discardedCount: number): void; onRunEnd?(result: FullResult): Promise<void> | void; onError?(error: Error): void;}TestResult
Section titled “TestResult”interface TestResult { name: string; fullName: string; status: "passed" | "failed" | "skipped"; durationMs: number; error?: Error; firstAttemptError?: Error; // on a flaky (passed-on-retry) result: the first failed attempt's error failedAttemptArtifacts?: { screenshot?: boolean; trace?: boolean; video?: boolean }; // which linked artifacts came from the failed attempt screenshotPath?: string; tracePath?: string; // path to the trace archive (.zip) when tracing is enabled videoPath?: string; // path to the recorded MP4 when `video` is enabled and retained workerIndex?: number; // set in parallel mode — index of the worker that ran this test retry?: number; // zero-based attempt number this result was recorded on (omitted for a first-attempt pass) filePath?: string; // path to the test file this result belongs to}For a flaky test (failed, then passed on retry) the final result links the
first failed attempt’s trace, screenshot, and video — the failure is what
needs debugging, and shipping pipelines (blob reports, CI artifacts) only pack
linked files. The failed attempt’s error is kept in firstAttemptError, and
console reporters print it in the flaky section of the run summary. When the
failed attempt has no artifact of a given kind (e.g. trace: "on-first-retry"
records nothing on the first attempt), the passing retry’s artifact is linked
instead.
SuiteResult
Section titled “SuiteResult”interface SuiteResult { name: string; durationMs: number; tests: TestResult[]; suites: SuiteResult[]; // nested describe() blocks}FullResult
Section titled “FullResult”interface FullResult { status: "passed" | "failed"; duration: number; // total wall-clock time in milliseconds (including setup) setupDuration?: number; // time spent on device provisioning, APK install, agent startup tests: TestResult[]; // flattened list of all test results suites: SuiteResult[]; // hierarchical suite tree (one per test file)}When setupDuration is present, console reporters show a timing breakdown:
Summary: 12 passed | 45.2s (setup 30.1s, tests 15.1s)