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

> ## Agent Instructions
> The canonical docs host is https://momentic.ai/docs. Append .md to any page URL for clean Markdown. Fetch https://momentic.ai/docs/llms.txt for the page index and https://momentic.ai/docs/llms-full.txt for every page in one file.
> For an unattended setup, run `npx --yes @momentic/wizard@latest -y --platform web --editor-tools skills` (use `--platform ios` or `--platform android` for mobile). Never run an interactive command in a non-TTY shell.
> Mo is the AI QA engineer, a separate product from the YAML test framework: its npm package and CLI are `qa` (not `mo` — `npx mo` is a different project). Install with `npm install -g qa`, authenticate the same MOMENTIC_API_KEY way, install repo skills with `qa skills -y`, and start a session with `qa start "<brief>"` or `qa <url>`. Docs: https://momentic.ai/docs/mo.md.
> You cannot complete the browser sign-in yourself. Read the API key from the exact MOMENTIC_API_KEY environment variable (similarly named vars like BILT_MOMENTIC_API_KEY are ignored), or ask the user to create one at https://app.momentic.ai/settings/api-keys and paste it back.
> Momentic's capability summary for agents is at https://momentic.ai/docs/skill.md. Install the skills with `npx momentic skills --yes` (or `npx momentic-mobile skills --yes` for mobile).
> Tests are YAML files in the user's repository. Use only the step names listed at https://momentic.ai/docs/reference/commands.md and the file structure at https://momentic.ai/docs/core-concepts/file-format.md. Do not invent step names, config keys, or CLI flags.
> Web tests run on Chromium, iOS tests on simulators, and Android tests on emulators. Physical devices are not supported.

# From Cypress

> Port a Cypress suite to Momentic, including custom commands, fixtures, intercepts, and session caching.

Move one Cypress flow at a time, preserving its authentication, mocked
responses, actions, assertions, and cleanup. Momentic tests are YAML steps
rather than `cy` command chains. A coding agent with the
[MCP server](/docs/coding-agents/mcp-server) and
[coding agent skills](/docs/coding-agents/skills) can draft the port; review the
result against the spec before changing your CI gate.

## Before and after

This example assumes `baseUrl: https://shop.example.com`, an existing
`cy.loginByApi` custom command, and this cart fixture:

```json cypress/fixtures/cart.json theme={null}
[{ "id": 1, "title": "Gravity Blanket", "qty": 1 }]
```

Both tests use a signed-in test account and create an order. Isolate or reset
that account's server-side data between runs.

```js checkout.cy.js theme={null}
describe("checkout", () => {
  beforeEach(() => {
    cy.session("user", () => cy.loginByApi());
    cy.intercept("GET", "/api/cart", { fixture: "cart.json" }).as("cart");
    cy.visit("/products/42");
  });

  it("lets a signed-in shopper buy a blanket", () => {
    cy.get('[data-testid="add-to-cart"]').click();
    cy.get('[data-testid="cart-icon"]').click();
    cy.wait("@cart");
    cy.contains("Gravity Blanket").should("be.visible");
    cy.contains("button", "Checkout").click();
    cy.get("#email").type("jeff@example.com");
    cy.contains("button", "Place order").click();
    cy.location("pathname").should("match", /^\/orders\/\w+/);
    cy.contains("Order confirmed").should("be.visible");
  });
});
```

