> ## 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` (use `--platform ios` or `--platform android` for mobile). Never run an interactive command in a non-TTY shell.
> You cannot complete the browser sign-in yourself. Read the API key from the MOMENTIC_API_KEY environment variable, 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.

Cypress specs chain commands on `cy`. Momentic tests are YAML steps that a
runner executes with built-in waiting and AI assertion. The porting unit is the
user flow, not the command chain. A coding agent with the
[MCP server](/docs/coding-agents/mcp-server) and
[coding agent skills](/docs/coding-agents/skills) ports a spec file in one pass.

## Before and after

A representative Cypress spec:

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

  it("lets a guest 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.findByRole("button", { name: "Checkout" }).click();
    cy.get("#email").type("jeff@example.com");
    cy.findByRole("button", { name: "Place order" }).click();
    cy.location("pathname").should("match", /\/orders\/\w+/);
    cy.contains("Order confirmed").should("be.visible");
  });
});
```

The same test in Momentic:

```yaml checkout.test.yaml theme={null}
fileType: momentic/test/v2
id: guest-checkout
url: https://shop.example.com/products/42
labels: [checkout]
before:
  - module: ../modules/log-in.module.yaml # your cy.session equivalent
steps:
  - mock:
      substring: /api/cart
      method: get
      responseGenerator: |-
        return new Response(
          JSON.stringify([{ id: 1, title: "Gravity Blanket", qty: 1 }]),
          { status: 200, headers: { "content-type": "application/json" } })
  - click: Add to cart
  - click: the cart icon
  - assert: The cart lists "Gravity Blanket"
  - click: Checkout
  - type:
      text: jeff@example.com
      into: the Email field
  - click: Place order
  - waitForUrl:
      regex: /\/orders\/\w+/
  - assert: An order confirmation is visible
```

## 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)`                     | `assert: "<text> is visible"` or `checkPageContains`                                                     |
| `.type(value)`                          | `type: { text: ..., into: <field> }`                                                                     |
| `.should("be.visible")` / assertions    | `checkElementVisible` / `assert:`                                                                        |
| `cy.location().should(match)`           | `waitForUrl: { regex }`                                                                                  |
| `cy.intercept(...)`                     | [`mock`](/docs/reference/commands/mock) (`substring`, `glob`, `regex`, `domain`)                              |
| `cy.wait("@alias")`                     | `registerRequestListener` + `awaitListener` to capture the payload; nothing when only ordering matters   |
| `cy.wait(ms)`                           | `wait: <ms>` (prefer an `assert` with `timeout` when a signal exists)                                    |
| `cy.getCookie` / `cy.setCookie`         | `cookie: name=value` sets one cookie; browser `javascript` reads them (HttpOnly stays unreadable)        |
| `cy.clearLocalStorage`                  | browser `javascript` calling `localStorage.clear()`; `localStorage` step only writes keys                |
| `cy.go("back")` / `"forward"`           | `goBack` / `goForward`                                                                                   |
| `cy.select(...)`                        | `select` step, or `click` the option                                                                     |
| `cy.on("window:alert"/"confirm")`       | `dialog: ACCEPT` or `DISMISS`, placed before the step that raises it                                     |
| `cy.screenshot()`                       | automatic per-step screenshots; `assertVisually` for visual checks                                       |
| `cy.fixture("cart.json")`               | inline the JSON into `mock.responseGenerator`, or read files with `child_process` in a `javascript` step |
| `cy.request(...)`                       | `javascript` step (`fetch` is available) or `graphqlRequest`                                             |
| `cy.session(...)`                       | `authLoad`/`authSave` steps, or a login module in `before:`                                              |
| `Cypress.Commands.add(...)`             | [module](/docs/core-concepts/modules)                                                                         |
| `cy.viewport(...)`                      | no equivalent; the runner controls the viewport                                                          |
| `it.skip` / `it.only`                   | `disabled: true` on the test, `--filter`/`--labels` at run time                                          |
| `cypress.config.ts` `baseUrl`           | `environments[].baseUrl`                                                                                 |
| `Cypress.env(...)`                      | `env.<NAME>` variables from `environments[].envVariables`                                                |
| Retry-ability of `cy.*`                 | steps poll targets and conditions until their `timeout`; `retries:` reruns a failed step                 |
| `cy.origin(...)` for cross-origin flows | unnecessary; steps work across origins and `newTab`                                                      |

## Fixture and plugin mapping

| Cypress                                | Momentic                                                                                                                                                                                                                                   |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `cypress/fixtures/*.json`              | Keep the files where they are. Read them with `child_process` (for example `execSync("cat cypress/fixtures/cart.json")`) in a `javascript` step and `setVariable`/`saveAs` the parsed value, or inline the payload into a `mock` response. |
| `cypress/support/commands.js`          | Each `Cypress.Commands.add` becomes a `*.module.yaml`. Parameters map to module `parameters`; call sites become `module:` steps with `inputs`.                                                                                             |
| `cypress.config.ts` plugins / `task()` | A `javascript` step runs Node in a sandbox. Database seeding, email inboxes, and file work port directly. See [JavaScript integration](/docs/integrations/javascript).                                                                          |
| `e2e` folder structure                 | Keep the same directories; Momentic discovers `*.test.yaml` through the `include` globs in `momentic.config.yaml`.                                                                                                                         |
| Component testing                      | No equivalent. Momentic is end-to-end only; keep Cypress or Vitest for component tests if you use them.                                                                                                                                    |

## What does not map

* **The command queue and `cy` object.** Steps are data, not a chained API.
  Anything you built on `cy.wrap`, subjects, or custom queue manipulation needs
  a `javascript` step.
* **`cy.spy`/`cy.stub` on window functions.** There is no step for spying on app
  internals. `mock` covers network interception; reach for `javascript` with
  `environment: browser` for the rest.
* **`cypress-real-events` and raw Chrome DevTools Protocol (CDP).** Momentic
  abstracts the driver. Device trust and CDP-specific tricks have no direct
  equivalent.
* **Time-travel snapshots UI.** The local editor and run viewer show the same
  evidence (video, per-step screenshots, DOM state) but it is not a scrubbable
  command log.

## Incremental strategy

1. Install `momentic` next to Cypress in the same repo:
   `npm install -D momentic` plus a minimal `momentic.config.yaml`. The two
   tools do not share files or ports.
2. Port `cy.session`/login first as a module or `authLoad` file; every other
   port depends on it.
3. Port the specs that hurt the most to maintain: the ones with the most
   selector churn. Label them `migrated` and run them with `--labels migrated`.
4. Run both suites in CI. Keep Cypress gating until the Momentic suite covers
   the same critical paths.
5. Retire specs one at a time after several consecutive passing Momentic runs.
   Remove `@cypress/*` dependencies and the `cypress` folder last.

## Porting at scale with a coding agent

Point your coding agent at the spec files and the
[`momentic-test` skill](/docs/coding-agents/skills). A prompt that works well:

```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 each cy.intercept
to a mock step. Reuse cypress/fixtures JSON files as-is. 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)
