Once set up, interacting with the native UI using Patrol is very easy!


After you've got your NativeAutomator object, you simply call methods on it and it does the magic.

To tap on a native view (for example, a button in a WebView):

await $.native.tap(Selector(text: 'Sign up for newsletter'));

To enter text into a native view (for example, a form in a WebView):

await $.native.enterText(
  Selector(text: 'Enter your email'),
  text: 'charlie@root.me',

You can also enter text into n-th currently visible text field (counting from 0):

await $.native.enterTextByIndex('charlie_root', index: 0); // enter username
await $.native.enterTextByIndex('ny4ncat', index: 1); // enter password

The above are the simplest, most common actions, but they already make it possible to test scenarios that were impossible to test before, such as WebViews.

To tap, enter text, or perform generally any UI interaction with a iOS app that is not your Flutter app under test, you need to pass its bundle identifier. For example, to tap on the plus button in the iPhone contacts app, use:

await $.native.tap(
  Selector(text: 'Add'),
  appId: 'com.apple.MobileAddressBook',


To open the notification shade:

await $.native.openNotifications();

To tap on the second notification:

await $.native.tapOnNotificationByIndex(1);

You can also tap on notification by its content:

await $.native.tapOnNotificationBySelector(
  Selector(textContains: 'Someone liked your recent post'),


To handle the native permission request dialog:

await $.native.grantPermissionWhenInUse();
await $.native.grantPermissionOnlyThisTime();
await $.native.denyPermission();

If the permission request dialog visible is the location dialog, you can also select the accuracy:

await $.native.selectFineLocation();
await $.native.selectCoarseLocation();

The test will fail if the permission request dialog is not visible. You can check if it is with:

if (await $.native.isPermissionDialogVisible()) {
  await $.native.grantPermissionWhenInUse();

By default, isPermissionDialogVisible() waits for a short amount of time and then returns false if the dialog is not visible. To increase the timeout:

if (await $.native.isPermissionDialogVisible(timeout: Duration(seconds: 5))) {
  await $.native.grantPermissionWhenInUse();

Patrol can handle permissions on iOS only if the device language is set to English (preferably US). That's because there's no way to refer to a specific view in a language-independent way (like resourceId on Android).

If you want to handle permissions on iOS device with non-English locale, do it manually:

await $.native.tap(
  Selector(text: 'Allow'),
  appId: 'com.apple.springboard',

More resources#

To see more integration tests demonstrating Patrol's various features, check out our example app.