npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fumadocs-test-reports

v0.1.1

Published

Test report integration for Fumadocs

Readme

fumadocs-test-reports

A test report integration for Fumadocs. Use framework presenters to display native reports in your documentation. Use shared UI primitives to build other report views.

Quick start

import { parseTUnitReport } from 'fumadocs-test-reports/tunit';
import { TUnitReport, TUnitReportLink } from 'fumadocs-test-reports/tunit/ui';
import input from './run.tunit-report.json';

const report = parseTUnitReport(input);

<TUnitReport report={report} />;
<TUnitReportLink report={report} href="/docs/reports/run" />;

Install the package in your Fumadocs application:

pnpm add fumadocs-test-reports

Use these peer dependencies:

  • React 19.2 or later.
  • Fumadocs Core 16.16.2 or later.
  • Fumadocs UI 16.16.2 or later.

The parser entry points do not import React or Fumadocs UI.

Import the stylesheet after the Fumadocs styles:

@import 'fumadocs-test-reports/css/preset.css';

Architecture

During 0.x development, changes replace the current API and native report models directly. The package does not keep deprecated APIs or compatibility branches for earlier versions.

TUnit JSON → parser → native report model → framework presenter → shared UI primitives

Each report format has its own parser, native report model, and framework presenter. Shared UI primitives receive display props, such as text, tone, or duration. Framework presenters can add traces, steps, or artifacts from their native reports.

| Entry point | Exports | | ----------------- | ------------------------------------------------------------------------ | | /tunit | parseTUnitReport, TUnitParseError, and native TUnit* types. | | /tunit/ui | TUnitReport and TUnitReportLink. | | /vitest | parseVitestReport, VitestParseError, and native VitestJson* types. | | /vitest/ui | VitestReport, VitestReportLink, and display selection types. | | /i18n | testReportTranslations(), zhCN(), and translation key types. | | /ui | StatusBadge, Duration, ErrorDetail, and StdoutPanel. | | /css/preset.css | Report layout and status styles that use Fumadocs theme variables. |

TUnit native report model

parseTUnitReport accepts decoded .tunit-report.json data with schema version 1. The parser checks the fields that the framework presenter uses. It then returns the same input object.

The caller reads files, sends network requests, and controls routes.

The parser keeps native field names and values. These include assemblyName, groups[].tests, displayName, output, errorOutput, exception.innerException, retryAttempt, spanId, and parentSpanId.

Unknown fields, custom status strings, and explicit null values remain in the native report. The parser does not add fields, default values, or status mappings.

The native report must contain these fields:

  • At the root: schemaVersion, assemblyName, and groups.
  • In each group: className and tests.
  • In each test: id, displayName, and status.

The parser also checks metadata and optional data when present. Invalid known fields, duplicate test IDs, or unsupported schema versions cause a TUnitParseError. The error's path identifies the JSON field.

The framework presenter reads the supplied TUnit summary counts. If the native report has no summary, the framework presenter calculates display counts from the tests.

Retry attempts remain part of a test's attempt history. The framework presenter keeps timestamp text unchanged. Duration values are in milliseconds.

TUnit framework presenter

TUnitReport shows search, outcome filters, inline details, output, retry attempts, and a trace timeline. Each row uses Fumadocs Accordion. Details open below the row and use the full list width.

Groups start closed. Each group heading shows the number of visible test rows. Use Expand all or Collapse all to control the groups.

Search and outcome filters open matching groups. A selected test link opens its group. Closing a group keeps the test selection. Outcome filters and group actions share one toolbar. The controls can wrap at narrow widths.

A group shows Passed only when all its tests passed. Vitest files must also have a passing file outcome and no collection error. This label uses the complete group, before search or outcome filters apply.

Both framework presenters use native Fumadocs Accordion for groups and test rows. Test names use the host's font size and family.

Only one test can be open at a time. Test details start closed unless the host supplies a selected test. The report uses document scroll, with no separate list or detail scroll boxes.

TUnitReportLink adds a link to the native report in a document.

Headers and selection

Set showHeader={false} if the host already displays a page title. Both framework presenters use colors from the host's Fumadocs theme variables.

Use selectedTestId and onTestSelect to control selection and report links.

| Prop value or event | Behavior | | --------------------- | ------------------------------------------------------------- | | Omit selectedTestId | The framework presenter controls local selection. | | Supply a string | The host selects that test. | | Supply null | The host closes all rows. | | Open a row | onTestSelect receives the native test or display selection. | | Close a row | onTestSelect receives undefined. |

Search and outcome filters can hide the open row. They do not select a different row. Clear the search or filter to show the selected row again.

<TUnitReport
  report={report}
  showHeader={false}
  selectedTestId={searchParams.get('test')}
  onTestSelect={(test) => {
    const params = new URLSearchParams(searchParams);
    if (test) params.set('test', test.id);
    else params.delete('test');
    // The host updates its URL with params, preserving scroll position.
  }}
/>

Fumadocs controls and layout

Framework presenters use Fumadocs Tabs, Accordion, Card, CodeBlock, Callout, and button variants. These controls supply keyboard navigation, row expansion, and code-copy buttons.

Report styles control test rows, counts, status badges, and trace bars. Container queries adjust rows and counts to the available report width. The host sidebar and table of contents can reduce this width.

Use page components that match the Fumadocs layout. Import the required layout styles for Spacious and Glass:

  • fumadocs-ui/css/generated/spacious.css.
  • fumadocs-ui/css/generated/glass.css.

