> ## 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 Selenium and Appium

> Port WebDriver and Appium suites to Momentic, including page objects, explicit waits, capabilities, and driver escapes.

Selenium and Appium suites carry heavy framework overhead: driver setup,
capability negotiation, explicit waits, page objects, and a grid. In Momentic,
all of that collapses into `*.test.yaml` files plus `momentic.config.yaml`. You
port flows, not plumbing.

## Before and after

A representative Selenium test (Java/TestNG, but the shape is the same in Python
or JavaScript):

```java CheckoutTest.java theme={null}
@Test
public void guestCanBuyBlanket() {
  WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  driver.get("https://shop.example.com/products/42");
  wait.until(ExpectedConditions.elementToBeClickable(
      By.cssSelector("[data-testid='add-to-cart']"))).click();
  driver.findElement(By.id("cart-icon")).click();
  wait.until(ExpectedConditions.textToBePresentInElementLocated(
      By.cssSelector(".cart-items"), "Gravity Blanket"));
  driver.findElement(By.xpath("//button[contains(.,'Checkout')]")).click();
  WebElement email = wait.until(ExpectedConditions.visibilityOfElementLocated(
      By.name("email")));
  email.sendKeys("jeff@example.com");
  driver.findElement(By.cssSelector("button[type='submit']")).click();
  wait.until(ExpectedConditions.urlMatches("/orders/\\w+"));
  Assert.assertTrue(
      driver.findElement(By.tagName("body")).getText().contains("Order confirmed"));
}
```

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
steps:
  - 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
```

Every `wait.until(...)` disappears: Momentic steps poll until their target or
condition resolves, up to a per-step `timeout`. Every selector becomes either a
natural-language target or a CSS string inside the step.

## API mapping

| Selenium / WebDriver                     | Momentic                                                             |
| ---------------------------------------- | -------------------------------------------------------------------- |
| `driver.get(url)`                        | `navigate: <url>` or the test's top-level `url`                      |
| `findElement(By.*)` + `click()`          | `click: <natural language>` or `click: { css: "..." }`               |
| `sendKeys(value)`                        | `type: { text: ..., into: <field> }`                                 |
| `WebDriverWait` + `ExpectedConditions.*` | the step's own waiting, or `assert`/`checkElement*` with `timeout`   |
| `Thread.sleep(ms)`                       | `wait: <ms>` (prefer a condition)                                    |
| `Assert.assertEquals` etc.               | `assert:` for semantic checks, `checkElementContent` for exact text  |
| `Actions` chains (hover, drag)           | `hover`, `dragAndDrop`, `mouseDrag`                                  |
| `driver.navigate().back()` / `forward()` | `goBack` / `goForward`                                               |
| `switchTo().window()` / tabs             | `newTab` / `closeTab`                                                |
| `switchTo().alert().accept()`/dismiss    | `dialog: ACCEPT` or `DISMISS`, placed before the step that raises it |
| `driver.manage().cookies()`              | `cookie` step; `localStorage` step for storage                       |
| `JavascriptExecutor`                     | `javascript` step with `environment: browser`                        |
| Screenshots on failure                   | automatic per-step screenshots; video needs `recordVideo`            |
| `DesiredCapabilities` / `ChromeOptions`  | `browser:` and `environments[]` in `momentic.config.yaml`            |
| Selenium Grid / BrowserStack / Sauce     | `browser.remoteBrowser: true` runs browsers on Momentic infra        |
| JUnit/TestNG/pytest reports              | `--reporter junit`                                                   |

| Appium                                         | Momentic (`momentic-mobile`)                               |
| ---------------------------------------------- | ---------------------------------------------------------- |
| `driver.activateApp(bundleId)`                 | `openApp: <package or bundle id>`                          |
| `driver.terminateApp`                          | `killApp`                                                  |
| `findElement` + `click()`                      | `tap: <natural language>`                                  |
| `sendKeys`                                     | `type: { text: ..., into: <field> }`                       |
| `TouchAction` / W3C gestures                   | `swipe`, `dragAndDrop`, `scrollTo`                         |
| `driver.pressKey`                              | `press` / `pressKey`                                       |
| `driver.execute("mobile: ...")`                | `appium` step: the raw escape hatch stays                  |
| `adb` shell commands                           | `adb` step                                                 |
| Desired/app capabilities (`platformName`, ...) | `platform:` on the test plus `momentic-mobile.config.yaml` |
| Local emulator/device farm                     | remote emulators and simulators hosted by Momentic         |

## Page objects and helpers

The Page Object Model maps to [modules](/docs/core-concepts/modules). Each
`LoginPage.java` becomes `modules/log-in.module.yaml` with `parameters` for its
inputs:

```yaml log-in.module.yaml theme={null}
fileType: momentic/module/v2
id: log-in
name: Log in
parameters:
  - name: USERNAME
  - name: PASSWORD
