diff --git a/docs/manifest.json b/docs/manifest.json
index 3bfd5ec86a..530e3bb61f 100644
--- a/docs/manifest.json
+++ b/docs/manifest.json
@@ -951,7 +951,23 @@
[
{
"title": "Playwright",
- "href": "/docs/testing/playwright"
+ "collapse": true,
+ "items": [
+ [
+ {
+ "title": "Overview",
+ "href": "/docs/testing/playwright/overview"
+ },
+ {
+ "title": "Test helpers",
+ "href": "/docs/testing/playwright/test-helpers"
+ },
+ {
+ "title": "Test authenticated flows",
+ "href": "/docs/testing/playwright/test-authenticated-flows"
+ }
+ ]
+ ]
},
{ "title": "Cypress", "href": "/docs/testing/cypress" },
{
diff --git a/docs/testing/overview.mdx b/docs/testing/overview.mdx
index e3fd423a24..c3d57f7197 100644
--- a/docs/testing/overview.mdx
+++ b/docs/testing/overview.mdx
@@ -14,7 +14,7 @@ To avoid sending an email or SMS message with a one time passcode (OTP) during t
Testing Tokens allow you to bypass bot detection mechanisms that protect Clerk applications from malicious bots, ensuring your test suites run smoothly. Without Testing Tokens, you may encounter "Bot traffic detected" errors in your requests.
> [!NOTE]
-> While you can manually implement the following logic in your test suite, Clerk provides [Playwright](/docs/testing/playwright) and [Cypress](/docs/testing/cypress) integrations that handle this automatically.
+> While you can manually implement the following logic in your test suite, Clerk provides [Playwright](/docs/testing/playwright/overview) and [Cypress](/docs/testing/cypress) integrations that handle this automatically.
Obtained via the [Backend API](/docs/reference/backend-api/tag/Testing-Tokens){{ target: '_blank' }}, Testing Tokens are short-lived and valid only for the specific instance for which they are issued. Testing Tokens are only available in development instances.
diff --git a/docs/testing/playwright/overview.mdx b/docs/testing/playwright/overview.mdx
new file mode 100644
index 0000000000..e65125b8ab
--- /dev/null
+++ b/docs/testing/playwright/overview.mdx
@@ -0,0 +1,76 @@
+---
+title: Testing with Playwright
+description: Use Playwright to write end-to-end tests with Clerk.
+---
+
+[Playwright](https://playwright.dev) is an open-source, end-to-end testing framework that automates web application testing across multiple browsers. This guide will help you set up your environment for creating authenticated tests with Clerk, assuming you have some familiarity with both Clerk and Playwright.
+
+> [!IMPORTANT]
+> Check out the [demo repo](https://github.com/clerk/clerk-playwright-nextjs) that demonstrates testing a Clerk-powered application using [Testing Tokens](/docs/testing/overview#testing-tokens). To run the tests, you'll need dev instance Clerk API keys, a test user with username and password, and have username and password authentication enabled in the Clerk Dashboard.
+
+
+ ### Install `@clerk/testing`
+
+ Clerk's testing package provides integration helpers for popular testing frameworks. Install it by running the following command:
+
+
+ ```sh {{ filename: 'terminal' }}
+ npm i @clerk/testing --save-dev
+ ```
+
+ ```sh {{ filename: 'terminal' }}
+ yarn add -D @clerk/testing
+ ```
+
+ ```sh {{ filename: 'terminal' }}
+ pnpm add @clerk/testing -D
+ ```
+
+
+ ### Set your API keys
+
+ In your test runner, set your publishable and secret key as the `CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` environment variables, respectively.
+
+ To find your keys:
+
+ 1. Navigate to the [Clerk Dashboard](https://dashboard.clerk.com/last-active?path=api-keys).
+ 1. In the top navbar, select **Configure**. In the sidebar, select **API Keys**.
+ 1. In the **Quick Copy** section, copy your Clerk publishable and secret key.
+
+ > [!WARNING]
+ > Ensure that the secret key is provided securely to prevent exposure to third parties. For example, if you are using GitHub Actions, refer to [_Using secrets in GitHub Actions_](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions).
+
+ ### Configure Playwright with Clerk
+
+ The `clerkSetup()` function obtains a Testing Token when your test suite starts, making it available for all subsequent tests to use. This ensures that you don't have to manually generate a Testing Token for each test.
+
+ To configure Playwright with Clerk, call the `clerkSetup()` function in your [global setup file](https://playwright.dev/docs/test-global-setup-teardown), as shown in the following example:
+
+ ```tsx {{ filename: 'global.setup.ts' }}
+ import { clerkSetup } from '@clerk/testing/playwright'
+ import { test as setup } from '@playwright/test'
+
+ setup('global setup', async ({}) => {
+ await clerkSetup()
+ })
+ ```
+
+ > [!NOTE]
+ > You can manually set the Testing Token by using the `CLERK_TESTING_TOKEN` environment variable instead of calling `clerkSetup()`.
+
+ ### Use `setupClerkTestingToken()`
+
+ Now that Playwright is configured with Clerk, you can use the `setupClerkTestingToken()` function to include the Testing Token in individual test cases. This function injects the Testing Token for the specific test, ensuring the test can bypass Clerk's bot detection mechanisms. See the following example:
+
+ ```tsx {{ filename: 'my-test.spec.ts' }}
+ import { setupClerkTestingToken } from '@clerk/testing/playwright'
+ import { test } from '@playwright/test'
+
+ test('sign up', async ({ page }) => {
+ await setupClerkTestingToken({ page })
+
+ await page.goto('/sign-up')
+ // Add additional test logic here
+ })
+ ```
+
diff --git a/docs/testing/playwright/test-authenticated-flows.mdx b/docs/testing/playwright/test-authenticated-flows.mdx
new file mode 100644
index 0000000000..2bf3fe5a45
--- /dev/null
+++ b/docs/testing/playwright/test-authenticated-flows.mdx
@@ -0,0 +1,122 @@
+---
+title: Test authenticated flows
+description: Learn how to test authenticated flows with Playwright.
+---
+
+Playwright executes tests in isolated environments called browser contexts. Because each test case runs in a new browser context, the user session is not shared between test cases by default. However, tests can load existing authenticated state.
+
+This guide demonstrates how to save the auth state globally and load it in your test cases, eliminating the need to authenticate in every test and speeding up test execution. Visit the [Playwright docs about authentication](https://playwright.dev/docs/auth) for more information.
+
+> [!IMPORTANT]
+> Check out the [demo repo](https://github.com/clerk/clerk-playwright-nextjs) that demonstrates testing a Clerk-powered application using [Testing Tokens](/docs/testing/overview#testing-tokens). To run the tests, you'll need dev instance Clerk API keys, a test user with username and password, and have username and password authentication enabled in the Clerk Dashboard.
+
+
+ ### Create a storage directory
+
+ Create a `playwright/.clerk` directory and add it to your `.gitignore`. Once the auth state is generated, it will be stored to a file in this directory. Later on, tests will reuse this state and start already authenticated.
+
+ ```sh {{ filename: 'terminal' }}
+ mkdir -p playwright/.clerk
+ echo $'\nplaywright/.clerk' >> .gitignore
+ ```
+
+ ### Prepare auth state for your tests
+
+ Authenticate and save the auth state in your [global setup file](https://playwright.dev/docs/test-global-setup-teardown).
+
+ This file:
+
+ - Is executed before all projects.
+ - Calls [`clerkSetup()`](/docs/testing/playwright/overview#configure-playwright-with-clerk) to configure Playwright with Clerk.
+ - Calls `clerk.signIn()` to sign in a test user using credentials stored in environment variables. See the [reference](/docs/testing/playwright/test-helpers#clerk-sign-in) for more information about the different parameters you can pass.
+ - Checks if the user can access a protected page to ensure the user is successfully authenticated.
+ - Stores the auth state in the storage file.
+
+ ```tsx {{ filename: 'global.setup.ts' }}
+ import { clerk, clerkSetup } from '@clerk/testing/playwright'
+ import { test as setup } from '@playwright/test'
+ import path from 'path'
+
+ // Configure Playwright with Clerk
+ setup('global setup', async ({}) => {
+ await clerkSetup()
+ })
+
+ // Define the path to the storage file, which is `user.json`
+ const authFile = path.join(__dirname, '../playwright/.clerk/user.json')
+
+ setup('authenticate and save state to storage', async ({ page }) => {
+ // Perform authentication steps.
+ // This example uses a Clerk helper to authenticate
+ await page.goto('/')
+ await clerk.signIn({
+ page,
+ signInParams: {
+ strategy: 'password',
+ identifier: process.env.E2E_CLERK_USER_USERNAME!,
+ password: process.env.E2E_CLERK_USER_PASSWORD!,
+ },
+ })
+ await page.goto('/protected')
+ // Ensure the user has successfully accessed the protected page
+ // by checking an element on the page that only the authenticated user can access
+ await page.waitForSelector("h1:has-text('This is a PROTECTED page')")
+
+ await page.context().storageState({ path: authFile })
+ })
+ ```
+
+ ### Load the stored auth state in your tests
+
+ You can either load the stored auth state [in the config](#-in-the-config) or directly [in a test file](#-in-a-test-file). Loading in the config is useful if you want to authenticate once and reuse the same auth state for all tests or groups of tests. Loading in a test file is useful if you want to authenticate for a specific test case.
+
+ #### In the config
+
+ In your `playwright.config.ts`, create a `global setup` project and declare it as a [dependency](https://playwright.dev/docs/test-projects#dependencies) for all your testing projects. This means that the `global setup` project will always run before all the tests, and because it's where you prepared auth state, it will authenticate before all the tests. All testing projects should use the authenticated state as `storageState`.
+
+ ```tsx {{ filename: 'playwright.config.ts' }}
+ // ...
+ projects: [
+ {
+ name: 'global setup',
+ testMatch: /global\.setup\.ts/,
+ },
+ {
+ name: 'Main tests',
+ testMatch: /.*app.spec.ts/,
+ use: {
+ ...devices['Desktop Chrome'],
+ },
+ dependencies: ['global setup'],
+ },
+ {
+ name: 'Authenticated tests',
+ testMatch: /.*authenticated.spec.ts/,
+ use: {
+ ...devices['Desktop Chrome'],
+
+ // Use prepared Clerk auth state
+ storageState: 'playwright/.clerk/user.json',
+ },
+ dependencies: ['global setup'],
+ },
+ ]
+ ```
+
+ #### In a test file
+
+ To use the stored auth state in a test file, see the following example:
+
+ ```tsx {{ filename: 'authenticated.spec.ts', mark: [4, 5] }}
+ import { test } from '@playwright/test'
+
+ // Use prepared Clerk auth state
+ test.use({ storageState: 'playwright/.clerk/user.json' })
+
+ test('user test', async ({ page }) => {
+ // page is authenticated
+ })
+ ```
+
+
+For more information, feedback, or issues, visit the [`@clerk/testing`](https://github.com/clerk/javascript/tree/main/packages/testing) package.
diff --git a/docs/testing/playwright.mdx b/docs/testing/playwright/test-helpers.mdx
similarity index 62%
rename from docs/testing/playwright.mdx
rename to docs/testing/playwright/test-helpers.mdx
index 3115703fcc..c653b31220 100644
--- a/docs/testing/playwright.mdx
+++ b/docs/testing/playwright/test-helpers.mdx
@@ -1,82 +1,8 @@
---
-title: Testing with Playwright
-description: Use Playwright to write end-to-end tests with Clerk.
+title: Test helpers
+description: Use test helpers to sign in/sign out with Clerk in your Playwright tests.
---
-[Playwright](https://playwright.dev) is an open-source, end-to-end testing framework that automates web application testing across multiple browsers. This guide will help you set up your environment for creating authenticated tests with Clerk, assuming you have some familiarity with both Clerk and Playwright.
-
-> [!IMPORTANT]
-> Check out the [demo repo](https://github.com/clerk/clerk-playwright-nextjs) that demonstrates testing a Clerk-powered application using [Testing Tokens](/docs/testing/overview#testing-tokens). To run the tests, you'll need dev instance keys, a test user with username and password, and have username and password authentication enabled in the Clerk Dashboard.
-
-
- ### Install `@clerk/testing`
-
- Clerk's testing package provides integration helpers for popular testing frameworks. Install it by running the following command:
-
-
- ```sh {{ filename: 'terminal' }}
- npm i @clerk/testing --save-dev
- ```
-
- ```sh {{ filename: 'terminal' }}
- yarn add -D @clerk/testing
- ```
-
- ```sh {{ filename: 'terminal' }}
- pnpm add @clerk/testing -D
- ```
-
-
- ### Set your API keys
-
- In your test runner, set your publishable and secret key as the `CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` environment variables, respectively.
-
- To find your keys:
-
- 1. Navigate to the [Clerk Dashboard](https://dashboard.clerk.com/last-active?path=api-keys).
- 1. In the top navbar, select **Configure**. In the sidebar, select **API Keys**.
- 1. In the **Quick Copy** section, copy your Clerk publishable and secret key.
-
- > [!WARNING]
- > Ensure that the secret key is provided securely to prevent exposure to third parties. For example, if you are using GitHub Actions, refer to [_Using secrets in GitHub Actions_](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions).
-
- ### Configure Playwright with Clerk
-
- The `clerkSetup()` function obtains a Testing Token when your test suite starts, making it available for all subsequent tests to use. This ensures that you don't have to manually generate a Testing Token for each test.
-
- To configure Playwright with Clerk, call the `clerkSetup()` function in your [global setup file](https://playwright.dev/docs/test-global-setup-teardown), as shown in the following example:
-
- ```tsx {{ filename: 'global.setup.ts' }}
- import { clerkSetup } from '@clerk/testing/playwright'
- import { test as setup } from '@playwright/test'
-
- setup('global setup', async ({}) => {
- await clerkSetup()
- })
- ```
-
- > [!NOTE]
- > You can manually set the Testing Token by using the `CLERK_TESTING_TOKEN` environment variable instead of calling `clerkSetup()`.
-
- ### Use `setupClerkTestingToken()`
-
- Now that Playwright is configured with Clerk, you can use the `setupClerkTestingToken()` function to include the Testing Token in individual test cases. This function injects the Testing Token for the specific test, ensuring the test can bypass Clerk's bot detection mechanisms. See the following example:
-
- ```tsx {{ filename: 'my-test.spec.ts' }}
- import { setupClerkTestingToken } from '@clerk/testing/playwright'
- import { test } from '@playwright/test'
-
- test('sign up', async ({ page }) => {
- await setupClerkTestingToken({ page })
-
- await page.goto('/sign-up')
- // Add additional test logic here
- })
- ```
-
-
-## Test Helpers
-
The `@clerk/testing` package also provides some helper functions to sign in/sign out with Clerk in your Playwright tests without having to interact with the UI.
To use these commands, import the `clerk` object from the `@clerk/testing/playwright` package.
@@ -272,5 +198,3 @@ test('ensure that clerk has loaded', async ({ page }) => {
// clerk has loaded
})
```
-
-For more information, feedback, or issues, visit the [`@clerk/testing`](https://github.com/clerk/javascript/tree/main/packages/testing) package.