Use <DocsPage full> for a separate report page. Spacious has a default page width limit of 760 px. The full prop changes this limit to 1200 px. The framework presenter uses the space available inside the page.

Flux in @fumadocs/[email protected] can make the page too narrow when a child uses inline-size containment. The documentation app applies a dependency patch that adds w-full to the native Flux main.

The patch keeps native page limits and alignment. The published test report integration does not include this patch. Hosts that use the affected Flux version need the same dependency fix. Other layout examples use their native page configuration.

Vitest native report model

Export a native report with the official Vitest JSON reporter:

vitest run --reporter=default --reporter=json --outputFile.json=./vitest-report.json

Read the native report and display it:

import { parseVitestReport } from 'fumadocs-test-reports/vitest';
import { VitestReport, VitestReportLink } from 'fumadocs-test-reports/vitest/ui';
import input from './vitest-report.json';

const report = parseVitestReport(input);
<VitestReport report={report} title="My tests" />;
<VitestReportLink report={report} href="/docs/reports/run" title="My tests" />;

The supported version is Vitest 5.0.3. The complete Fumadocs test run supplies the verification data.

The native report has no schema version field. Verify other producer versions with real exports before you add support. Public types describe the fields that the framework presenter uses. The types do not depend on the Vitest runtime package.

The parser keeps other source fields at their original paths. These fields can include snapshot, coverage, and benchmark data.

parseVitestReport accepts decoded JSON and returns the same input object. It checks the required structure, counts, and fields used for display.

Optional fields can be absent if the native report model permits this. Invalid supplied values cause a VitestParseError with a field path. Unknown fields and outcome strings remain unchanged.

Summary counts can differ from the visible details. A native report can contain only some test details.

Vitest framework presenter

The framework presenter shows files, test ancestry, outcomes, durations, failure messages, source locations, tags, and supplied metadata. It also shows file collection errors when the file has no test assertions.

numTotalTestSuites includes nested suites. Use testResults.length for the file count. The framework presenter does not use root numPendingTests as a skipped-test count.

The Vitest JSON reporter does not export standard output, standard error, attempt history, or traces. These features need a different native report format.

The success field gives the reporter's result. It does not replace the process exit code. The fixture's separate provenance file records that exit code.

Vitest selection

The native report has no unique test IDs. The framework presenter uses positions to identify rows within one export:

  • 0:2 identifies file index 0 and assertion index 2.
  • 0:file identifies a collection error in file index 0.

These display identifiers permit selection of tests with duplicate names. The framework presenter does not add the identifiers to the native report. Identifiers can change between test runs.

When a row opens, onTestSelect receives the identifier and references to the native file and optional assertion. When the row closes, the callback receives undefined.

The inline Accordion layout, header prop, and selection props use the same rules as TUnitReport.

Internationalization

Framework presenters read the same translation provider as Fumadocs UI. Register the test report integration's translation extension. Add the supplied Simplified Chinese preset if needed:

import { defineI18n } from 'fumadocs-core/i18n';
import { uiTranslations, i18nProvider } from 'fumadocs-ui/i18n';
import { RootProvider } from 'fumadocs-ui/provider/next';
import { testReportTranslations, zhCN } from 'fumadocs-test-reports/i18n';

const i18n = defineI18n({ defaultLanguage: 'en', languages: ['en', 'zh'] });
const translations = i18n
  .translations()
  .extend(uiTranslations())
  .extend(testReportTranslations())
  .preset('zh', zhCN())
  .add({ zh: { 'Passed(test reports)': '通过' } });

<RootProvider i18n={i18nProvider(translations, lang)}>
  <TUnitReport report={tunitReport} />
  <VitestReport report={vitestReport} />
</RootProvider>;

The host selects locale codes. It can add languages and change labels. If the host supplies no translations, UI labels use English.

Both framework presenters use this provider. During 0.x development, the package removed the old locale prop and TUnitReportLocale export.

Translations apply to UI labels and known outcome labels. Native test names, exception messages, output, and metadata remain unchanged.

The host controls Fumadocs layouts, Fumadocs UI translations, and application routes. See Fumadocs translations.

Shared UI primitives

import { StatusBadge, Duration, ErrorDetail, StdoutPanel } from 'fumadocs-test-reports/ui';

<StatusBadge status="failed" tone="danger" />;
<Duration value={42} />;
<ErrorDetail message="Expected 400, received 200" stack="at example.test.ts:12" />;
<StdoutPanel content="Connection refused" title="Standard error" />;

StatusBadge displays the caller's text with a tone. The framework presenter interprets the native status.

Duration shows an unknown duration for a missing or null value. It shows a recorded zero as zero.

ErrorDetail and StdoutPanel display escaped text. The framework presenter controls nested exceptions and interprets retry attempts.

This version supports TUnit and Vitest JSON. Other native report formats will have their own parsers and framework presenters. Dashboard, history, and search across frameworks are future features.

See these source references:

Local release

Run the workspace checks from the repository root:

pnpm test --run
pnpm types:check
pnpm build
pnpm lint
pnpm lint:format

From packages/test-reports, examine the files for publication:

npm pack --dry-run --ignore-scripts

pnpm pack builds the package through prepack. The published package contains dist, css, the package README, license, and manifest. Native report examples and test fixtures stay in the repository.

Log in to npm. Then publish from packages/test-reports:

pnpm publish --access public --no-git-checks

The manifest specifies the public npm registry. Publication requires npm account access and the account's authentication checks.