steps:
  - type:
      text: "{{ env.USERNAME }}"
      into: the Username field
  - type:
      text: "{{ env.PASSWORD }}"
      into: the Password field
  - click: the Submit button
```

Call it from `before:` or `steps:` with `inputs`. Callers pass concrete values
or `env` references, mirroring constructor-injected page objects.

## What keeps working unchanged

* **Your test data and seed APIs.** `javascript` steps run Node with `axios`,
  `pg`, `faker`, and `child_process`. Existing seed endpoints and database
  helpers port without redesign.
* **Appium-specific glue.** On mobile, the `appium` step executes arbitrary
  `mobile:` scripts (`mobile: shell`, `mobile: deepLink`, gestures that no
  preset step covers). Port the common paths to natural-language steps and keep
  `appium` for the edge cases.
* **Your CI.** Replace the grid and driver setup with
  `npx momentic install-browsers chromium` (web) or a hosted browser/emulator.
  See [Hosted test environments](/docs/running-tests/hosted-test-environments).

## What does not map

* **Driver lifecycle control.** There is no `WebDriver` object to hold or pass.
  You cannot run two driver sessions in one test; parallel testing is per-test
  parallelism, not multi-session choreography.
* **XPath/CSS depth.** Selectors still work as targets, but the intended use is
  natural language. Complex XPath logic has no equivalent: express the element
  by what it looks like, and let [step caching](/docs/reliability/step-cache) keep it
  fast.
* **`ExpectedConditions` variety.** Momentic covers the common conditions
  (visible, text, URL, attribute) but not exotic ones like
  `elementSelectionStateToBe`. A `javascript` step in the browser can check
  anything the DOM exposes.
* **Real devices.** Remote execution covers Android emulators and iOS
  simulators, not physical device farms. Keep a device-farm runner for the tests
  that need hardware.
* **Non-HTTP protocols.** Selenium suites that drive WebDriver against
  non-browser targets do not map; Momentic tests browsers and mobile apps.

## Incremental strategy

1. Start on the suite's worst offender: the flakiest flow, the one with the most
   `ExpectedConditions`. Port it to a single `*.test.yaml` and run it daily for
   a week. This is the fastest way to see whether Momentic's waiting model holds
   up on your app.
2. Convert page objects to modules as you go; the second test on the same flow
   is nearly free.
3. For mobile, run a local emulator first (`momentic-mobile run` against your
   `.apk`/`.app`), then switch individual tests to remote instances through the
   Region selector.
4. Run Selenium and Momentic side by side in CI. Label ported tests and gate on
   them once they stabilize.
5. Retire the grid last: after the browser coverage you need is confirmed, not
   when the first suite passes.

## Porting at scale with a coding agent

Hand the port to your coding agent with a prompt like:

```text theme={null}
Port the Selenium tests in src/test/java/checkout/ to Momentic tests.
Read the momentic-test skill first. Write one *.test.yaml per @Test method,
convert each Page class to a *.module.yaml, drop all explicit waits, and keep
any JavascriptExecutor blocks as javascript steps. Run each ported test with
npx momentic run <file>.
```

## Related

* [Test portability](/docs/get-started/test-portability)
* [Web steps reference](/docs/reference/commands/index)
* [Mobile steps reference](/docs/reference/mobile-commands/index)
* [Hosted test environments](/docs/running-tests/hosted-test-environments)
* [Modules](/docs/core-concepts/modules)
