🧪 Test Hub
testing: Demo target v3.0.0 · built-in demo site

DEMO-T16 TS Freight: password reset through email, in TypeScript

Edit Load test Duplicate

DEMO-023's flow in TypeScript on its own account (courier): request a reset, wait for the email in the mailbox, follow the link, set a random password, sign in -- then check the link no longer works.

demoemailfreightsecuritytypescript DEMO-T16__freight_password_reset_typescript.spec.ts group: Freight in TypeScriptgroup: Python and TypeScript, side by side

Runs
7
Pass rate
86%
6 passed / 1 failed
Avg duration
11s
p95 15s
Estimate
11s
avg of last 10 judged runs
Flakiness
0.33
0 stable · 1 alternates
Current streak
3
passed

Last 7 results newest on the right — click a square to open that run

Duration per run point color = outcome; dashed = 7-run average; click a point to open the run

Step timing trends the same step compared across the last 7 runs — slowest steps first, one line each

How long it takes distribution of 7 runs — two humps mean two different behaviours hiding behind one average

fastest 9s · slowest 17s

Why this test failed grouped by message, last 90 days

timesmessagelast
1 1 of 1 test(s) failed: a password reset works through the email -- ex… Sep 25 open

Outcomes by target version

What this test does plain language, derived from the code

    No steps found.
Show the code
import { test, expect } from '@playwright/test';
import { randomBytes } from 'crypto';
import { open } from './_lib/freight';

// A password reset through the email, in TypeScript -- DEMO-023's flow on its
// own account (`courier`, so the two can run side by side). Waiting for the
// email is one web-first assertion with a longer timeout: the mailbox page
// reloads itself when new mail lands, and expect() keeps looking across the
// reloads. The reset link carries a secret token, so it is CLICKED in the
// email -- never navigated to, which would write the token into the log.
const ACCOUNT = 'courier';
const ADDRESS = 'courier@acme-freight.example';

test('a password reset works through the email -- exactly once', async ({ page }) => {
  await open(page, 'login/');
  await page.click('#forgot-link');
  await page.fill('#forgot-login', ACCOUNT);
  await page.click('#forgot-btn');
  const ref = (await page.locator('#forgot-ref').innerText()).trim();
  console.log(`reset requested, reference ${ref}`);

  const subject = page.locator(`#mail-list a.mail-subject:has-text('ref ${ref}')`);
  const resetLink = page.locator("#mail-body a[href*='/login/reset/']");
  await test.step('wait for the email', async () => {
    await open(page, `mailbox/?to=${ADDRESS}`);
    await expect(subject).toBeVisible({ timeout: 60_000 });
  });
  await subject.click();
  await expect(resetLink).toBeVisible();
  const message = page.url();

  const password = 'Pw-' + randomBytes(9).toString('base64url');   // fresh every run, never logged
  await test.step('choose a new password', async () => {
    await resetLink.click();
    await page.fill('#new-password', password);
    await page.fill('#confirm-password', password);
    await page.click('#reset-btn');
    await expect(page.locator('#login-btn')).toBeVisible();
  });

  await test.step('sign in with the new password', async () => {
    await page.fill('#username', ACCOUNT);
    await page.fill('#password', password);
    await page.click('#login-btn');
    await expect(page.locator('#signed-in-user')).toBeVisible();
  });
  await page.click('#sign-out');

  await test.step('follow the same link again', async () => {
    await page.goto(message);
    await resetLink.click();
    await expect(page.locator('#reset-invalid, #reset-form')).toBeVisible();
    await expect(page.locator('#reset-form'),
      'the reset link worked a SECOND time: any old reset email is still a key to the account')
      .toHaveCount(0);
  });
});

All runs

RunStatusQueuedDuration VersionTriggerBatch
#480 passed 2026-09-25 00:30:11 9s 3.0.0 group group: Python and TypeScript,…
#468 passed 2026-09-25 00:29:44 11s 3.0.0 group group: Freight in TypeScript
#434 passed 2026-09-25 00:23:39 10s 3.0.0 cli-adopted 7 tests (terminal)
#427 failed 2026-09-25 00:23:08 17s 2.1.0 cli-adopted 7 tests (terminal)
#420 passed 2026-09-25 00:22:38 12s 2.0.0 cli-adopted 7 tests (terminal)
#413 passed 2026-09-25 00:22:11 10s 1.1.0 cli-adopted 7 tests (terminal)
#406 passed 2026-09-25 00:21:43 12s 1.0.0 cli-adopted 7 tests (terminal)