Skip to content

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();

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 assertions

expect.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

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();

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)).

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 timeout
await expect(device.getByText("Welcome", { exact: true })).toBeVisible({ timeout: 10000 });
// One assertion for both states: `visible: false` asserts the element is hidden
await 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.

Assert that the element is enabled (interactive).

await expect(device.getByRole("button", { name: "Submit" })).toBeEnabled();
await expect(device.getByRole("button", { name: "Submit" })).not.toBeEnabled();

Assert that the element is disabled (not interactive). More expressive than .not.toBeEnabled().

await expect(device.getByRole("button", { name: "Submit" })).toBeDisabled();

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();

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();

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() and getHintText(), 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, so toBeEmpty() after clear() may incorrectly report the field as non-empty (it sees the placeholder text). Bump minSdk to 26 if your tests rely on this behavior. iOS is unaffected.

await expect(device.getByRole("textfield", { name: "Search" })).toBeEmpty();

Assert that the element currently has accessibility/input focus.

await device.getByRole("textfield", { name: "Email" }).tap();
await expect(device.getByRole("textfield", { name: "Email" })).toBeFocused();

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

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");

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();

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");