playwright/docs/src/testing-library-js.md

7.7 KiB

id title
testing-library Migrating from Testing Library

Migration principles

This guide describes migration to Playwright's Experimental Component Testing from DOM Testing Library, React Testing Library, Vue Testing Library and Svelte Testing Library.

:::note If you use DOM Testing Library in the browser (for example, you bundle end-to-end tests with webpack), you can switch directly to Playwright Test. Examples below are focused on component tests, but for end-to-end test you just need to replace await mount with await page.goto('http://localhost:3000/') to open the page under test. :::

Cheat Sheet

Testing Library Playwright
screen page and component
queries locators
async helpers assertions
user events actions
await user.click(screen.getByText('Click me')) await component.locator('text=Click me').click()
await user.click(await screen.findByText('Click me')) await component.locator('text=Click me').click()
await user.type(screen.getByLabelText('Password'), 'secret') await component.locator('text=Password').fill('secret')
expect(screen.getByLabelText('Password')).toHaveValue('secret') await expect(component.locator('text=Password')).toHaveValue('secret')
screen.findByText('...') component.locator('text=...')
screen.getByTestId('...') component.locator('data-testid=...')
screen.queryByPlaceholderText('...') component.locator('[placeholder="..."]')
screen.getAllByRole('button', { pressed: true }) component.locator('role=button[pressed]')

Example

Testing Library:

import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

test('should sign in', async () => {
  // Setup the page.
  const user = userEvent.setup();
  render(<SignInPage />);

  // Perform actions.
  await user.type(screen.getByLabelText('Username'), 'John');
  await user.type(screen.getByLabelText('Password'), 'secret');
  await user.click(screen.getByText('Sign in'));

  // Verify signed in state by waiting until "Welcome" message appears.
  await screen.findByText('Welcome, John');
});

Line-by-line migration to Playwright Test:

const { test, expect } = require('@playwright/experimental-ct-react'); // 1

test('should sign in', async ({ page, mount }) => { // 2
  // Setup the page.
  const component = await mount(<SignInPage />); // 3

  // Perform actions.
  await component.locator('text=Username').fill('John'); // 4
  await component.locator('text=Password').fill('secret');
  await component.locator('text=Sign in').click();

  // Verify signed in state by waiting until "Welcome" message appears.
  await expect(component.locator('text=Welcome, John')).toBeVisible(); // 5
});

Migration highlights (see inline comments in the Playwright Test code snippet):

  1. Import everything from @playwright/experimental-ct-react (or -vue, -svelte) for component tests, or from @playwright/test for end-to-end tests.
  2. Test function is given a page that is isolated from other tests, and mount that renders a component in this page. These are two of the useful fixtures in Playwright Test.
  3. Replace render with mount that returns a component locator.
  4. Use locators created with [method: Locator.locator] or [method: Page.locator] to perform most of the actions.
  5. Use assertions to verify the state.

Migrating queries

All queries like getBy..., findBy..., queryBy... and their multi-element counterparts are replaced with page.locator('...'). Locators always auto-wait and retry when needed, so you don't have to worry about choosing the right method. When you want to do a list operation, e.g. assert a list of texts, Playwright automatically performs multi-element opertations.

  1. getByRole: use role selector component.locator('role=button[name="Sign up"]').
  2. getByText: use component.locator('text=some value') and other variations of the text selector.
  3. getByTestId: use test id selectors, for example component.locator('data-testid=some value').
  4. getByPlaceholderText: use css alternative component.locator('[placeholder="some value"]').
  5. getByAltText: use css alternative component.locator('[alt="some value"]') or role selector component.locator('role=img[name="some value"]').
  6. getByTitle: use css alternative component.locator('[title="some value"]')

Replacing waitFor

Playwright includes assertions that automatically wait for the condition, so you don't usually need an explicit waitFor/waitForElementToBeRemoved call.

// Testing Library
await waitFor(() => {
  expect(getByText('the lion king')).toBeInTheDocument()
})
await waitForElementToBeRemoved(() => queryByText('the mummy'))

// Playwright
await expect(page.locator('text=the lion king')).toBeVisible()
await expect(page.locator('text=the mummy')).toBeHidden()

When you cannot find a suitable assertion, use expect.poll instead.

await expect.poll(async () => {
  const response = await page.request.get('https://api.example.com');
  return response.status();
}).toBe(200);

Replacing within

You can create a locator inside another locator with [method: Locator.locator] method.

// Testing Library
const messages = document.getElementById('messages')
const helloMessage = within(messages).getByText('hello')

// Playwright
const messages = component.locator('id=messages')
const helloMessage = messages.locator('text=hello')

Playwright Test Super Powers

Once you're on Playwright Test, you get a lot!

  • Full zero-configuration TypeScript support
  • Run tests across all web engines (Chrome, Firefox, Safari) on any popular operating system (Windows, macOS, Ubuntu)
  • Full support for multiple origins, (i)frames, tabs and contexts
  • Run tests in isolation in parallel across multiple browsers
  • Built-in test artifact collection: video recording, screenshots and playwright traces

Also you get all these awesome tools that come bundled with Playwright Test:

Further Reading

Learn more about Playwright Test runner: