# Coming from Playwright

> Try existing Playwright files on Retest, identify compatibility gaps and migrate a test.

Source: https://rehearsal.dev/retest/docs/scaling-up/from-playwright

Try `--playwright` to run an existing Playwright file through Retest's compatibility API. Start with one file and use the list of supported calls below to decide what to change before moving a larger suite.

If Retest is not installed in the project yet, follow the installation steps in [Quick start](https://rehearsal.dev/retest/docs/quick-start.md) first. Then try an existing spec before changing its imports or file name.

## Try one file

Keep the file's Playwright import and ordinary page fixture. This task test uses supported locators, actions and checks, so its body needs no changes:

```ts filename="tests/task.spec.ts"
import { expect, test } from '@playwright/test'

test('saves a task', async ({ page }) => {
  await page.goto('/')
  await page.getByTestId('task-title').fill('Release checklist')
  await page.getByTestId('save-task').click()
  await expect(page.getByTestId('saved-task')).toHaveText('Release checklist')
})
```

For a first trial without a Retest config, supply the executable and app address directly. Use the path to an installed Chrome or Chromium binary on your machine.

```sh
npx retest run --playwright tests/task.spec.ts \
  --browser "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
  --base-url http://127.0.0.1:4173
```

Retest resolves `@playwright/test` and `playwright/test` to its own compatibility API. Playwright does not need to be installed for this run, and no Playwright driver runs. The report labels it `playwright compatibility`.

## Move the configuration

Retest does not read `playwright.config.ts`. Browser selection, app addresses, startup and budgets must come from Retest's config or command line, so a passing trial does not mean your Playwright configuration was applied.

```ts filename="retest.config.ts"
import { chrome, defineConfig } from '@rehearsal-labs/retest'

const config = defineConfig({
  apps: { web: chrome({ baseUrl: 'http://127.0.0.1:4173' }) },
})

export default config

declare module '@rehearsal-labs/retest' {
  interface Register {
    config: typeof config
  }
}
```

```sh
npx retest run --playwright tests/task.spec.ts
```

With this config, omit `--browser`; Retest refuses that flag alongside a config. With no file arguments, compatibility mode discovers `.spec.ts`, `.spec.js`, `.spec.mts` and `.spec.mjs`. Corresponding `.test` files work when named explicitly, but are not discovered automatically.

## Check the supported subset

The compatibility API covers the calls listed below. A call or option outside this subset fails where you use it with `unsupported`, naming what needs to change.

| Area | Supported calls |
| --- | --- |
| Structure | `test`, `test.describe`, `test.beforeEach`, `test.afterEach`, `test.step` and the `page` fixture. |
| Page | `goto`, `reload`, `goBack`, `goForward`, `title` and `keyboard.press`. |
| Finders | `getByRole`, `getByLabel`, `getByText`, `getByTestId`, `getByPlaceholder` and CSS `locator`, with scoping, `first`, `last` and `nth`. |
| Actions | `fill`, `click`, `hover`, `press`, `check`, `uncheck` and single-option `selectOption`. |
| Checks | Visibility, checked state, enabled state, text, count, value, URL and title matchers; `expect.soft` and `expect.poll`. |
| Values | `toBe`, `toEqual`, `toContain` and `toMatch`. |

Common gaps include custom fixtures, `test.use`, Playwright's `test.skip` and `test.only`, `page.url()`, named table rows, file operations and options such as `force` or `waitUntil`. Compatibility file operations remain unsupported even though Retest's own API has uploads and downloads.

`selectOption` must identify one option by label or value. A bare string, array, index or null is refused, so make the intended selection explicit:

```ts
await page.getByLabel('Priority').selectOption({ label: 'High' })
```

Navigation calls do not provide a usable Playwright response, and `selectOption` does not provide its selected values. Await those calls without reading their return values; accessing a member of the returned value fails by name.

## Review behaviour differences

Compatibility keeps Playwright's partial, case-insensitive string matching for text finders unless you set `exact: true`. Actions and checks still follow Retest's rules: input is sent once, ambiguous matches fail, and a test with no assertion fails.

Retest selects options with keyboard input, so your app hears keys as well as input and change events. Role names come from the browser's accessibility tree; named table rows are refused because they differ from Playwright's naming. Enabled-state checks also differ for `aria-disabled` on ordinary elements or ancestors.

The default test budget is 60 seconds, the action budget 10 seconds and the assertion budget 5 seconds. A call-specific timeout can shorten a budget but cannot extend it. History navigation without an entry fails rather than returning null.

## Convert a test

Once a file works, change its import to `@rehearsal-labs/retest`, rename it to `.retest.ts` and run without `--playwright`. For the task example, the body stays the same. Review text finders because Retest's own default is exact and case-sensitive.

```ts
import { expect, test } from '@rehearsal-labs/retest'
```

```sh
npx retest run tests/task.retest.ts
```

Use [Signing in and secrets](https://rehearsal.dev/retest/docs/guides/signing-in.md) to replace config-based Playwright storage state with Retest's named setup state. Keep files requiring unsupported behaviour on their existing runner until you can express the same check in Retest.

## Next steps

- [Writing tests](https://rehearsal.dev/retest/docs/essentials/writing-tests.md): Use Retest's test structure and named app handles.
- [Configuration](https://rehearsal.dev/retest/docs/essentials/configuration.md): Replace browser projects and app startup settings.
- [Locators](https://rehearsal.dev/retest/docs/essentials/locators.md): Review exact matching and platform-specific limits.
