Skip to main content

Writing Tests

First test

Mobilewright tests are written in TypeScript using the test and expect functions from @mobilewright/test.

import { test, expect } from '@mobilewright/test';

test('app launches and shows home screen', async ({ screen }) => {
await expect(screen.getByText('Welcome')).toBeVisible();
});

Each test receives a screen fixture that lets you find elements and interact with them. Assertions like toBeVisible() auto-wait until the condition is met.

Actions

Finding elements

Use locator methods on screen to find elements:

// By visible text
screen.getByText('Sign In');

// By accessibility label
screen.getByLabel('Username');

// By test ID (accessibilityIdentifier on iOS, resourceId on Android)
screen.getByTestId('submit-button');

// By semantic role
screen.getByRole('button', { name: 'Submit' });

// By element type
screen.getByType('TextField');

Tapping

await screen.getByText('Sign In').tap();
await screen.getByRole('button', { name: 'Submit' }).doubleTap();
await screen.getByText('Options').longPress();

Filling text fields

await screen.getByLabel('Email').fill('user@example.com');
await screen.getByLabel('Password').fill('secret');

Swiping

await screen.swipe('up');
await screen.swipe('down', { distance: 300 });

Pressing hardware buttons

await screen.pressButton('HOME');
await screen.pressButton('BACK'); // android only

Assertions

Use expect to verify the state of elements. Assertions auto-wait and retry until the condition is met or the timeout expires.

await expect(screen.getByText('Welcome')).toBeVisible();
await expect(screen.getByRole('button', { name: 'Submit' })).toBeEnabled();
await expect(screen.getByTestId('greeting')).toHaveText('Hello, World');

See the Assertions guide for the full list.

Chaining locators

Locators can be chained to narrow the search within a parent element:

const row = screen.getByType('Cell').first();
await row.getByRole('button', { name: 'Delete' }).tap();

Collection methods

// Get specific elements from a set of matches
screen.getByRole('button').first();
screen.getByRole('button').last();
screen.getByRole('button').nth(2);

// Count matching elements
const count = await screen.getByRole('listitem').count();

// Iterate over all matches
const items = await screen.getByRole('listitem').all();

Grouping tests

Use test.describe to group related tests:

import { test, expect } from '@mobilewright/test';

test.describe('login flow', () => {
test('shows login form', async ({ screen }) => {
await expect(screen.getByLabel('Email')).toBeVisible();
await expect(screen.getByLabel('Password')).toBeVisible();
});

test('rejects invalid credentials', async ({ screen }) => {
await screen.getByLabel('Email').fill('bad@example.com');
await screen.getByLabel('Password').fill('wrong');
await screen.getByRole('button', { name: 'Sign In' }).tap();
await expect(screen.getByText('Invalid credentials')).toBeVisible();
});
});

Using the device fixture

When you need device-level control beyond the screen, use the device fixture:

import { test, expect } from '@mobilewright/test';

test('deep link opens profile', async ({ device, screen }) => {
await device.openUrl('myapp://profile/123');
await expect(screen.getByText('Profile')).toBeVisible();
});