Skip to main content

Deep Links

Use device.openUrl() to open a URL or custom scheme on the device. The OS routes the URL to the appropriate app — your own app, a system app, or the default browser.

await device.openUrl('myapp://home');

Try it: opening the phone dialer

The tel: scheme is available on every device and is a good way to verify your setup before testing your own app's scheme.

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

test('tel: scheme opens the phone dialer', async ({ device, screen }) => {
await device.openUrl('tel:+15550001234');
await expect(screen.getByText('Call')).toBeVisible();
});

Testing your app's custom scheme

Register your URL scheme in your app's manifest, then use it in tests to navigate directly to any screen.

On iOS, URL schemes are declared in Info.plist under CFBundleURLSchemes.

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

test('deep link opens product detail', async ({ device, screen }) => {
await device.openUrl('myapp://products/42');
await expect(screen.getByTestId('product-detail')).toBeVisible();
});

Universal Links (iOS) and App Links (Android) use https:// URLs instead of a custom scheme. The OS opens your app if it's installed, or the browser as a fallback.

test('universal link opens in-app', async ({ device, screen }) => {
await device.openUrl('https://example.com/products/42');
await expect(screen.getByTestId('product-detail')).toBeVisible();
});

Universal Links require an apple-app-site-association file hosted at https://example.com/.well-known/apple-app-site-association.

Deep links let you land a test directly on the screen it needs without tapping through the app, this makes each test fast and focused.

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

test.describe('order history', () => {
test.beforeEach(async ({ device }) => {
// Navigate straight to the screen under test
await device.openUrl('myapp://account/orders');
});

test('shows past orders', async ({ screen }) => {
await expect(screen.getByText('Your Orders')).toBeVisible();
});

test('empty state shown when no orders', async ({ screen }) => {
await expect(screen.getByTestId('empty-orders')).toBeVisible();
});
});

Passing parameters

Pass IDs, filters, or any state as path segments or query parameters — whatever your app's routing supports.

// Path parameter
await device.openUrl('myapp://users/99');

// Query parameter
await device.openUrl('myapp://search?q=headphones&sort=price');

// Combined
await device.openUrl('myapp://products/42?variant=blue&size=M');

Use device.getForegroundApp() to assert which app is in the foreground after opening a URL.

test('https link opens Safari when app is not installed', async ({ device }) => {
await device.openUrl('https://example.com');
const app = await device.getForegroundApp();
expect(app.bundleId).toBe('com.apple.mobilesafari');
});