The same user-flow checks in Momentic. Before running it, create
`tests/modules/log-in.module.yaml` by porting `cy.loginByApi`; it must establish
and validate the same signed-in identity. See
[session and fixture scope](#session-and-fixture-scope) below.

```yaml tests/checkout/checkout.test.yaml theme={null}
fileType: momentic/test/v2
id: signed-in-checkout
url: https://shop.example.com
labels: [checkout]
before:
  - module: ../modules/log-in.module.yaml
  - mock:
      regex: /api/cart$
      method: get
      responseGenerator: |-
        return new Response(
          JSON.stringify([{ id: 1, title: "Gravity Blanket", qty: 1 }]),
          { status: 200, headers: { "content-type": "application/json" } }
        );
  - registerRequestListener:
      key: cart
      regex: /api/cart$
      method: get
  - navigate: https://shop.example.com/products/42
steps:
  - click: Add to cart
  - click: the cart icon
  - awaitListener: cart
  - checkElementVisible: the text "Gravity Blanket"
  - click: Checkout
  - type:
      text: jeff@example.com
      into: the Email field
      clear: never
  - click: Place order
  - waitForUrl:
      regex: ^https://shop\.example\.com/orders/\w+
  - checkElementVisible: the text "Order confirmed"
```

The mock and listener are registered before navigating to the product page. This
preserves the request wait, including a request made during page load. Adapt the
matcher if your endpoint has query parameters. The response body matches
`cart.json`; copying the filename alone would not load a fixture into a mock.
YAML `regex` values omit JavaScript's surrounding `/.../` delimiters.

Lint and run the new file alone, with whole-test retries disabled:

```bash theme={null}
npx momentic lint tests/checkout/checkout.test.yaml
npx momentic run tests/checkout/checkout.test.yaml --parallel 1 --retries 0 --upload-results
```

## API mapping

| Cypress | Momentic |
| - | - |
| `cy.visit(url)` | `navigate: <url>` or the test's top-level `url` |
| `cy.get(sel).click()` | `click: <natural language>` or `click: { css: sel }` |
| `cy.contains(text)` | `click` with a target to interact; `checkElementVisible` or `checkPageContains` to assert |
| `.type(value)` | `type: { text: ..., into: <field>, clear: never }` to append; `fill` replaces a value |
| `.should("be.visible")` / assertions | `checkElementVisible` for visibility; `assert` for semantic conditions |
| `cy.location().should(match)` | `waitForUrl: { regex }` |
| `cy.intercept(...)` | [`mock`](/docs/reference/commands/mock) with `substring`, `glob`, `regex`, or `domain` |
| `cy.wait("@alias")` | `registerRequestListener` before the trigger, then `awaitListener` to inspect the request/response |
| `cy.wait(ms)` | `wait: <ms>`; prefer a preset condition with a timeout when a signal exists |
| `cy.getCookie` / `cy.setCookie` | `cookie` sets cookies; browser `javascript` reads non-HttpOnly cookies |
| `cy.clearLocalStorage` | Browser `javascript` calling `localStorage.clear()`; `localStorage` writes keys |
| `cy.go("back")` / `"forward"` | `goBack` / `goForward` |
| `cy.select(...)` | `select` for a native select; `click` or an `act` goal for a styled dropdown |
| `cy.on("window:alert"/"confirm")` | `dialog: ACCEPT` or `DISMISS`, before the step that raises it |
| `cy.screenshot()` | Per-step screenshots; `assertVisually` / `visualDiff` for visual checks |
| `cy.fixture("cart.json")` | Inline JSON into the mock, or load it in Node `javascript` and pass the parsed value |
| `cy.request(...)` | `request`, `graphqlRequest`, or Node `javascript` with `fetch`; handle browser cookies explicitly |
| `cy.session(...)` | Explicit auth bootstrap with `authLoad`/`authSave`, a live login module, or a configured cached auth module |
| `Cypress.Commands.add(...)` | A [module](/docs/core-concepts/modules) for reusable test steps |
| `cy.viewport(...)` | Test `viewport` for initial size; no preset step to resize mid-test |
| `it.skip` / `it.only` | `disabled: true` skips a test; pass a test path or `--labels` to select tests |
| `cypress.config.ts` `baseUrl` | `environments[].baseUrl`, selected with `--env` or `defaultEnv` |
| `Cypress.env(...)` | `env.<NAME>` variables from `environments[].envVariables` |
| Retry-ability of queries/assertions | Use the matching preset check and timeout; preserve the condition rather than the command queue |
| Test retries | Test/config `retries` or `--retries` reruns the whole test; step `retries` repeats only that step |
| `cy.origin(...)` | Browser steps can navigate across origins; callback code and storage assumptions still need adaptation |

## Fixture and plugin mapping

| Cypress | Momentic |
| - | - |
| `cypress/fixtures/*.json` | Keep the payload. Read it with `child_process` in a Node `javascript` step and `setVariable`/`saveAs`, or inline it in a mock. Files must exist on the runner; check the working directory. |
| `cypress/support/commands.js` | Port reusable browser actions into modules. Parameters become module `parameters`; calls use `module` with `inputs`. Commands that call modules need restructuring: modules cannot call other modules. |
| `cypress.config.ts` plugins / `task()` | Port calls into the documented [JavaScript globals](/docs/integrations/javascript), or keep plugin-dependent helpers in a script before the CLI run. |
| `e2e` folder structure | Keep directories; configure `include` globs to discover the new `*.test.yaml` and `*.module.yaml` files. |
| Component testing | Keep Cypress or another component runner. Momentic tests the running app end to end. |

## Session and fixture scope

[`cy.session`](https://docs.cypress.io/api/commands/session) caches browser
state by an ID and can validate a restored session before rerunning login. A
live login module in Momentic's `before` runs on each whole-test attempt. For
reuse, configure a [cached auth module](/docs/guides/auth/cached-session) with an
explicit cache key and expiry; this does not port Cypress's session callback or
validation function. `authLoad` restores state without testing whether a
server-side session is still valid. Add an authenticated-page or API check, and
regenerate expired state in your bootstrap.

Port a login helper's API call with `request` or Node `javascript`. Browser
cookies are not established merely by calling `fetch` in Node: use
`extractCookiesFromResponse`, then `authLoad` with the resulting state, or
authenticate through the browser. See
[cookie extraction](/docs/integrations/javascript#extractcookiesfromresponse-response)
and [saved state](/docs/guides/auth/overview). Cypress's internal session cache is
not a Playwright storage-state JSON file you can give to `authLoad`.

Momentic initializes a browser for each whole-test attempt. Tests that rely on
Cypress
[`testIsolation: false`](https://docs.cypress.io/app/core-concepts/test-isolation)
need explicit per-test setup or one combined flow. Browser isolation does not
reset shared database records. Use unique accounts or records before enabling
parallel runs.

Map `beforeEach` and `afterEach` to `before` and `after`. Keep suite-level
`before`/`after` scripts outside the test unless repeating them per attempt is
intentional. Momentic teardown runs after setup or main-step failures and can
itself fail the test; initial navigation failure or process interruption can
prevent cleanup. Make cleanup idempotent and retain an external cleanup path.

Separate Cypress
[whole-test retries](https://docs.cypress.io/app/guides/test-retries) from query
retry behavior. Preset conditions can wait; step retries repeat the step and may
repeat side effects. Use checks or JavaScript that throws for exact response
values, counts, and text. Returning a value from JavaScript alone does not
assert it. Review AI assertions against the original expected state rather than
replacing them with a broad page-success check. Carry forward CSS constraints,
text matching rules, and scope from `cy.get`/`cy.contains`; keep an explicit CSS
target when a description cannot preserve them.

## What does not map

* There is no `cy` object or command queue. Port `cy.wrap` subjects into values
  passed through `saveAs`/`env`, and rewrite custom queue manipulation; a
  JavaScript step cannot execute a Cypress command chain.
* There is no preset equivalent of `cy.spy`/`cy.stub`. `mock` covers network
  interception; browser `javascript` can inspect the current page. It is not a
  drop-in replacement for stubs installed before app initialization.
* `cypress-real-events` and raw Chrome DevTools Protocol calls have no direct
  equivalent. Keep tests that require those behaviors in their existing runner.
* Cypress's time-travel snapshots UI has no scrubbable equivalent. Momentic's
  editor and run viewer expose screenshots, logs, and available recordings.
  Compare the evidence you rely on before retiring the original job.
* Keep Firefox/WebKit runs and component-test jobs in their existing runner.
  Momentic's web browser targets are Chromium-based; `--env` does not change
  that support boundary.

## Incremental strategy

1. Keep Cypress and its CI gate. Follow [web setup](/docs/quickstart/web) to add
   Momentic, preserving existing config. Commit the dependency lockfile and
   confirm the config includes your new test/module directories.
2. Inventory each flow's login helper, session validation, fixtures, intercepts,
   assertions, plugin tasks, and cleanup. Port authentication first and run it
   independently. Test both fresh login and expired saved state.
3. Port one critical flow and label it `migrated`. Lint it and run it alone with
   `--parallel 1 --retries 0`. In a test environment, confirm a deliberate
   response or assertion mismatch fails the replacement, then restore it.
4. Run a separate Momentic CI job with its own output directory and test data.
   Keep Cypress required while comparing the same critical paths. Preserve the
   request wait and response checks from every intercept; review any recovery,
   classification, or quarantine before accepting a passing result.
5. Switch the gate one flow at a time after repeated passes and a reviewed
   expected failure. Preserve the Cypress specs and CI config in Git so you can
   restore the old gate. Remove Cypress only after its remaining plugin,
   browser, and component coverage has a replacement.

Inspect the selected paths before running the overlap job:

```bash theme={null}
npx momentic lint
npx momentic list --labels migrated
npx momentic run --labels migrated --parallel 1 --retries 0 --ignore-quarantine --output-dir ./momentic-migration-results --upload-results --reporter junit
npx momentic results check ./momentic-migration-results
```

By default, `results check` rejects non-quarantined runs that failed, were
cancelled, recovered, or had a failure classification. It ignores quarantined
runs and accepts an archive with zero tests. The recipe uses
`--ignore-quarantine` so quarantine does not mask the selected tests' statuses;
confirm the list and run totals contain the enabled tests you intend to port.
`--filter` selects a workspace project, not a Cypress spec. See
[results checks](/docs/cli-reference/momentic/commands/results#check) and
[GitHub Actions](/docs/running-tests/ci/github-actions) for CI setup.

## Porting at scale with a coding agent

Point your coding agent at the spec files and the
[`momentic-test` skill](/docs/coding-agents/skills). Use a prompt that names the
behavior to preserve:

```text theme={null}
Port cypress/e2e/checkout.cy.js to Momentic tests under tests/checkout/.
Read the momentic-test skill first. Convert each it() to a *.test.yaml, each
custom command to a *.module.yaml under tests/modules/, and stubbed cy.intercept
calls to mock steps. Use registerRequestListener and awaitListener for spy-only
intercepts and alias waits. Reuse cypress/fixtures JSON payloads, loading or
inlining them explicitly. Run each ported test
with npx momentic run <file>.
```

## Related

* [Test portability](/docs/get-started/test-portability)
* [Web steps reference](/docs/reference/commands/index)
* [Modules](/docs/core-concepts/modules)
* [Mock network routes](/docs/reference/commands/mock)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.