Skip to main content
Port the user flows from your Selenium or Appium suite into *.test.yaml files. Move reusable page-object behavior into modules, configure browser or device settings in momentic.config.yaml, and retain explicit readiness checks where the app requires them. This is a manual translation of the test contract, not an import of WebDriver code or capabilities.

Prepare the project

  • Complete the web, iOS, or Android setup for the target you are migrating. Keep your existing runner and CI job while you verify the new tests.
  • Web tests run on Chromium, Google Chrome, or Chrome for Testing. Keep Selenium coverage for Firefox, Safari, or other required browser targets.
  • Mobile tests need an Android APK or an iOS simulator .app build. A device-signed .ipa is not a simulator build. Momentic supports emulators and simulators, not physical devices. Android runs require adb and an SDK path even when using remote emulators; local iOS runs require macOS, Xcode, and idb. See Android app setup and iOS app setup.
  • Pick one test and record its starting state, inputs, expected results, and cleanup. Include setup hidden in base classes, fixtures, and page-object constructors. Use the same app build and test data when comparing runners.

Before and after

A representative Selenium test (Java/TestNG, but the shape is the same in Python or JavaScript):
CheckoutTest.java
The Momentic version keeps the CSS targets and URL pattern. Browser JavaScript checks rendered text, and the Checkout button uses a natural-language target:
checkout.test.yaml
Web interaction steps wait for their target using the browser’s smart-waiting setting. Condition steps accept their own timeout. Preserve explicit waits when a transition can outlast the interaction’s default: the checks above wait for visibility and enabled state before clicking. Each check has its own deadline. A Selenium Duration.ofSeconds(10) becomes timeout: 10000, not timeout: 10. See auto-waiting. Keep readiness checks for conditions that finding a target does not establish, such as a completed background save. The JavaScript loop above preserves the cart’s rendered-text wait; its step timeout allows the polling loop to finish. An AI assert checks meaning; it does not preserve a literal text equality or substring assertion. Web element content checks compare DOM textContent, which can include hidden text. Selenium getText() reads rendered text. Use a browser JavaScript check, as above, when that distinction affects coverage; review whitespace and visibility behavior for your app.

Appium example

An Appium Java test might enter an email, continue, and compare the welcome message exactly:
In Momentic, describe the intended controls and retain the exact text check. Install the same APK through the run command’s build options before this test runs:
mobile-tests/welcome.test.yaml
The accessibility ID is no longer a selector object. Confirm that the description identifies the same element, especially when multiple controls have the same text. Keep the original wait and reset behavior if the test’s fixtures add it outside this excerpt.

API mapping

Page objects and helpers

Extract reusable page-object actions into modules. You do not need a module for every page class. Keep assertions that define a test’s result in the calling test. This web module accepts credentials:
modules/log-in.module.yaml
Call it from before: or steps: with inputs. Callers pass concrete values or env references. For example, a web test can call the module during setup:
account.test.yaml
Declare TEST_PASSWORD in the selected environment’s secret configuration. A module input such as env.TEST_PASSWORD is a JavaScript expression; { string: ... } is a literal. Mobile modules use fileType: momentic/mobile-module/v2, a platform, and a different parameter declaration. See module parameters. Modules cannot call other modules. Flatten page-object methods that call other helpers into a single module, or call the modules in sequence from the test.

Setup, teardown, and state

Move per-test fixtures such as @BeforeMethod, @AfterMethod, or pytest fixtures into before and after. A failed setup skips the main steps. Teardown runs after setup or main-step failures; make cleanup tolerate data that setup never created. Run the whole test when validating hooks: running an individual editor step skips them. See before and after sections. Suite-wide build commands and external service startup belong in your CI job. Keep test data independent: allocate unique accounts or records per test, and clean up only those records. A new browser or device session does not reset shared backend data. Configure credentials through environments, rather than copying secrets from driver setup into YAML. For Appium, check the old reset, permissions, app installation, and launch behavior separately. openApp launches the installed app; it does not express all the behavior of an Appium capabilities object. killApp stops the current foreground app. Use it before openApp only when the intended app is already in the foreground. For an Android restart that targets a package regardless of foreground state, use the named-package restart example. Preserve any required data reset explicitly; stopping an app does not clear its data.

