Table of Contents

Actions

Actions on an element act the way a user would, through WebDriver BiDi's input actions, so the page sees the same events it would from a person. Each action waits until its locator finds exactly one element and that element is ready.

Readiness

Action Waits until the element is
ClickAsync, DblClickAsync, TapAsync, CheckAsync, DragToAsync Visible, stable, enabled, and not covered by another element
HoverAsync Visible, stable, enabled, and not covered
FillAsync, ClearAsync Visible, stable, enabled, editable, and not covered
SelectOptionAsync Visible and enabled, with every option present and enabled
ScrollIntoViewIfNeededAsync Visible and stable
PressAsync, PressSequentiallyAsync, FocusAsync, BlurAsync, SetInputFilesAsync, DispatchEventAsync Found

"Stable" means it has stopped moving. "Not covered" means the point the pointer would use is on the element, not on something drawn over it; the element is scrolled into view first if needed. An element that is removed while an action waits is found again, and an action that runs out of time throws WebDriverBiDiTimeoutException saying what it last saw.

Clicking and Pointing

await page.GetByRole("button", "Save").ClickAsync();
await page.GetByText("README.md").DblClickAsync();
await page.GetByRole("link", "Docs").ClickAsync(new ClickOptions() { Modifiers = KeyModifiers.Control });
await page.GetByRole("row").First().ClickAsync(new ClickOptions() { Button = PointerButton.Right });
await page.GetByRole("menuitem", "File").HoverAsync();
await page.GetByRole("slider").ClickAsync(new ClickOptions() { Offset = new PointerOffset(40, 0) });
await page.GetByRole("button", "Like").TapAsync();
await page.GetByText("Card 1").DragToAsync(page.GetByRole("region", "Done"));

ClickOptions sets the button, the number of clicks, the modifier keys held, and the Offset from the center of the element's visible part; by default the pointer goes to a point on the element that nothing covers. TapAsync uses a touch pointer. DragToAsync drags with the mouse onto another element in the same frame, and DragOptions.TargetOffset chooses where it lands.

Firefox: a native HTML5 drag from WebDriver input actions dispatches only dragstart (bug 1515879), so DragToAsync onto a draggable element's drop target does not drop in Firefox.

Typing

ElementLocator search = page.GetByRole("searchbox");
await search.FillAsync("webdriver bidi");
await search.PressAsync(Keys.Enter);

// Types each character as a key press, for pages that react to each key, such as an autocomplete.
await search.ClearAsync();
await search.PressSequentiallyAsync("drama", new PressSequentiallyOptions() { Delay = TimeSpan.FromMilliseconds(50) });

await search.PressAsync("a", new KeyActionOptions() { Modifiers = KeyModifiers.Control });
  • FillAsync replaces an input's, a text area's, or an editable element's text, selecting it and typing the new text over it. An input whose value is not typed, such as a date, a color, or a checkbox, cannot be filled and throws InvalidOperationException.
  • PressSequentiallyAsync types text one key press at a time, without clearing what is there, optionally with a delay between keys.
  • PressAsync presses one key: a character, or a Keys constant (in WebDriverBiDi.Input) such as Keys.Enter, holding any KeyModifiers.

Text is typed one user-perceived character at a time, so emoji and accented characters arrive whole.

Form Controls

await page.GetByLabel("I agree to the terms").CheckAsync();
await page.GetByLabel("Send me news").SetCheckedAsync(false);
await page.GetByLabel("Express delivery").CheckAsync();

IReadOnlyList<string> selected = await page.GetByLabel("Country").SelectOptionAsync([SelectOption.ByLabel("Norway")]);
await page.GetByLabel("Toppings").SelectOptionAsync([SelectOption.ByValue("cheese"), SelectOption.ByIndex(3)]);

await page.GetByLabel("Attachment").SetInputFilesAsync(["/home/ada/report.pdf"]);
  • CheckAsync, UncheckAsync, and SetCheckedAsync click the control only if it is not already in the state asked for, then confirm that the click changed it. A radio button cannot be unchecked by clicking it, so unchecking one throws.
  • SelectOptionAsync selects options of a <select> by value, label, or index, deselecting the rest, and fires the input and change events a user's choice would. It returns the values selected.
  • SetInputFilesAsync sets a file input's files. The paths are on the machine the browser runs on.

Acting Without Waiting

Every action takes Force, which skips the readiness checks. The element must still be found, exactly once:

// Clicks even though another element covers it, such as a translucent overlay the page leaves in place.
await page.GetByRole("button", "Close").ClickAsync(new ClickOptions() { Force = true });

Use it only when a check is wrong for a particular page; a forced click on a covered element can land on whatever covers it.

Other Actions

ElementLocator field = page.GetByLabel("Name");
await field.FocusAsync();
await field.BlurAsync();
await page.GetByText("Terms").ScrollIntoViewIfNeededAsync();

// Dispatches a synthetic event, which the page sees but which no user action caused.
bool notCanceled = await page.GetByRole("button", "Save").DispatchEventAsync(
    "click",
    new Dictionary<string, LocalValue>() { ["detail"] = LocalValue.Number(1) });

DispatchEventAsync creates the event with the interface a user's action would use for its type, such as MouseEvent for click. The event bubbles, is cancelable, and crosses shadow boundaries unless its init properties say otherwise. It returns false if a listener canceled it.

The Page's Mouse and Keyboard

For input not aimed at one element, such as drawing on a canvas or holding a key across several actions, use the page's Mouse and Keyboard. Mouse coordinates are CSS pixels of the page's viewport; for an element's position, see BoundingBoxAsync and BoundingBox.ToTopLevelAsync:

// Draws a line on a canvas, in CSS pixels of the page's viewport.
await page.Mouse.MoveAsync(100, 100);
await page.Mouse.DownAsync();
await page.Mouse.MoveAsync(300, 200, steps: 10);
await page.Mouse.UpAsync();

await page.Keyboard.DownAsync(Keys.Shift);
await page.Keyboard.PressAsync(Keys.ArrowRight);
await page.Keyboard.UpAsync(Keys.Shift);
await page.Keyboard.TypeAsync("Hello");

A page keeps one mouse and one keyboard for its lifetime, so a key or button held down stays down until it is released.