Waits
Introduction
CSTesting.DotNet uses Playwright under the hood. Playwright performs actionability checks before actions such as await locator.ClickAsync() (visible, stable, enabled as applicable). If conditions are not met within the timeout (default 30 seconds), the action throws.
For await locator.TypeAsync(text), the element must be visible and editable. Summary:
| Action (ICSTestingLocator) | Visible | Enabled | Editable |
|---|---|---|---|
CheckAsync |
Yes | Yes | — |
ClickAsync |
Yes | Yes | — |
DoubleClickAsync |
Yes | Yes | — |
RightClickAsync |
Yes | Yes | — |
UncheckAsync |
Yes | Yes | — |
HoverAsync |
Yes | — | — |
DragToAsync |
Yes (both) | — | — |
TypeAsync |
Yes | — | Yes |
SelectAsync / SelectByLabelAsync |
Yes | Yes | — |
Explicit waits on ICSTestingBrowser: WaitForLoadAsync, WaitForSelectorAsync(selector, timeoutMs?), WaitForURLAsync(urlOrPattern, timeoutMs?), SleepAsync(ms).
You typically do not need to call WaitForSelectorAsync before every action; Playwright waits for the element to be actionable. After navigation, you can use await browser.WaitForLoadAsync() for page-level readiness.
Assertions
The .NET API has no assertThat. After waiting, assert with NUnit using values from await browser... (see Assertions).
| Check | Typical pattern |
|---|---|
| Visible | Assert.That(await browser.Locator("h1").IsVisibleAsync(), Is.True); |
| Text | Assert.That(await browser.Locator("h1").GetTextContentAsync(), Does.Contain("x")); |
| URL | Assert.That(await browser.GetUrlAsync(), Does.Contain("example")); |
| Title | Assert.That(await browser.EvaluateAsync<string>("document.title"), Does.Contain("x")); |
Visible
An element is considered visible when it has a non-zero size and is not visibility: hidden in computed style.
- Elements with zero size are not considered visible.
- Elements with
display: noneare not considered visible. - Elements with
opacity: 0are still considered visible by this definition.
Enabled
An element is considered enabled when it is not disabled.
An element is disabled when:
- It is a
<button>,<select>,<input>,<textarea>,<option>, or<optgroup>with a[disabled]attribute; or - It is one of those elements inside a
<fieldset>with[disabled]; or - It is inside an element with
[aria-disabled="true"].
CSTesting uses the element's disabled property and DOM structure for this check.
Editable
An element is considered editable when it is enabled and not readonly.
An element is readonly when:
- It is a
<input>or<textarea>with a[readonly]attribute; or - It has
[aria-readonly="true"]with a role that supports it.
<select> elements are treated as editable when enabled (they can be changed). CSTesting checks disabled and readOnly (and tag type) for inputs and textareas.
Example
CSTesting will wait for the Sign Up button to become actionable before clicking, even if it appears only after a delay:
- The page checks that the user name is unique and shows a disabled Sign Up button.
- After the server responds, the button is replaced with an enabled one.
locator.click()waits for the element to exist, be visible, and be enabled, then clicks.
await browser.GotoAsync("https://example.com/signup");
await browser.TypeAsync("name=username", "alice");
// Sign Up may be disabled until username is validated.
await browser.Locator("//button[contains(.,'Sign Up')]").First().ClickAsync();
await browser.WaitForURLAsync("**/welcome", 10_000);
Assert.That(await browser.GetUrlAsync(), Does.Contain("welcome"));
No explicit WaitForSelectorAsync is always required; the click auto-waits for the button to be ready (within Playwright’s timeout).