Reuse setup and custom code

  • javascript steps provide axios, pg, faker, and child_process in a Node sandbox. Reuse seed endpoints and database operations, but adapt helpers that depend on your test framework or imported packages. The sandbox does not expose your Selenium or Appium driver object. See JavaScript integration.
  • Rewrite JavascriptExecutor page scripts as web javascript steps with environment: browser. Replace driver argument references with DOM queries and return or throw explicitly. Mobile JavaScript has no browser execution context.
  • On mobile, appium executes a named script with JSON-string arguments. Command availability and arguments depend on the device platform. Verify each script on the selected emulator or simulator before retiring its legacy coverage.
  • Replace the grid and driver setup with npx momentic install-browsers chromium (web) or a hosted browser/emulator. See Hosted test environments.

What does not map

  • 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.
  • Selectors still work as targets, but the intended use is natural language. Web steps accept CSS selectors, not WebDriver By objects. Rewrite XPath or mobile selector objects as a description of the intended target. Preserve index, ancestor, and state constraints when they distinguish the target.
  • A custom ExpectedCondition does not translate by name. Use a supported condition step or rewrite a DOM check as browser JavaScript. Preserve its timeout and failure behavior; a single JavaScript evaluation is not a polling wait.
  • Remote execution covers Android emulators and iOS simulators, not physical device farms. Keep a device-farm runner for the tests that need hardware.
  • Selenium suites that drive WebDriver against non-browser targets do not map; Momentic tests browsers and mobile apps.

Selenium, Playwright, or Momentic in 2026

Choose per flow based on required browsers and devices, framework-dependent helpers, and the maintenance work you can measure:
  • Keep Selenium or Appium coverage for unsupported browsers, physical devices, or driver-specific behavior you still need. A stable suite may not need a migration.
  • Compare a Playwright port when you want to retain browser tests as code. Inventory selector, wait, fixture, and CI changes before estimating the work.
  • Port a bounded flow to Momentic when you want repository YAML with preset steps, AI actions, and modules. Adapt its setup, assertions, and cleanup using this guide, then compare the run evidence with the original test.
Estimate migration effort from that pilot, including authoring, review, helper adaptation, and CI changes. A coding agent can draft YAML, but you still need to verify the test’s behavior. Replace coverage only after the migrated flow passes the checks below. Do not port a suite you plan to retire.

Incremental strategy

  1. Pick one bounded flow with recurring locator or wait failures. Port its setup, steps, assertions, and cleanup to a single *.test.yaml before converting the rest of the suite.
  2. Lint and run that file using the commands below. Compare the original and migrated run evidence on the same build. Check that the assertion fails when the expected outcome is absent; a passing happy path alone is not evidence of equivalent coverage.
  3. Extract modules once another test needs the same sequence. For mobile, verify the build, OS version, app state, and permissions on your intended local or remote target.
  4. Add a separate Momentic CI job. Keep the Selenium or Appium job and its reports while you compare failures. Use separate test data when both jobs mutate the same backend.
  5. Replace gates flow by flow after reviewing equivalent coverage and repeated results. Retain legacy tests for unsupported browsers, hardware, and custom behavior. Retire their grid or device-farm jobs only when that coverage is no longer required.
For the web example, lint and run from the configured project root:
For the Android example on a local AVD, provide both the AVD and APK:
For iOS, use --local-ios-device-type and --local-app-path instead, or upload the build and select a channel and tag for remote execution. See mobile run options. The AVD name and build path above must match your machine. In CI, use the same committed test files and lockfile, set MOMENTIC_API_KEY from your CI secret store, and install the browser or device prerequisites. Keep the CLI’s exit status as the job result and publish the JUnit report from ./reports. See GitHub Actions or the other CI guides.

Porting at scale with a coding agent

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