DEV Community

Cover image for Sending beautiful Playwright test reports via email using shadcn/ui and react-email
Vitali Haradkou
Vitali Haradkou

Posted on

Sending beautiful Playwright test reports via email using shadcn/ui and react-email

Why email reports?

After a CI run finishes you usually have two options: check GitHub Actions manually or wait for a Slack ping with a link. Neither is great when you want the whole team — including non-engineers — to see what broke.

@playwright-labs/reporter-email solves this by hooking into Playwright's reporter API and sending an HTML email as soon as the run completes. No extra server, no external service — just SMTP.

New in this release: shadcn/ui templates

The package now ships 4 new templates built on top of email-safe shadcn/ui components.

"Email-safe" means no Radix UI (requires browser APIs), no CSS variables (not supported in most clients), and <a> tags instead of <button> for interactive elements.

Template overview

Template Import Key feature
Base …/shadcn Badge + Card layout
Chart …/shadcn/base-chart Pass-rate stacked bar
Button …/shadcn/base-button CTA links to report / failures
Themes …/shadcn/base-themes 6 color themes
Select …/shadcn/base-select Status filter

Subpath exports

Each template ships as its own bundle so you only import what you use:

import { PlaywrightReportShadcnChartEmail }
  from "@playwright-labs/reporter-email/templates/shadcn/base-chart";
Enter fullscreen mode Exit fullscreen mode

TypeScript resolves types correctly with "moduleResolution": "bundler" in tsconfig.json.

Quick setup

Install the package:

npm install @playwright-labs/reporter-email
Enter fullscreen mode Exit fullscreen mode

Add to playwright.config.ts:

import type { PlaywrightTestConfig } from "@playwright/test";

const config: PlaywrightTestConfig = {
  reporter: [
    ["@playwright-labs/reporter-email", {
      host: "smtp.example.com",
      port: 587,
      from: "ci@example.com",
      to: ["team@example.com"],
      template: "shadcn",          // or "shadcn-chart", "shadcn-themes", …
      statusFilter: ["failed"],    // send only failures
    }],
  ],
};

export default config;
Enter fullscreen mode Exit fullscreen mode

The templates

The most useful pattern for busy pipelines: send an email only when something breaks, and show only the failed tests.

import PlaywrightReportShadcnEmail from
  "@playwright-labs/reporter-email/templates/shadcn/base-button";

<PlaywrightReportShadcnEmail
  result={result}
  testCases={testCases}
/>
Enter fullscreen mode Exit fullscreen mode

The email renders a shadcn-like button trigger showing.

Previewing templates locally

The examples/ directory has a dev server powered by react-email:

cd packages/reporter-email/examples
pnpm email:preview
# → http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

In your project:

# install @react-email/components & @react-email/render 
pnpm i @react-email/components @react-email/render -D
Enter fullscreen mode Exit fullscreen mode

Create template & Start dev server

mkdir -p ./emails
pnpm exec email dev --dir emails
Enter fullscreen mode Exit fullscreen mode

Create your template:

import React from "react";
import type { FullResult, TestCase, TestResult } from "@playwright/test/reporter";
import PlaywrightReportEmail from "@playwright-labs/reporter-email/templates/base";

// mock data
const result = {
  status: "failed",
  duration: 14_320,
  startTime: new Date(),
} satisfies FullResult;

function tc(title: string, suite: string): TestCase {
  return { title, parent: { title: suite } } as unknown as TestCase;
}

function tr(status: TestResult["status"], duration: number): TestResult {
  return { status, duration } as TestResult;
}

const testCases: [TestCase, TestResult][] = [
  [tc("Login with valid credentials",   "Auth"),          tr("passed",  342)],
  [tc("Login with invalid credentials", "Auth"),          tr("passed",  289)],
  [tc("Logout",                         "Auth"),          tr("passed",  190)],
  [tc("Add item to cart",               "Shopping Cart"), tr("failed", 5102)],
  [tc("Remove item from cart",          "Shopping Cart"), tr("failed", 4320)],
  [tc("View product details",           "Product"),       tr("passed",  421)],
  [tc("Filter by category",             "Product"),       tr("passed",  374)],
  [tc("Search by keyword",              "Search"),        tr("skipped",   0)],
];

// your template!
/** Default export is required by the React Email dev server. */
export default function PlaywrightReportPreview() {
  return (
     <>
      <span> This is an example preview</span>
    <PlaywrightReportEmail result={result} testCases={testCases} />
     </>
  );
}

Enter fullscreen mode Exit fullscreen mode

Check out the repo for all preview files and the full source.

GitHub: https://github.com/vitalics/playwright-labs

Top comments (0)