Parallelism, Projects & Retries
Run tests on multiple devices at once, target iOS and Android from one config with projects, and retry flaky tests automatically.
Workers = Devices
Mobilewright runs tests in parallel using workers — independent processes that each hold a connection to one device or simulator. Two workers means two devices running two tests at the same time. To actually use multiple devices you need both a higher worker count and fullyParallel: true (without it, all tests in one file stay on the same worker):
import { defineConfig } from 'mobilewright';
export default defineConfig({
// Two devices running tests at the same time
workers: 2,
// Required: lets tests from the same file spread across workers
fullyParallel: true,
});
const { defineConfig } = require('mobilewright');
module.exports = defineConfig({
// Two devices running tests at the same time
workers: 2,
// Required: lets tests from the same file spread across workers
fullyParallel: true,
});
Serial Mode for Dependent Tests
Some flows must run in order — sign in, add to cart, check out. Mark the group serial so the tests share one device and run sequentially. If one fails, the rest are skipped, and the whole group retries together:
import { test, expect } from '@mobilewright/test';
// These tests run in order on the same device
test.describe.configure({ mode: 'serial' });
test('sign in', async ({ screen }) => { /* ... */ });
test('add to cart', async ({ screen }) => { /* ... */ });
test('complete purchase', async ({ screen }) => { /* ... */ });
const { test, expect } = require('@mobilewright/test');
// These tests run in order on the same device
test.describe.configure({ mode: 'serial' });
test('sign in', async ({ screen }) => { /* ... */ });
test('add to cart', async ({ screen }) => { /* ... */ });
test('complete purchase', async ({ screen }) => { /* ... */ });
Projects: iOS and Android in One Config
A project is a named group of tests with its own configuration. The classic use-case: run your whole suite on both platforms from a single config file. Running npx mobilewright test then executes every test twice — once per project:
import { defineConfig } from 'mobilewright';
export default defineConfig({
bundleId: 'com.example.myapp',
timeout: 120_000,
workers: 2,
projects: [
{
name: 'ios',
use: { platform: 'ios', installApps: 'ios/MyApp.zip' },
},
{
name: 'android',
use: { platform: 'android', installApps: 'android/MyApp.apk' },
},
],
});
const { defineConfig } = require('mobilewright');
module.exports = defineConfig({
bundleId: 'com.example.myapp',
timeout: 120_000,
workers: 2,
projects: [
{
name: 'ios',
use: { platform: 'ios', installApps: 'ios/MyApp.zip' },
},
{
name: 'android',
use: { platform: 'android', installApps: 'android/MyApp.apk' },
},
],
});
Target one platform with npx mobilewright test --project=android.
Retries: Taming Flaky Tests
Mobile tests can be flaky — network, timing, device state. With retries configured, a failing test is automatically re-run: the app is terminated and relaunched on the same device (fast — no re-allocation), and the test gets another chance. A test that passes on a retry is reported as flaky, not failed:
import { defineConfig } from 'mobilewright';
export default defineConfig({
// Retry twice in CI, never locally
retries: process.env.CI ? 2 : 0,
});
const { defineConfig } = require('mobilewright');
module.exports = defineConfig({
// Retry twice in CI, never locally
retries: process.env.CI ? 2 : 0,
});
A common pattern is retries in CI only, keeping local feedback fast — and you can check testInfo.retry inside a test to clear leftover state before a re-run.
Written by PV
© 2026 All Rights Reserved