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

# app

> The portable app lifecycle fixture, available on every platform.

The `app` fixture opens, restarts, and resets the app under test, and takes
screenshots and recordings. It is on every target. A method the engine can't perform fails
with `UNSUPPORTED_CAPABILITY`.

```ts title="tests/billing.e2e.ts"

test('billing page', async ({ app, screen }) => {
  await app.open('/settings/billing');
  await expect(screen.getByRole('heading', { name: 'Billing' })).toBeVisible();
  await app.screenshot('billing');
});
```

## Reference

| Member | Returns |
| --- | --- |
| [`baseUrl`](#baseurl) | `string \| undefined` |
| [`open`](#open) | `Promise<void>` |
| [`restart`](#restart) | `Promise<void>` |
| [`clearState`](#clearstate) | `Promise<void>` |
| [`back`](#back) | `Promise<void>` |
| [`screenshot`](#screenshot) | `Promise<string>` |
| [`startRecording`](#startrecording) | `Promise<void>` |
| [`stopRecording`](#stoprecording) | `Promise<[RecordedVideo, ...RecordedVideo[]]>` |

`open`, `restart`, and `clearState` are bounded by `timeout`. The others
are bounded by `actionTimeout`. Both come from the
[config](https://e2e.tester.army/docs/reference/config): `timeout` defaults to 120000 ms and
`actionTimeout` to 30000 ms. The remaining test timeout caps both. `app`
methods take no per-call timeout option.

### `baseUrl`

The resolved base URL of the target's app.

```ts
const health = await fetch(`${app.baseUrl}/api/health`);
```

- When `app.url` declares port `0`, `baseUrl` carries the port the run
  allocated.
- On a target that declares no `app.url`, it is `undefined`.

### `open`

Opens the app: the declared URL, a path relative to it, or any absolute
`http(s)` URL.

```ts
await app.open(); // the target's app.url
await app.open('/settings/billing'); // a path relative to app.url
await app.open('https://example.com/login'); // any http(s) URL
```

On a device target, which has no URL, `open()` launches the pinned app fresh
and takes no path.

| Throws | When |
| --- | --- |
| `APP_URL_REQUIRED` | A path, on a target that declares no `app.url`. |
| `POLICY_DENIED` | A URL whose scheme is not `http:` or `https:`. `about:blank` is allowed. |
| `APP_UNREACHABLE` | The app URL could not be reached. |
| `ACTION_FAILED` | The operation failed or timed out. |
| `UNSUPPORTED_CAPABILITY` | No `session.open` on a target with a URL, or no `session.restart` on one without. |

### `restart`

Recreates the execution context and keeps persisted state. Then it reopens
the app at its base URL when the target declares one.

```ts
await app.restart();
```

| Throws | When |
| --- | --- |
| `ACTION_FAILED`, `ENGINE_FAILURE` | The operation or the engine failed. |
| `UNSUPPORTED_CAPABILITY` | No `session.restart`. |

### `clearState`

Clears persisted client state and recreates the execution context. Then it
reopens the app at its base URL when the target declares one.

```ts
test.beforeEach(async ({ app }) => {
  await app.clearState();
});
```

| Throws | When |
| --- | --- |
| `ACTION_FAILED`, `ENGINE_FAILURE` | The operation or the engine failed. |
| `UNSUPPORTED_CAPABILITY` | No `session.reset`. |

<Warning>
`clearState` inside a serial group destroys the shared state the group
depends on. Use it in `beforeEach` of an ordinary group instead.
</Warning>

### `back`

Navigates back once.

```ts
await app.back();
```

| Throws | When |
| --- | --- |
| `APP_NOT_OPEN` | `app.open()` has not run, or the engine reported invalid state. |
| `ACTION_FAILED` | The operation failed or timed out. |
| `UNSUPPORTED_CAPABILITY` | No `session.back`. |

### `screenshot`

Captures a redacted evidence screenshot and returns its path.

```ts
const shot = await app.screenshot('after-checkout');
```

- The file is an attempt artifact under `screenshots/`. The returned path is
  absolute. The report records the path relative to the artifact root.
- `label` names the step and joins the file name.

| Throws | When |
| --- | --- |
| `UNSUPPORTED_CAPABILITY` | The engine takes no screenshots. |
| `ENGINE_FAILURE` | The capture failed. |

<Note>
The screenshot masks secure fields only, after a `Secret` fill too. A secret
the app shows anywhere else is in the image. See
[screenshots after a secret fill](https://e2e.tester.army/docs/reference/security#screenshots-after-a-secret-fill).
</Note>

### `startRecording`

Starts recording the screen, until `stopRecording`.

```ts
test('the dialog slides in', { video: 'off' }, async ({ app, screen }) => {
  await app.open();
  await app.startRecording({ name: 'dialog' });
  await screen.getByRole('button', 'Open').tap();
  await expect(screen.getByRole('dialog')).toBeVisible();
  const [video] = await app.stopRecording();
});
```

- One recording at a time. The engine has one recorder, so set
  `video: 'off'` on the test: a start fails while the test's
  [video](https://e2e.tester.army/docs/reference/config#video) records. That includes `--video`,
  `retain-on-failure`, and the retries `on-first-retry` records.
- A recording still running when the test ends is stopped and kept.
- Like the test's video, a recording masks nothing.

| Throws | When |
| --- | --- |
| `UNSUPPORTED_CAPABILITY` | The test's video records, or the engine records no video. |
| `INVALID_ARGUMENT` | Another recording is running. |

### `stopRecording`

Stops the recording and returns its videos, in play order.

```ts
const [video] = await app.stopRecording();
if ('path' in video) console.log(video.path);
```

- A video is a file (`path`, absolute) under the attempt's `recordings/`,
  named `001-<name>.<ext>`, or a `url` when a hosted browser or device
  keeps the recording.
- There is one video, except on the web when the page was replaced while
  it recorded (`app.restart()`, `app.clearState()`): then one per page.
- The step links each video in the trace.

| Throws | When |
| --- | --- |
| `INVALID_ARGUMENT` | No recording is running. |
| `ENGINE_FAILURE` | The engine wrote no video. |

## Types

```ts
export interface App {
  /**
   * The resolved base URL of the target's app, with the port the run
   * allocated when `app.url` declared port 0; undefined for a target that
   * declares no `app.url`.
   */
  readonly baseUrl: string | undefined;
  /**
   * Opens the app: the declared URL, a path relative to it, or any absolute
   * http(s) URL. On a device target, which has no URL, it launches the pinned
   * app fresh and takes no path.
   */
  open(path?: string): Promise<void>;
  /**
   * Recreates the execution context while preserving persisted state, then
   * reopens the app at its base URL when the target declares one.
   */
  restart(): Promise<void>;
  /**
   * Clears persisted client state, recreates the execution context, then
   * reopens the app at its base URL when the target declares one.
   */
  clearState(): Promise<void>;
  /** Navigates back once. */
  back(): Promise<void>;
  /** Captures a redacted evidence screenshot and returns its absolute path. */
  screenshot(label?: string): Promise<string>;
  /**
   * Starts recording the screen, until `stopRecording`. One recording at a
   * time, and none while the test's `video` records: set `{ video: 'off' }`
   * on the test.
   */
  startRecording(options?: RecordingOptions): Promise<void>;
  /**
   * Stops the recording and returns its videos in play order: one, or on the
   * web one per page when the page was replaced while it recorded.
   */
  stopRecording(): Promise<readonly [RecordedVideo, ...RecordedVideo[]]>;
}

/** How `app.startRecording` names its file. */
export interface RecordingOptions {
  /** File name stem, `recordings/001-<name>.<ext>`; defaults to `recording`. */
  readonly name?: string;
}

/** One video `app.stopRecording` returns: a file, or a link to a recording a hosted service keeps. */
export type RecordedVideo = RecordedVideoFile | RecordedVideoLink;

/** A video file under the attempt's `recordings/` directory. */
export interface RecordedVideoFile {
  /** Absolute path of the file. */
  readonly path: string;
  /** When it started recording, as an ISO timestamp. */
  readonly startedAt: string;
}

/** A recording a hosted browser or device service keeps, by URL. */
export interface RecordedVideoLink {
  /** `http(s)` URL of the recording. */
  readonly url: string;
  /** Media type of what the URL serves: `video/mp4`, or `text/html` for a player page. */
  readonly mediaType: string;
  /** When it started recording, as an ISO timestamp. */
  readonly startedAt: string;
}
```

## Related

Browser-only operations live on the [`browser`](https://e2e.tester.army/docs/reference/web) fixture, and
device operations on [`device`](https://e2e.tester.army/docs/reference/mobile).
