Assertions
The expect() function creates assertions for an ElementHandle or a plain value. Locator assertions auto-wait by polling until the condition is met or the timeout expires.
expect(elementHandle: ElementHandle): TapsmithAssertions
Section titled “expect(elementHandle: ElementHandle): TapsmithAssertions”Create an assertion object for the given element handle.
await expect(device.getByText("Hello", { exact: true })).toBeVisible();expect(value: unknown): GenericAssertions
Section titled “expect(value: unknown): GenericAssertions”Create a generic assertion for a plain value (non-ElementHandle). These are synchronous and do not auto-wait.
expect(5).toBe(5);expect("hello").toContain("ell");expect([1, 2, 3]).toHaveLength(3);expect.soft(elementHandle: ElementHandle): TapsmithAssertions
Section titled “expect.soft(elementHandle: ElementHandle): TapsmithAssertions”Create a soft assertion that records failures without stopping the test. Failures are collected and can be flushed at the end.
expect.soft(device.getByText("Header", { exact: true })).toBeVisible();expect.soft(device.getByText("Footer", { exact: true })).toBeVisible();// Test continues even if assertions fail
const errors = flushSoftErrors();// errors contains any failures from soft assertionsexpect.poll(fn: () => unknown | Promise<unknown>, options?: PollOptions): GenericAssertions
Section titled “expect.poll(fn: () => unknown | Promise<unknown>, options?: PollOptions): GenericAssertions”Poll an async function until the assertion passes or the timeout expires. Useful for waiting on values that change over time.
await expect.poll(async () => { const el = await device.getByRole("listitem").count(); return el;}).toBe(5);
await expect.poll(() => fetchStatus(), { timeout: 10000 }).toBe("ready");PollOptions:
| Option | Type | Default | Description |
|---|---|---|---|
timeout |
number |
5000 | How long to poll before failing |
intervals |
number[] |
[250] |
Polling intervals in milliseconds |
flushSoftErrors(): Error[]
Section titled “flushSoftErrors(): Error[]”Retrieve and clear all soft assertion failures collected by expect.soft().
const errors = flushSoftErrors();if (errors.length > 0) { console.log(`${errors.length} soft assertions failed`);}Negate the following assertion.
await expect(device.getByText("Loading...", { exact: true })).not.toBeVisible();Locator Assertions
Section titled “Locator Assertions”All locator assertions accept an optional options object:
| Option | Type | Default | Description |
|---|---|---|---|
timeout |
number |
Element’s timeout (default 30s) | How long to wait for the condition |
visible |
boolean |
true |
(toBeVisible only) false asserts the element is hidden, exactly like toBeHidden() |
ratio |
number |
0 |
(toBeInViewport only) Minimum fraction of element visible in viewport |
An option the assertion does not support (a misspelling, or a Playwright option Tapsmith does not have yet, such as toBeEnabled({ enabled: false }) or toHaveText(text, { ignoreCase: true })) throws a TypeError at once, naming the supported options, rather than being ignored — so the assertion never silently checks something other than what you wrote. So does an options argument that is not an object (toBeVisible(5000)).
.toBeVisible(options?): Promise<void>
Section titled “.toBeVisible(options?): Promise<void>”Assert that the element is visible on screen. With .not, waits for the element to disappear.
await expect(device.getByText("Welcome", { exact: true })).toBeVisible();await expect(device.getByText("Spinner", { exact: true })).not.toBeVisible();
// Custom timeoutawait expect(device.getByText("Welcome", { exact: true })).toBeVisible({ timeout: 10000 });
// One assertion for both states: `visible: false` asserts the element is hiddenawait expect(device.getByText("Sign out", { exact: true })).toBeVisible({ visible: isLoggedIn });With { visible: false } the assertion is toBeHidden() in every respect, as in Playwright: it passes when the element is absent or every match is hidden, waits up to the timeout for that, and .not.toBeVisible({ visible: false }) behaves like .not.toBeHidden(). visible must be a boolean.
.toBeEnabled(options?): Promise<void>
Section titled “.toBeEnabled(options?): Promise<void>”Assert that the element is enabled (interactive).
await expect(device.getByRole("button", { name: "Submit" })).toBeEnabled();await expect(device.getByRole("button", { name: "Submit" })).not.toBeEnabled();.toBeDisabled(options?): Promise<void>
Section titled “.toBeDisabled(options?): Promise<void>”Assert that the element is disabled (not interactive). More expressive than .not.toBeEnabled().
await expect(device.getByRole("button", { name: "Submit" })).toBeDisabled();.toBeChecked(options?): Promise<void>
Section titled “.toBeChecked(options?): Promise<void>”Assert that a checkbox, switch, or radio button is in the checked state.
await expect(device.getByRole("switch", { name: "Dark Mode" })).toBeChecked();await expect(device.getByRole("checkbox")).not.toBeChecked();.toBeHidden(options?): Promise<void>
Section titled “.toBeHidden(options?): Promise<void>”Assert that the element is not visible on screen (either not in the hierarchy or has visibility=false). More expressive than .not.toBeVisible().
await expect(device.getByText("Loading...", { exact: true })).toBeHidden();.toBeEmpty(options?): Promise<void>
Section titled “.toBeEmpty(options?): Promise<void>”Assert that the element has no text content or is an empty input field. The agents normalize text-input fields so a placeholder/hint is not reported as text — toBeEmpty() after clear() passes even when the placeholder is still drawn.
Android API < 26 limitation. The precise placeholder-vs-value distinction uses
AccessibilityNodeInfo.isShowingHintText()andgetHintText(), both of which are only available from API 26 (Android 8.0). On API 21–25 we cannot tell whether a textfield is displaying its placeholder or a real typed value, sotoBeEmpty()afterclear()may incorrectly report the field as non-empty (it sees the placeholder text). BumpminSdkto 26 if your tests rely on this behavior. iOS is unaffected.
await expect(device.getByRole("textfield", { name: "Search" })).toBeEmpty();.toBeFocused(options?): Promise<void>
Section titled “.toBeFocused(options?): Promise<void>”Assert that the element currently has accessibility/input focus.
await device.getByRole("textfield", { name: "Email" }).tap();await expect(device.getByRole("textfield", { name: "Email" })).toBeFocused();.toBeEditable(options?): Promise<void>
Section titled “.toBeEditable(options?): Promise<void>”Assert that the element is an editable input field (a text field that is enabled).
await expect(device.getByRole("textfield", { name: "Name" })).toBeEditable();await expect(device.getByRole("textfield", { name: "ID" })).not.toBeEditable(); // read-only.toBeInViewport(options?): Promise<void>
Section titled “.toBeInViewport(options?): Promise<void>”Assert that the element is currently within the visible screen area. Different from toBeVisible() which checks the visibility property – this checks if the element’s bounds intersect with the screen bounds.
await expect(device.getByText("Footer", { exact: true })).toBeInViewport();await expect(device.getByText("Footer", { exact: true })).toBeInViewport({ ratio: 0.5 }); // at least 50% visible.toHaveText(expected: string | RegExp | Array<string | RegExp>, options?): Promise<void>
Section titled “.toHaveText(expected: string | RegExp | Array<string | RegExp>, options?): Promise<void>”Assert that the element’s text equals the expected string exactly, or matches a regular expression.
With an array, the locator may match several elements (no strict-mode violation): it must match exactly as many elements as there are items, and each element’s text must match its item, in order. toHaveText([]) asserts that nothing matches.
await expect(device.locator({ id: "counter" })).toHaveText("42");await expect(device.getByTestId("status")).toHaveText(/^\d+ items$/);await expect(device.getByRole("listitem")).toHaveText(["Apples", "Bananas", /^Cherries/]);.toContainText(expected: string | RegExp | Array<string | RegExp>, options?): Promise<void>
Section titled “.toContainText(expected: string | RegExp | Array<string | RegExp>, options?): Promise<void>”Assert that the element’s text contains the given substring or matches a regex. Unlike toHaveText() which requires an exact match, this allows partial matching.
With an array, the locator may match several elements: each item must match one of them, in order, and other elements may come between (["Apples", "Cherries"] passes for Apples, Bananas, Cherries).
A RegExp is tested afresh on every poll, so a g flag can’t make it skip a match. Any expected value other than a string, a RegExp or an array of them throws a TypeError at once. The string forms compare the text as it is (no whitespace normalization).
When the matched element has no own text (e.g. a wrapping View around <Text> children, common in React Native), the agents aggregate descendant text/labels so the assertion sees the visible string.
await expect(device.getByTestId("status")).toContainText("Success");await expect(device.getByTestId("status")).toContainText(/\d+ items/);.toHaveCount(count: number, options?): Promise<void>
Section titled “.toHaveCount(count: number, options?): Promise<void>”Assert that the locator resolves to exactly N elements. Every modifier on the locator applies — filter(), and()/or(), scoping and first()/nth()/last() — so it counts the same set count() returns, and a positional locator has a count of 1 or 0.
await expect(device.getByRole("listitem")).toHaveCount(5);await expect(device.getByText("Error", { exact: true })).toHaveCount(0);.toHaveAttribute(name: string, value: unknown, options?): Promise<void>
Section titled “.toHaveAttribute(name: string, value: unknown, options?): Promise<void>”Assert that the element has a specific property/attribute value. For Android, this maps to view properties like className, resourceId, contentDescription, enabled, clickable, focusable, scrollable, selected, etc.
await expect(device.getByText("Item", { exact: true })).toHaveAttribute("selected", true);await expect(device.getByText("Item", { exact: true })).toHaveAttribute("className", "android.widget.TextView");.toHaveAccessibleName(name: string | RegExp, options?): Promise<void>
Section titled “.toHaveAccessibleName(name: string | RegExp, options?): Promise<void>”Assert that the element has the given accessible name. On Android, this is the contentDescription if set, otherwise the text property.
await expect(device.getByRole("button")).toHaveAccessibleName("Submit form");await expect(device.getByRole("image")).toHaveAccessibleName(/Profile/);.toHaveAccessibleDescription(description: string | RegExp, options?): Promise<void>
Section titled “.toHaveAccessibleDescription(description: string | RegExp, options?): Promise<void>”Assert that the element has the given accessible description. On Android, this maps to the hint property.
await expect(device.getByRole("image")).toHaveAccessibleDescription("Profile photo");.toHaveRole(role: string, options?): Promise<void>
Section titled “.toHaveRole(role: string, options?): Promise<void>”Assert that the element has a specific accessibility role.
The role is derived from a framework-set role description first (React Native’s accessibilityRole, the isHeading flag, the UIAccessibilityTraitHeader trait, etc.) and falls back to the platform’s class/element-type mapping. "header" and "heading" are accepted as aliases on both platforms.
await expect(device.getByText("Submit", { exact: true })).toHaveRole("button");await expect(device.getByTestId("toggle")).toHaveRole("switch");await expect(device.getByText("Section title", { exact: true })).toHaveRole("heading");.toHaveValue(value: string, options?): Promise<void>
Section titled “.toHaveValue(value: string, options?): Promise<void>”Assert that an input field contains a specific value.
await device.getByRole("textfield", { name: "Email" }).type("test@example.com");await expect(device.getByRole("textfield", { name: "Email" })).toHaveValue("test@example.com");.toExist(options?): Promise<void>
Section titled “.toExist(options?): Promise<void>”Assert that the element exists in the UI hierarchy (regardless of visibility).
await expect(device.getByTestId("hidden-input")).toExist();await expect(device.getByText("Deleted item", { exact: true })).not.toExist();Generic Value Assertions
Section titled “Generic Value Assertions”When expect() receives a non-ElementHandle value, it returns GenericAssertions with synchronous Jest-style matchers. All support .not for negation.
| Assertion | Description |
|---|---|
.toBe(expected) |
Strict equality using Object.is |
.toEqual(expected) |
Deep equality |
.toStrictEqual(expected) |
Deep equality with type checking |
.toBeTruthy() |
Value is truthy |
.toBeFalsy() |
Value is falsy |
.toBeDefined() |
Value is not undefined |
.toBeUndefined() |
Value is undefined |
.toBeNull() |
Value is null |
.toBeNaN() |
Value is NaN |
.toContain(expected) |
String/array contains item |
.toContainEqual(expected) |
Array contains item matching deep equality |
.toHaveLength(expected) |
Value has .length equal to expected |
.toHaveProperty(path, value?) |
Value has property at path, optionally with value |
.toMatch(expected) |
String matches regex or string pattern |
.toMatchObject(expected) |
Object matches subset of properties |
.toBeGreaterThan(expected) |
Number is greater than expected |
.toBeGreaterThanOrEqual(expected) |
Number is greater than or equal to expected |
.toBeLessThan(expected) |
Number is less than expected |
.toBeLessThanOrEqual(expected) |
Number is less than or equal to expected |
.toBeCloseTo(expected, numDigits?) |
Number is close to expected within precision |
.toBeInstanceOf(expected) |
Value is instance of class |
.toThrow(expected?) |
Function throws, optionally matching message |
expect(result).toBe(42);expect(items).toHaveLength(3);expect(name).toMatch(/^[A-Z]/);expect(config).toMatchObject({ debug: true });expect(() => parse("bad")).toThrow("Invalid");
