## JavaScript Steps

JavaScript steps execute code as part of a test. `async`/`await` is supported. Return values are passed to downstream steps and must be [JSON-serializable](https://en.wikipedia.org/wiki/Serialization).

```javascript
const res = await axios.post("https://api.example.com/login", {
  email: env.USERNAME,
  password: env.PASSWORD,
});

setVariable("SESSION_TOKEN", res.data.token);
return res.status;
```

## Execution Contexts

| Context           | When to use                                      | Access                                                             |
|-------------------|--------------------------------------------------|--------------------------------------------------------------------|
| **Node sandbox**   | Default. API calls, data prep, secret rotation, DB queries. | Momentic globals (see below)                                       |
| **Browser page**   | Enable **Execute in browser**. DOM queries, local storage. | `window`, `document`, page globals                                 |

Browser steps don’t have access to the Node sandbox globals. The browser context is available only for web tests. Mobile JavaScript runs in the Node sandbox.

## Timeout

JavaScript steps default to a **90-second** timeout. Configure per step via the **Timeout** field (seconds), or in simplified YAML (milliseconds):

```yaml
- javascript:
    code: |
      const msg = await email.fetchLatest({
        inbox: "qa+signup", // your Momentic-provisioned inbox prefix
        timeout: 60_000,
      });
      return msg.text;
    timeout: 120000
```

The maximum configurable timeout is **10 minutes** (600 seconds), suitable for long external polls or batched lookups against slow APIs. If a nested helper such as `email.fetchLatest` or `sms.fetchLatest` polls for longer than the JavaScript step’s own timeout, the step times out before the helper returns. Set the step’s **Timeout** to comfortably cover the longest nested poll.

## `{{ }}` Templating

Any string input on any step can contain `{{ expression }}`. Expressions evaluate at runtime and are interpolated into the value.

```yaml
- type:
    text: "{{ env.USERNAME }}@gmail.com"
    into: Email field
```

Don’t use `{{}}` inside **JavaScript** step source. Variables are already in scope as `env.VARIABLE_NAME`.

## Momentic Utilities

The Momentic runtime provides these globals.

### `env`

`env` is a read-only map of the current environment’s variables. See [Variables](/content/docs/core-concepts/variables/index.html) for how variables are resolved.

```javascript
const res = await axios.get("https://api.example.com/me", {
  headers: { Authorization: `Bearer ${env.API_TOKEN}` },
});
```

### `setVariable(name, value)`

`setVariable` writes a variable scoped to the current test run. Downstream steps can read it via `{{ env.NAME }}` in a string input, or via `env.NAME` inside JavaScript.

```javascript
const res = await axios.post("https://api.example.com/login", {
  email: env.USERNAME,
  password: env.PASSWORD,
});

setVariable("SESSION_TOKEN", res.data.token);
```

### `email`

`email` sends and fetches email. See [Email](/content/docs/integrations/email/index.html) for inbox setup.

```javascript
// fetch the latest verification email
const msg = await email.fetchLatest({
  inbox: "qa+signup", // your Momentic-provisioned inbox prefix
  timeout: 30_000,
});
const [code] = msg.text.match(/\b\d{6}\b/) ?? [];
if (!code) throw new Error("No verification code found in email");
setVariable("VERIFICATION_CODE", code);
```

### `sms`

`sms` sends and fetches SMS. See [SMS](/content/docs/integrations/sms/index.html) for number setup.

```javascript
const msg = await sms.fetchLatest({
  to: "+15551234567",
  timeout: 60_000,
});
const [code] = msg.body.match(/\b\d{6}\b/) ?? [];
if (!code) throw new Error("No OTP code found in SMS");
setVariable("OTP", code);
```

### `extractCookiesFromResponse(response)`

`extractCookiesFromResponse` converts a `fetch` / `axios` response’s `Set-Cookie` headers into cookie objects for a browser context. Use it to bootstrap an authenticated session.

```javascript
const res = await fetch("https://api.example.com/login", {
  method: "POST",
  body: JSON.stringify({ email: env.USERNAME, password: env.PASSWORD }),
});

const cookies = await extractCookiesFromResponse(res);
setVariable("AUTH_COOKIES", cookies);
```

### `mock`

`mock` is only available in **mock handler** steps on mocked routes. It exposes the intercepted `Request` and the upstream `Response`.

```javascript
// stub the /pricing response but forward everything else
if (mock.request.url.endsWith("/pricing")) {
  return new Response(JSON.stringify({ plan: "enterprise" }), {
    status: 200,
    headers: { "content-type": "application/json" },
  });
}
return mock.response;
```

## Libraries

### `axios`

`axios` is an HTTP client. See [axios docs](https://axios-http.com/docs/intro).

```javascript
const { data } = await axios.get("https://api.example.com/status");
assert.equal(data.ok, true);
```

### `assert`

`assert` provides Node’s built-in assertions. See [Node docs](https://nodejs.org/api/assert.html).

```javascript
assert.equal(res.status, 200);
assert.deepStrictEqual(res.data, { success: true });
```

### `faker`

`faker` generates realistic fake data. See [Faker docs](https://fakerjs.dev/api/).

```javascript
const email = faker.internet.email();
const name = faker.person.fullName();
setVariable("NEW_USER_EMAIL", email);
setVariable("NEW_USER_NAME", name);
```

### `moment`

`moment` parses and formats dates. See [Moment docs](https://momentjs.com/docs/).

```javascript
// pick a date 30 days from now, formatted for a date input
setVariable("FUTURE_DATE", moment().add(30, "days").format("YYYY-MM-DD"));
```

### `pg`

`pg` is a Postgres client. See [node-postgres docs](https://node-postgres.com/).

```javascript
const client = new pg.Client({ connectionString: env.DATABASE_URL });
await client.connect();
const { rows } = await client.query(
  "SELECT id FROM users WHERE email = $1 LIMIT 1",
  [env.TEST_EMAIL],
);
await client.end();
setVariable("USER_ID", rows[0].id);
```

### `OTPAuth`

`OTPAuth` generates time-based one-time password (TOTP) codes for two-factor authentication (2FA) tests. See [otpauth docs](https://github.com/hectorm/otpauth).

```javascript
const totp = new OTPAuth.TOTP({ secret: env.TOTP_SECRET });
setVariable("OTP_CODE", totp.generate());
```

### `child_process`

`child_process` spawns subprocesses. See [Node docs](https://nodejs.org/api/child_process.html).

```javascript
const { execSync } = child_process;
const branch = execSync("git rev-parse --abbrev-ref HEAD").toString().trim();
setVariable("GIT_BRANCH", branch);
```

### `Octokit` + `createAppAuth`

`Octokit` with `createAppAuth` provides authenticated GitHub API access. See [Octokit docs](https://github.com/octokit/octokit.js) and [auth-app docs](https://github.com/octokit/auth-app.js/).

```javascript
const octokit = new Octokit({
  authStrategy: createAppAuth,
  auth: {
    appId: env.GITHUB_APP_ID,
    privateKey: env.GITHUB_APP_PRIVATE_KEY,
    installationId: env.GITHUB_INSTALLATION_ID,
  },
});

const { data: pr } = await octokit.rest.pulls.get({
  owner: "momentic-ai",
  repo: "examples",
  pull_number: 42,
});
setVariable("PR_STATE", pr.state);
```
