hey-api-playwright
v0.3.0
Published
Playwright integration for hey-api
Downloads
43
Maintainers
Readme
hey-api-playwright
Generate type-safe Playwright E2E test fixtures, route mocks, and consistent data builders from your OpenAPI specification.
This plugin for @hey-api/openapi-ts bridges the gap between your API definition and Playwright tests, ensuring your test data always matches your API schema.
Features
- Automated Route Mocking: Generates
page.route()helpers for every API operation. - Type-safe Fixtures: Mock data is validated against your OpenAPI schemas using Zod.
- Fluent Builders: Override default mock data easily with a chainable
.with()API. - Strict Mode Compatibility: ensuring your tests never drift from the API contract.
- Integration Ready: Works seamlessly with
@playwright/test. - MSW Support: Generates compatible MSW handlers for component testing.
Installation
npm install hey-api-playwright hey-api-builders --save-devPeer Dependencies
Ensure you have the following installed:
@hey-api/openapi-ts>= 0.61.0@playwright/test>= 1.40.0
Configuration
Add the plugin to your openapi-ts.config.ts. You must also include hey-api-builders as it powers the data generation.
import { defineConfig } from '@hey-api/openapi-ts';
import playwrightPlugin from 'hey-api-playwright';
import { buildersPlugin } from 'hey-api-builders';
export default defineConfig({
input: './openapi.yaml',
output: './src/generated',
plugins: [
'@hey-api/typescript',
buildersPlugin({
schema: './src/generated/schemas.ts' // Optional: if using schema references
}),
playwrightPlugin({
generateBuilders: true,
generateErrorMocks: true,
}),
],
});Options
| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| output | string | 'playwright-mocks' | Path to the generated output file relative to the output directory. |
| generateBuilders | boolean | true | Whether to generate fluent builder classes. |
| generateErrorMocks | boolean | true | Whether to generate mocks for error responses (e.g. 4xx, 5xx). |
| generateMsw | boolean | false | Whether to generate MSW handlers. |
| baseUrlPattern | string | '**/api/**' | The default glob pattern used to match API routes. |
| mockStrategy | 'static' \| 'zod' | 'static' | Strategy for generating mock data. 'static' uses pre-generated fixtures, 'zod' generates data at runtime using Zod schemas (requires zod dependency). |
Run the generator:
npx openapi-tsThis will produce a playwright-mocks.gen.ts file in your output directory.
Usage
1. Basic Route Mocking
For simple tests where you just need the API to return a valid 200 OK response with default data:
import { test, expect } from '@playwright/test';
import { mockViewUsers, mockCreateUser } from './generated/playwright-mocks.gen';
test('renders user list', async ({ page }) => {
// Mocks GET /users with default generated data matching the schema
await mockViewUsers(page);
await page.goto('/users');
await expect(page.getByRole('list')).toBeVisible();
});2. Fluent Builders (Recommended)
For more complex scenarios where you need specific data states, use the generated Mock classes with the Builder pattern. This allows you to override specific fields while keeping the rest compliant with the schema.
import { test, expect } from '@playwright/test';
import { ViewUsersMock } from './generated/playwright-mocks.gen';
test('renders specific users', async ({ page }) => {
// Override specific fields, rest are auto-generated
await new ViewUsersMock()
.with({
items: [
{ id: 'user-123', name: 'Alice', role: 'ADMIN' },
{ id: 'user-456', name: 'Bob', role: 'USER' }
],
meta: { total: 2 }
})
.apply(page); // Applies the route handler
await page.goto('/users');
await expect(page.getByText('Alice')).toBeVisible();
await expect(page.getByText('Bob')).toBeVisible();
});3. Pattern Matching
By default, mocks match the path defined in OpenAPI using a regex that allows query parameters. You can override the matching logic (e.g., to be more strict) when applying the mock.
// Match strict URL
await new ViewUsersMock().apply(page, '**/api/v1/users');
// Match custom Regex
await new ViewUsersMock().apply(page, /.*\/api\/v1\/users(\?.*)?$/);4. Conditional Mocking
You can pass an optional matcher function to dynamically determine if a request should be mocked. This is useful for conditional logic, such as returning different responses based on query parameters.
import { mockSearchCollections } from './generated/playwright-mocks.gen';
// Mock specific search query
await mockSearchCollections(page, {
items: [itemA]
}, {
matcher: (request) => request.url().includes('q=termA')
});
// Mock another search query
await mockSearchCollections(page, {
items: [itemB]
}, {
matcher: (request) => request.url().includes('q=termB')
});5. Global Fixtures
You can combine these with Playwright's test fixtures to set up common mocks for all tests.
// fixtures.ts
import { test as base } from '@playwright/test';
import { ViewMeMock } from './generated/playwright-mocks.gen';
export const test = base.extend({
page: async ({ page }, use) => {
// Gloablly mock the "Get Current User" endpoint
await new ViewMeMock()
.with({ id: 'test-user', email: '[email protected]' })
.apply(page);
await use(page);
},
});6. MSW Integration
You can also generate MSW handlers for use in component tests (e.g. Vitest, Jest).
Enable it in your config:
// openapi-ts.config.ts
export default defineConfig({
plugins: [
playwrightPlugin({
generateMsw: true
})
]
});This will generate mswMock* functions that wrap http.get, http.post, etc.
import { setupServer } from 'msw/node';
import { mswMockGetUsers } from './generated/playwright-mocks.gen';
const server = setupServer(
// mock with default data
mswMockGetUsers(),
// or override data
mswMockGetUsers((defaults) => ({
...defaults,
items: []
}))
);How It Works
- Schema Parsing: Parses your OpenAPI spec to understand all available operations and data models.
- Builder Generation: Uses
hey-api-buildersto createBuilderclasses for every response schema. These builders can generate valid mock data instantly. - Route Generation: Creates
Mockclasses that wrap Playwright'spage.route(). - Runtime Validation: When you call
.with(), TypeScript ensures you only pass valid fields. The underlying Zod schemas ensure the final response is valid.
License
MIT
