# Export your suite as a Playwright project

Source: https://testwatch.dev/docs/export
Updated: 2026-10-17

One download gives you a plain Playwright project with every test the app would run. It needs no TestWatch account to run. Export is on every plan.

## Download it

Choose **Export suite** on the app’s Scenarios page, or use the “Run locally” card on **CI & deploys**. Pick the environment and, optionally, tags. The dialog previews how many tests go in per device and lists any that are left out, with the reason. Quarantined tests are included only if you switch them on.

The export contains the tests a run would run. Tests that need review, are out of date or are drafts are listed as skipped instead. Exporting also works while a workspace is suspended, so your tests stay yours.

## What’s in the zip

| Path | Contents |
| --- | --- |
| `tests/<name>.<device>.spec.ts` | Each test’s code, exactly as it runs in TestWatch. The device suffix sends it to the matching Playwright project. |
| `fixtures.ts` | The same helpers the tests use in TestWatch, made to run without it. |
| `email-provider.ts` | Where you connect your own email service, for tests that read email. |
| `playwright.config.ts` | One project per device the tests use; loads `.env`; one retry; trace, video and screenshot kept on failure. |
| `package.json` | An exact `@playwright/test` version, the one TestWatch runs. |
| `.env.example` | The variable names the suite reads. `TARGET_BASE_URL` is filled in; every secret is left empty. |
| `.github/workflows/playwright.yml` | A workflow that installs, runs the suite with your repository secrets and uploads the report. |
| `README.md` | How to run it, what the fixtures do, and anything left out. |
| `testwatch.json` | A manifest of every test with its TestWatch ids and version, so two exports can be compared. |
| `files/` | The files the tests upload, at their current version. Files over the size limit are listed in the README to download separately. |
| `tsconfig.json`, `.gitignore` | The usual. |

No password, token or secret is ever written into the zip.

## Run it locally

```
npm install
npx playwright install chromium webkit   # the README lists the browsers your suite needs
cp .env.example .env                     # then fill in TARGET_EMAIL / TARGET_PASSWORD
npx playwright test
```

You need Node 20.12 or newer. Open the report with `npx playwright show-report`. Each device is its own project, so `npx playwright test --project=desktop-chrome` runs one. Tests run one at a time, because they may share the same login.

Before each test the fixtures open `TARGET_BASE_URL`, accept a cookie banner if one shows, turn off CSS animations and block a few chat and marketing widgets. Set `TESTWATCH_VENDOR_BLOCK=off` if your app needs one of them. Set `TW_INCLUDE_QUARANTINED=1` to run quarantined tests too.

## Protected staging after export

Protection comes from environment variables. `.env.example` names only the kinds your environment uses:

```
TARGET_BASE_URL=https://staging.example.com
TARGET_EMAIL=
TARGET_PASSWORD=

# Only when the environment is protected; headers go only to TARGET_BASE_URL
TARGET_BASIC_USER=
TARGET_BASIC_PASSWORD=
TARGET_VERCEL_BYPASS=
TARGET_CF_ACCESS_CLIENT_ID=
TARGET_CF_ACCESS_CLIENT_SECRET=
TARGET_EXTRA_HEADERS={"x-staging-key":""}
```

As in TestWatch, these headers go only to the exact origin of `TARGET_BASE_URL`, never to another site and never on a redirect.

## Email after export

In TestWatch, tests that read email use TestWatch’s own inboxes. An exported suite reads mail through a provider you connect in `email-provider.ts`. Until you do, those tests fail with `EMAIL_PROVIDER_NOT_CONFIGURED` and the rest run normally. The README names the tests that read email.

A provider has two functions: `address(tag)` returns a fresh address you can receive at, and `list({ to, since })` returns the messages sent to it since a time. Links and one-time codes are extracted for you, as in TestWatch. The README has a complete example for a hosted test-email service; plus-addressing on a mailbox you own works too:

```
// email-provider.ts, using plus-addressing on a mailbox you own
export const emailProvider = {
  // A fresh address. tag is unique per call, e.g. "tw-l1a2b3c-x9k2m4".
  address: (tag: string) => `qa+${tag}@yourcompany.com`,
  // The messages sent to `to` since `since`: subject, from, html or text, receivedAt.
  async list({ to, since }: { to: string; since: Date }) {
    return fetchMessagesFromYourProvider(to, since);
  },
};
```

Without a match within 45 seconds, `waitForEmail()` fails with `EMAIL_NOT_RECEIVED`. Set `TW_EMAIL_WAIT_MS` to change the wait, up to 120 seconds.

## Test data after export

`unique()`, `testEmail()` and `track()` work the same way. Every value from one `npx playwright test` shares a `tw-<tag>` prefix, so you can find and delete what a run created. `testEmail()` uses `TW_TEST_EMAIL_DOMAIN`, default `example.com`. See [Test fixtures](https://testwatch.dev/docs/fixtures).

## What stays in TestWatch

Writing new tests, checking failures and proposing fixes, schedules, alerts, run history and evidence stay in TestWatch. The export is a snapshot: export again after tests change.
