Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# @codeceptjs/mobilewright

> Experimental. Try it and [report issues](https://github.com/codeceptjs/mobilewright/issues).
> Experimental. Try it and [report issues](https://github.com/codeceptjs/mobilewright-helper/issues).

[CodeceptJS](https://codecept.io) helper for testing iOS and Android apps with [mobilewright](https://mobilewright.dev). It runs on simulators, emulators and real devices without an Appium server.

Expand Down Expand Up @@ -110,6 +110,10 @@ Appium contexts and web views, settings, network connection, activities, touch a

The mobilewright library sends no telemetry; only its own CLI does. The helper still sets `MOBILEWRIGHT_DISABLE_TELEMETRY=1` so the mobilecli server it starts inherits it.

## Demo

A runnable demo project lives in [demo/](./demo): CodeceptJS tests for the Sauce Labs My Demo App (React Native), ready to run on a booted Android emulator. See [demo/README.md](./demo/README.md).

## Development

```
Expand Down
55 changes: 55 additions & 0 deletions demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Mobilewright Demo

End-to-end tests for the [Sauce Labs My Demo App](https://github.com/saucelabs/my-demo-app-rn) (React Native), run with CodeceptJS and the Mobilewright helper — no Appium server involved.

## Prerequisites

- Node.js 22.12+
- An Android emulator (or iOS simulator) booted, or a connected device

Check your environment:

```sh
npx mobilewright doctor
npx mobilewright devices
```

Download the demo APK (the same one CI uses):

```sh
mkdir -p ../test/data
curl -fsSL -o ../test/data/MyRNDemoApp.apk https://github.com/saucelabs/my-demo-app-rn/releases/download/v1.3.0/Android-MyDemoAppRN.1.3.0.build-244.apk
```

## Run

From this folder:

```sh
npm i
npm i ../ # install the helper from this repository
npm test
```

For iOS: set `platform: 'ios'` in `codecept.conf.js` and install the simulator build (a `.zip` of the `.app` bundle) instead of the APK — see the links in `.github/workflows/ios.yml`.

The config uses `require: '../index.js'` so the demo runs straight from the repo checkout. In your own project install the published package instead:

```sh
npm i @codeceptjs/mobilewright --save-dev
```

and change the helper config to `require: '@codeceptjs/mobilewright'`.

## What it demonstrates

- launching and resetting the app between tests (`restart: 'app'`)
- locating elements: by visible text, by accessibility id (`~`), by the label next to a field
- deep links (`mydemoapprn://login`)
- filling fields with `secret()` to keep passwords out of logs
- screen rotation
- full-page and element screenshots

## Known flakiness

The login scenario may fail intermittently: after a deep link (or the post-login navigation) the accessibility tree dump sometimes comes back empty (a bare root node) even though the screen is rendered — visible on a screenshot, missing from `grabSource()`. Relaunching the app does not always recover it. This is an upstream mobilecli/mobilewright issue (Android emulator + React Native), not a problem in the test or the helper.
24 changes: 24 additions & 0 deletions demo/codecept.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import path from 'node:path'

export const config = {
tests: './*_test.js',
output: './output',
noGlobals: true,
helpers: {
// in your own project use: require: '@codeceptjs/mobilewright'
Mobilewright: {
require: '../index.js',
platform: 'android',
app: 'com.saucelabs.mydemoapp.rn',
installApps: path.resolve(import.meta.dirname, '../test/data/MyRNDemoApp.apk'),
actionTimeout: 10000,
waitForTimeout: 10000,
animations: 'off',
},
},
plugins: {
screenshot: { enabled: true }, // screenshot on failure
retryFailedStep: { enabled: true },
},
name: 'mobilewright-demo',
}
44 changes: 44 additions & 0 deletions demo/demo_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { secret } from 'codeceptjs'

Feature('Sauce Labs Store')

// The helper relaunches the app before every test (restart: 'app'),
// no Before() hook needed

Scenario('Product catalog', ({ I }) => {
I.waitForText('Products', 30)
I.saveScreenshot('01-catalog.png')
I.see('Sauce Labs Backpack')
I.grabNumberOfVisibleElements('~store button') // catalog items
})

Scenario('Open a product and add it to cart', ({ I }) => {
I.waitForText('Products', 30)
I.longPress('~longpress reset app', 2) // reset demo app state
I.click('Sauce Labs Backpack')
I.waitForElement('~Add To Cart button', 15)
I.saveScreenshot('02-product.png')
I.click('~Add To Cart button')
I.see('1', '~cart badge')
I.saveElementScreenshot('~cart badge', '03-cart-badge.png')
})

Scenario('Find a field by its label + deep link', ({ I }) => {
I.waitForText('Products', 30)
I.amOnPage('mydemoapprn://login')
I.waitForElement('~Username input field', 15)
I.saveScreenshot('04-login.png')
I.fillField('Username', 'bob@example.com')
I.fillField('Password', secret('10203040'))
I.click('~Login button')
I.waitForText('Products', 15)
I.saveScreenshot('05-after-login.png')
})

Scenario('Rotate the screen', ({ I }) => {
I.waitForText('Products', 30)
I.setOrientation('LANDSCAPE')
I.seeOrientationIs('LANDSCAPE')
I.saveScreenshot('06-landscape.png')
I.setOrientation('PORTRAIT')
})
Loading
Loading