Adetayo Akinsanya unkletayo.dev

Capstone Project: Building a Custom Vitest Plugin & Test Runner Reporter

Architecting a custom Vitest reporter and Vite plugin to measure test execution metrics.

Adetayo Akinsanya (unkletayo) 2026-10-27

Part 14 in Series — Catch up on the previous article: Vitest Workspaces: Multi-Project Monorepo Test Execution Isolation (Part 13) before diving into this post.

In this capstone project, we build a custom Vitest reporter from scratch that hooks into test lifecycle events, tracks test execution durations, and exports metric reports.

// src/reporters/CustomMetricReporter.ts
import type { Reporter, TestCase, TestSuite, Vitest } from 'vitest/node';
import fs from 'node:fs';

export default class CustomMetricReporter implements Reporter {
  private vitest!: Vitest;
  private startTime: number = 0;

  onInit(vitest: Vitest) {
    this.vitest = vitest;
    this.startTime = Date.now();
    console.log('[MetricReporter] Initialized test runner instance...');
  }

  onFinished(files = [], errors = []) {
    const duration = Date.now() - this.startTime;
    const summary = {
      totalFiles: files.length,
      totalErrors: errors.length,
      durationMs: duration,
      timestamp: new Date().toISOString(),
    };

    fs.writeFileSync('test-metrics.json', JSON.stringify(summary, null, 2));
    console.log(`[MetricReporter] Test run complete in ${duration}ms. Report saved.`);
  }
}

Registering Custom Reporter in Config

// vitest.config.ts
import { defineConfig } from 'vitest/config';
import CustomMetricReporter from './src/reporters/CustomMetricReporter';

export default defineConfig({
  test: {
    reporters: ['default', new CustomMetricReporter()],
  },
});

This completes our 15-part series on Vitest architecture and modern testing mechanics.

Series Status

Part 15 in this series is scheduled for upcoming release on the daily publication roadmap.