Skip to content

kevmuret/playwright-react-test

Repository files navigation

Playwright React Test Utility

A lightweight, zero‑configuration library that lets you mount and update React components inside Playwright tests.

Features

  • 🏃 Zero‑configuration setup – just install, use the defineConfig from 'playwright-react-test/test' module and start writing tests.
  • 🎉 Mount & update – expose mountStory and updateStory fixtures in your test files.
  • ⚡️ Automatic bundling of stories (and their CSS) via esbuild at runtime.
  • 🚀 HTTP server that serves bundled assets from a temporary directory, exposing the port through process.env.PWRIGHT_REACT_TEST_PORT.
  • 🔧 Global setup/teardown hooks (setup.ts, teardown.ts).
  • 🧪 TypeScript‑first – all components are typed, tests use Playwright's built‑in test runner.
  • 🤖 Automatic function exposing in props – functions passed to components are automatically exposed to the page via exposeFunction or exposeBinding.

Note: Currently, it supports only tests written in TypeScript.

Prerequisites

  • Node 18.x+
  • npm
  • Playwright (peer dependency of this package)

Installation

# Using npm
npm i -D playwright-react-test

The package pulls in @playwright/test as a peer dependency, so make sure you have it installed:

npm i -D @playwright/test

A minimal package.json file would be:

{
  "devDependencies": {
    "@types/react": "^19.2.13",
    "playwright": "^1.58.2"
  },
  "dependencies": {
    "playwright-react-test": "file:../playwright-react-test"
  }
}

Usage

Writing playwright config

Use the defineConfig from the playwright-react-test/test module instead of the original Playwright defineConfig for easy setup.

Create a file with the name playwright.config.ts and write:

import { defineConfig } from 'playwright-react-test/test';

export default defineConfig({
  // Write you usual playwright configuration
  testMatch: ["tests/**/*.ts"],
  timeout: 30_000,
  retries: 0,
  use: {
    viewport: { width: 1280, height: 720 },
    headless: true,
  },
});

NOTE: All playwright options are still available.

or if you prefer you can use the original defineConfig and pass the globalSetup and globalTeardown available at playwright-react-test/setup and playwright-react-test/teardown respectively:

export default defineConfig({
  globalSetup: 'playwright-react-test/setup',
  globalTeardown: 'playwright-react-test/teardown',
});

NOTE: If you need to add your custom setup and/or teardown pass an array.

Writing tests

First create story file (e.g., tests/example.story.tsx) and write:

import { React } from 'react';
import MyComponent, { MyComponentProps } from '../src/MyComponent';

// The default export is the React component that will be mounted
// you can encapsulate the component you want to test here passing the same props.
export default (props: MyComponentProps) => {
  return <MyComponent {...props}>Hello {props.text} !</MyComponent>;
}

Note: The story file is only available within the browser; it is not accessible directly from your test file.

Create a test file with the same name as the story file (e.g., tests/example.test.ts) and write:

import { test, expect } from 'playwright-react-test/test';
import { MyComponentProps } from '../src/MyComponent';

test('MyComponent renders and update correctly', async ({ page, mountStory, updateStory }) => {
  // Specify optional configuration such as a custom story file path
  // mountStory<MyComponentProps>({ text: 'world' }, { storyFile: './custom.story.tsx' });
  // The `storyFile` option allows you to mount a different story than the one inferred from the test filename.
  
  // Functions in props are automatically exposed for callbacks and event handlers
  const my_props = {
    text: 'world',
    onClick: (name: string) => console.log('Clicked:', name)
  };
  mountStory<MyComponentProps>(my_props);
  await expect(page.getByText('Hello world !')).toBeVisible();
  // Write any other expectations for MyComponent...

  // Update story props cause re-render of the story component
  // The props will replace all props, pass a variable if you don't want to change all props.
  updateStory<MyComponentProps>({
    text: 'you',
  });
  await expect(page.getByText('Hello you !')).toBeVisible();
});

Running tests

Run the tests using:

npx playwright test

License

MIT © 2026 Kevin Muret kevmuret@gmail.com

About

Test your React components (currently only works with TypeScript and ESBuild compiler).

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages