Skip to main content
WebAutomator provides web-specific methods for automating browser interactions in Patrol tests. Access it through $.platform.web in your tests.

Accessing WebAutomator

patrolTest('web test', ($) async {
  // Access via platform.web
  await $.platform.web.tap(WebSelector(text: 'Submit'));
  
  // Platform-specific action helper
  await $.platform.action(
    web: $.platform.web.configure,
  );
});

Initialization

initialize()
Future<void>
Initializes the web automator.Called automatically before tests begin.
configure()
Future<void>
Configures the web automator with settings from WebAutomatorConfig.

Element Interaction

Tapping

tap(WebSelector selector, {...})
Future<void>
Clicks on a web element.Parameters:
  • selector - WebSelector to locate the element
  • iframeSelector - Optional selector for iframe context
// Click a button
await $.platform.web.tap(
  WebSelector(text: 'Submit'),
);

// Click element in iframe
await $.platform.web.tap(
  WebSelector(role: 'button'),
  iframeSelector: WebSelector(cssOrXpath: '#payment-iframe'),
);

Text Entry

enterText(WebSelector selector, {...})
Future<void>
Enters text into a web form field.Parameters:
  • selector - The input field to target
  • text - Text to enter (required)
  • iframeSelector - Optional iframe selector
await $.platform.web.enterText(
  WebSelector(label: 'Email'),
  text: '[email protected]',
);

// In iframe
await $.platform.web.enterText(
  WebSelector(placeholder: 'Card number'),
  text: '4242 4242 4242 4242',
  iframeSelector: WebSelector(cssOrXpath: '#stripe-iframe'),
);

Scrolling

scrollTo(WebSelector selector, {...})
Future<void>
Scrolls to bring an element into view.
await $.platform.web.scrollTo(
  WebSelector(text: 'Footer Content'),
);

Browser Permissions

grantPermissions({required List<String> permissions})
Future<void>
Grants browser permissions.Common permissions:
  • 'geolocation'
  • 'notifications'
  • 'camera'
  • 'microphone'
  • 'clipboard-read'
  • 'clipboard-write'
await $.platform.web.grantPermissions(
  permissions: ['geolocation', 'notifications'],
);
clearPermissions()
Future<void>
Clears all granted browser permissions.
await $.platform.web.clearPermissions();
Adds a browser cookie.Parameters:
  • name - Cookie name (required)
  • value - Cookie value (required)
  • url - URL to set cookie for
  • domain - Cookie domain
  • path - Cookie path
  • expires - Expiration timestamp
  • httpOnly - HTTP-only flag
  • secure - Secure flag
  • sameSite - SameSite policy (‘Strict’, ‘Lax’, ‘None’)
await $.platform.web.addCookie(
  name: 'session_id',
  value: 'abc123',
  domain: '.example.com',
  secure: true,
  sameSite: 'Lax',
);
getCookies()
Future<List<LinkedHashMap<Object?, Object?>>>
Retrieves all browser cookies.
final cookies = await $.platform.web.getCookies();
for (final cookie in cookies) {
  print('${cookie['name']}: ${cookie['value']}');
}
clearCookies()
Future<void>
Clears all browser cookies.
await $.platform.web.clearCookies();

File Upload

uploadFile({required List<UploadFileData> files})
Future<void>
Uploads files through file input elements.
await $.platform.web.uploadFile(
  files: [
    UploadFileData(
      path: '/path/to/document.pdf',
      mimeType: 'application/pdf',
    ),
    UploadFileData(
      path: '/path/to/image.png',
      mimeType: 'image/png',
    ),
  ],
);

Dialog Handling

acceptNextDialog()
Future<String>
Accepts the next JavaScript dialog (alert, confirm, prompt) that appears.Returns the dialog message.
// Start listening before triggering dialog
final dialogFuture = $.platform.web.acceptNextDialog();

// Trigger dialog
await $.platform.web.tap(WebSelector(text: 'Show Alert'));

// Get dialog message
final message = await dialogFuture;
print('Dialog said: $message');
dismissNextDialog()
Future<String>
Dismisses the next JavaScript dialog.
final dialogFuture = $.platform.web.dismissNextDialog();
await $.platform.web.tap(WebSelector(text: 'Show Confirm'));
await dialogFuture;

Keyboard Input

pressKey({required String key})
Future<void>
Presses a single keyboard key.Common keys: 'Enter', 'Escape', 'Tab', 'Backspace', 'ArrowUp', etc.
await $.platform.web.pressKey(key: 'Enter');
await $.platform.web.pressKey(key: 'Escape');
pressKeyCombo({required List<String> keys})
Future<void>
Presses a keyboard shortcut.
// Ctrl+C
await $.platform.web.pressKeyCombo(keys: ['Control', 'c']);

// Cmd+V (on Mac)
await $.platform.web.pressKeyCombo(keys: ['Meta', 'v']);

// Ctrl+Shift+K
await $.platform.web.pressKeyCombo(keys: ['Control', 'Shift', 'k']);

Browser Navigation

goBack()
Future<void>
Navigates back in browser history.
await $.platform.web.goBack();
goForward()
Future<void>
Navigates forward in browser history.
await $.platform.web.goForward();

Clipboard

getClipboard()
Future<String>
Retrieves text from the clipboard.Requires clipboard-read permission.
await $.platform.web.grantPermissions(
  permissions: ['clipboard-read'],
);

final clipboardText = await $.platform.web.getClipboard();
expect(clipboardText, 'Expected content');
setClipboard({required String text})
Future<void>
Sets clipboard text.Requires clipboard-write permission.
await $.platform.web.grantPermissions(
  permissions: ['clipboard-write'],
);

await $.platform.web.setClipboard(text: 'Hello, World!');

Window Management

resizeWindow({required Size size})
Future<void>
Resizes the browser window.
// Mobile viewport
await $.platform.web.resizeWindow(
  size: Size(375, 667), // iPhone SE
);

// Desktop viewport
await $.platform.web.resizeWindow(
  size: Size(1920, 1080),
);

Dark Mode

enableDarkMode()
Future<void>
Enables dark mode in the browser.
await $.platform.web.enableDarkMode();
disableDarkMode()
Future<void>
Disables dark mode (switches to light mode).
await $.platform.web.disableDarkMode();

File Downloads

verifyFileDownloads()
Future<List<String>>
Returns a list of all files downloaded during the current test.
// Trigger download
await $.platform.web.tap(WebSelector(text: 'Download Report'));

// Wait for download
await Future.delayed(Duration(seconds: 2));

// Verify
final downloads = await $.platform.web.verifyFileDownloads();
expect(downloads, contains('report.pdf'));

WebSelector

The selector class for locating web elements:
WebSelector({
  String? role,
  String? label,
  String? placeholder,
  String? text,
  String? altText,
  String? title,
  String? testId,
  String? cssOrXpath,
})

Selector Examples

// By text content
WebSelector(text: 'Submit')

// By ARIA label
WebSelector(label: 'Email address')

// By placeholder
WebSelector(placeholder: 'Enter your email')

// By role
WebSelector(role: 'button')

// By test ID (data-testid attribute)
WebSelector(testId: 'login-button')

// By CSS selector
WebSelector(cssOrXpath: '.submit-button')

// By XPath
WebSelector(cssOrXpath: '//button[@class="primary"]')

// Combined
WebSelector(
  role: 'textbox',
  label: 'Password',
)

Usage Examples

Complete Login Flow

patrolTest('web login', ($) async {
  await $.pumpWidgetAndSettle(MyWebApp());
  
  // Enter credentials
  await $.platform.web.enterText(
    WebSelector(label: 'Email'),
    text: '[email protected]',
  );
  
  await $.platform.web.enterText(
    WebSelector(label: 'Password'),
    text: 'secure123',
  );
  
  // Submit
  await $.platform.web.tap(
    WebSelector(role: 'button', text: 'Sign In'),
  );
  
  // Verify success (back in Flutter)
  await $(Text('Dashboard')).waitUntilVisible();
});

Handle Iframe Payment Form

patrolTest('payment in iframe', ($) async {
  await $.pumpWidgetAndSettle(MyApp());
  
  // Interact with main page
  await $('Checkout').tap();
  
  // Enter card details in Stripe iframe
  final stripeIframe = WebSelector(
    cssOrXpath: 'iframe[name="stripe"]',
  );
  
  await $.platform.web.enterText(
    WebSelector(placeholder: 'Card number'),
    text: '4242424242424242',
    iframeSelector: stripeIframe,
  );
  
  await $.platform.web.enterText(
    WebSelector(placeholder: 'MM / YY'),
    text: '12/25',
    iframeSelector: stripeIframe,
  );
  
  await $.platform.web.tap(
    WebSelector(text: 'Pay'),
  );
});

Test with Permissions

patrolTest('geolocation feature', ($) async {
  // Grant permission
  await $.platform.web.grantPermissions(
    permissions: ['geolocation'],
  );
  
  await $.pumpWidgetAndSettle(MyApp());
  
  await $('Use My Location').tap();
  await $(Text('Location: 37.7749, -122.4194')).waitUntilVisible();
});

Keyboard Shortcuts

patrolTest('keyboard shortcuts', ($) async {
  await $.pumpWidgetAndSettle(MyApp());
  
  // Open search with Ctrl+K
  await $.platform.web.pressKeyCombo(keys: ['Control', 'k']);
  await $(TextField).waitUntilVisible();
  
  // Close with Escape
  await $.platform.web.pressKey(key: 'Escape');
});

Responsive Testing

patrolTest('responsive design', ($) async {
  // Test mobile layout
  await $.platform.web.resizeWindow(size: Size(375, 667));
  await $.pumpWidgetAndSettle(MyApp());
  expect($(#mobileMenu).visible, true);
  
  // Test desktop layout
  await $.platform.web.resizeWindow(size: Size(1920, 1080));
  await $.pumpAndSettle();
  expect($(#desktopMenu).visible, true);
});

See Also

Build docs developers (and LLMs) love