Signing in and secrets

Sign in with named secrets and reuse browser sign-in state across tests.

When a flow needs an account, keep its password in a named secret. This guide shows how to use that secret for sign-in and share the resulting browser state across tests.

Declare a secret Link to Declare a secret

Declare the password source in your config, then refer to it by name in the test. This task-app config reads an environment variable and names the sign-in state you will save.

retest.config.ts
import { chrome, defineConfig, env } from '@rehearsal-labs/retest'const config = defineConfig({  apps: { web: chrome({ baseUrl: 'http://127.0.0.1:4173' }) },  secrets: { password: env('TASK_APP_PASSWORD') },  states: ['signed-in'],})export default configdeclare module '@rehearsal-labs/retest' {  interface Register {    config: typeof config  }}

Set TASK_APP_PASSWORD in the environment where you run Retest. An env() source is read once when the run starts; a missing value or one shorter than four characters stops the run with exit code 2.

secret('password') gives the test a handle that prints as {{password}}. Retest types the password from its own process and removes the source variable from the test process's environment, so the test receives no value.

Sign in once Link to Sign in once

Use test.setup() to sign in through the page. When the setup passes, Retest saves its browser state, so check that sign-in succeeded before the setup returns.

tests/sign-in.retest.ts
import { expect, secret, test } from '@rehearsal-labs/retest'test.setup('signed-in', async ({ page }) => {  await page.goto('/login')  await page.getByLabel('User name').fill('alice')  await page.getByLabel('Password').fill(secret('password'))  await page.getByRole('button', { name: 'Sign in' }).click()  await expect(page.getByTestId('account')).toHaveText('Signed in as alice')})test('saves a task while signed in', { state: 'signed-in' }, async ({ page }) => {  await page.goto('/')  await page.getByTestId('task-title').fill('Release checklist')  await page.getByTestId('save-task').click()  await expect(page.getByTestId('saved-task')).toHaveText('Release checklist')})

The setup runs once for each browser target that needs it. Each dependent test gets a new browser context with the saved cookies and localStorage, then opens its own page with goto().

Declare setups at the top level of a file, with one app and a unique state name. When you select a test file without its setup, Retest searches the other .retest.ts files under the root for the setup it needs.

If the setup fails, its dependent tests are not_run and show that failure as their reason. A state name with no matching setup is a collection error, so check the spelling and app in both declarations.

What the state holds

Saved state holds cookies and localStorage, but no sessionStorage or server data. Retest keeps it under the run folder's states/ directory and removes it during cleanup; a forced kill can leave it behind.

Allow another origin Link to Allow another origin

On a browser page, a secret may be typed on the origins of the test's apps' base URLs. If sign-in takes you to another site, add that site's origin beside secrets in the config.

retest.config.ts
defineConfig({  // Keep your apps, secrets and states here.  secretOrigins: { password: ['https://login.tasks.example'] },})

Retest checks the destination before reading the secret and again before typing it. A fill on an origin outside this list fails with not_actionable and sends no text; check the destination before adding it.

In an Electron window, only the origins explicitly listed in secretOrigins count, and a file:// page cannot receive a secret. For an iOS simulator or macOS app, list its exact bundle identifier instead of a web origin.

Redaction and platform limits Link to Redaction and platform limits

Retest replaces known secret values with their placeholders in recorded text and in page text returned to the test. Check the result of signing in, such as the account label, rather than trying to read the password back.

A secret source can also be a function, called for each fill with an abort signal. If it throws or returns invalid text, the fill fails with setup_failed; see Configuration options for the source contract.

Pixels can show a secret

Screenshots and recordings are not redacted. A password your app displays can appear in them, even when recorded text is hidden. See Recordings and evidence for the capture rules.

Browser sign-in state works on Chromium-family browsers, Firefox and WebKit. test.setup() cannot save or restore Electron or native app state. For persistent app data, see Electron apps, iOS simulator apps or macOS apps.

Next steps Link to Next steps