# Sign up with an email code

> Test a sign-up that sends a code, with a new address on every run.

Source: https://rehearsal.dev/docs/examples/sign-up-with-an-email-code

This example uses Parcel, a demo store at `parcel.example.com`. Parcel is a demo project, not a customer.

Parcel's sign-up asks for an email and a password, then emails a code to finish. A sign-up test needs a new address on every run. With the same address, the second run would find the account already there.

## Before you start

A sign-up needs no [test account](https://rehearsal.dev/docs/reagent/test-accounts.md). Re:agent opens its browser as a new user, with a new address and a password that Rehearsal keeps.

Every run gets a new address in the [test inbox](https://rehearsal.dev/docs/reagent/test-inbox.md), such as `fresh-55a96c3ffd89f41f2379c02b9bfed590036a9b08b973006c@inbox.rehearsal.dev`. Each one starts with `fresh-`, so you can find these accounts in your app's data later.

## Ask Re:agent

Open **Re:agent** and type: "Sign up for Parcel with a new account. Parcel emails a code. Check that the welcome page opens."

## What Re:agent does

Each line below is a row in the chat, in the app's own words. What follows a dot is the detail the chat shows beside the row.

- Checked your projects
- Opened a browser on **parcel.example.com** as a new user
- Opened **parcel.example.com/sign-up**
- Filled **Email**
- Filled **Password**
- Clicked **Create account**
- Read the test inbox · 1 message
- Filled **Code**
- Clicked **Verify**
- Read the page · Welcome to Parcel
- Saved the flow

Re:agent types `{{email}}` and `{{password}}`, and Rehearsal puts the real address and password in the fields. It reads the code from the inbox and types it, and the flow writes it down as `{{code}}`. Nothing shows beside these rows, and the chat does not keep the code.

## The test

Rehearsal writes a Playwright test from the saved flow. It looks like this.

```ts
import { expect, test } from '@playwright/test';
import { participant } from '@rehearsal/codegen/runtime';

test('New visitor signs up with an email code', async ({ browser }) => {
  const visitor = await participant(browser, 'visitor');
  try {
    await test.step('Open the sign-up page', async () => {
      await visitor.page.goto('/sign-up');
    });
    await test.step('Sign up with a new address', async () => {
      const { email } = await visitor.identity();
      await visitor.page.getByLabel('Email').fill(email);
      await visitor.page.getByLabel('Password').fill(visitor.password());
      await visitor.page.getByRole('button', { name: 'Create account' }).click();
    });
    await test.step('Enter the code from the email', async () => {
      const message = await visitor.latestEmail();
      await visitor.page.getByLabel('Code').fill(message.codes[0]);
      await visitor.page.getByRole('button', { name: 'Verify' }).click();
    });
    await test.step('Check the welcome page', async () => {
      await expect(visitor.page.getByRole('heading', { name: 'Welcome to Parcel' }))
        .toBeVisible();
    });
  }
  finally {
    await visitor.close();
  }
});
```

`visitor.identity()` gives the run its new address, and `visitor.password()` gives the password. `visitor.latestEmail()` waits up to 30 seconds for the email, then returns its codes and links. The code is read again on every run, so it is never in the file.

> [!NOTE]
> If your app emails a link instead, Re:agent opens it, and the flow writes it down as `{{link}}`. The test then opens the link from `latestEmail()`.

## Run it

Press **Run now** on the card in the chat, or **Run** on the test's row in **Tests**. From the terminal:

```sh
rehearsal runs start --test <test-id>
rehearsal runs wait <run-id>
```

Every run signs up a new account in Parcel. Remove old ones from your app's data when you no longer need them.

## Next steps

- Read more about [the test inbox](https://rehearsal.dev/docs/reagent/test-inbox.md).
- Test a flow between two people: [Invite a member and join](https://rehearsal.dev/docs/examples/invite-a-member.md).
- Learn to [read a run](https://rehearsal.dev/docs/tests/read-a-run.md) when a test fails.
