> ## Documentation Index
> Fetch the complete documentation index at: https://resend.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# How to set up E2E testing with Playwright

> End to end testing ensures your entire app flow is fully functioning.

export const YouTube = ({id}) => {
  return <iframe className="w-full aspect-video rounded-xl" src={`https://www.youtube.com/embed/${id}`} title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen></iframe>;
};

Below is a basic guide on setting up E2E testing with NextJS, Resend, and Playwright.

Prefer watching a video? Check out our video walkthrough below.

<YouTube id="lzozXSMKl6E" />

## Guide

<Steps>
  <Step title="Create an endpoint">
    For simplicity, we'll create a GET endpoint that sends an email to the testing account, `delivered@resend.dev` on fetch.

    ```ts app/api/send/route.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
    import { Resend } from 'resend';
    const resend = new Resend(process.env.RESEND_API_KEY);

    export async function GET() {
      try {
        const { data, error } = await resend.emails.send({
          from: 'Acme <onboarding@resend.dev>',
          to: ['delivered@resend.dev'],
          subject: 'Hello world',
          html: '<h1>Hello world</h1>',
        });

        if (error) {
          return Response.json({ error }, { status: 500 });
        }

        return Response.json({ data });
      } catch (error) {
        return Response.json({ error }, { status: 500 });
      }
    }
    ```
  </Step>

  <Step title="Write the test spec file">
    Create a test spec file at `e2e/app.spec.ts`. You can test in two ways: by calling the Resend API or by mocking a response.

    Calling the Resend API tests the entire API flow, including Resend's API responses, but counts towards your account's sending quota.

    ```ts e2e/app.spec.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
    import { test, expect } from '@playwright/test';

    test('does not mock the response and calls the Resend API', async ({
      page,
    }) => {
      // Go to the page
      await page.goto('http://localhost:3000/api/send');

      // Assert that the response is visible
      await expect(page.getByText('id')).toBeVisible();
    });
    ```

    Mocking the response lets you test your app's flow without calling the Resend API and impacting your account's sending quota.

    ```ts e2e/app.spec.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
    import { test, expect } from '@playwright/test';

    test("mocks the response and doesn't call the Resend API", async ({ page }) => {
      // Sample response from Resend
      const body = JSON.stringify({
        data: {
          id: '621f3ecf-f4d2-453a-9f82-21332409b4d2',
        },
      });

      // Mock the api call before navigating
      await page.route('*/**/api/send', async (route) => {
        await route.fulfill({
          body,
          contentType: 'application/json',
          status: 200,
        });
      });
    });
    ```

    <Note>
      However you test, it's important to test using a test email address (e.g.,
      [delivered@resend.dev](mailto:delivered@resend.dev)) so your tests don't impact your deliverability. Resend's
      [test accounts](/dashboard/emails/send-test-emails) run through the entire API
      flow without harming your reputation.
    </Note>
  </Step>

  <Step title="Create a Playwright config file">
    Write your config file, paying special attention to a few properties:

    * `testDir`: the directory containing your test files
    * `outputDir`: the directory to store test results
    * `webServer`: provide instructions for Playwright to run your app before starting the tests
    * `projects`: an array of the browsers you want to test

    ```ts playwright.config.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
    import { defineConfig, devices } from '@playwright/test';
    import path from 'path';

    const baseURL = 'http://localhost:3000';

    export default defineConfig({
      timeout: 30 * 1000,
      testDir: path.join(__dirname, 'e2e'),
      retries: 2,
      outputDir: 'test-results/',
      webServer: {
        command: 'npm run dev',
        url: baseURL,
        timeout: 120 * 1000,
        reuseExistingServer: !process.env.CI,
      },

      use: {
        baseURL,
        // Retry a test if its failing with enabled tracing. This allows you to analyze the DOM, console logs, network traffic etc.
        trace: 'retry-with-trace',
      },

      projects: [
        // Test against desktop browsers.
        {
          name: 'Desktop Chrome',
          use: {
            ...devices['Desktop Chrome'],
          },
        },
        {
          name: 'Desktop Firefox',
          use: {
            ...devices['Desktop Firefox'],
          },
        },
        {
          name: 'Desktop Safari',
          use: {
            ...devices['Desktop Safari'],
          },
        },
        // Test against mobile viewports.
        {
          name: 'Mobile Chrome',
          use: {
            ...devices['Pixel 5'],
          },
        },
        {
          name: 'Mobile Safari',
          use: devices['iPhone 12'],
        },
      ],
    });
    ```

    [See the Playwright docs](https://playwright.dev/docs/intro) for more help.
  </Step>

  <Step title="Run the test">
    You can run the test by installing Playwright and running the tests.

    ```bash theme={"theme":{"light":"github-light","dark":"vesper"}}
    npx playwright install
    npx playwright test
    ```

    Playwright will run the tests in the browsers of your choice and show you the results.
  </Step>
</Steps>

## Examples

<Card title="Example repo" icon="arrow-up-right-from-square" href="https://github.com/resend/resend-nextjs-playwright-example">
  See the full source code.
</Card>
