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');
});