Skip to main content

Assertions

Taqwright assertions come in two equivalent styles backed by one engine:

await expect(mobile.getByLabel('View All')).toBeVisible(); // Playwright-style matcher
await mobile.getByLabel('View All').assertVisible(); // method on the locator

expect imported from @taqwright/taqwright returns mobile matchers when you pass a Locator, and falls straight through to Playwright's real expect for plain values, so value assertions are unchanged. Pick whichever style reads better; both auto-retry. See the "two styles" note in Writing tests.

Auto-retrying assertions

Assertions on a Locator poll the device until the condition holds or the timeout elapses (default 30 seconds, see Timeouts), so you never write a manual wait:

tests/cart.spec.ts
import { test, expect } from '@taqwright/taqwright';

test('cart', async ({ mobile }) => {
await expect(mobile.getById('VIEW CART')).toBeVisible();
await expect(mobile.getByText('Total')).toContainText('$69.99');
await expect(mobile.getByType('CartItem')).toHaveCount(3);
await expect(mobile.getById('darkMode')).toBeChecked();
});

Each expect(locator) matcher has a paired assert* method that does the same thing:

expect(locator) matcherLocator methodAsserts
toBeVisible() / toBeHidden()assertVisible() / assertHidden()Element is (or is not) displayed
toBeEnabled() / toBeDisabled()assertEnabled() / assertDisabled()Element is interactive
toBeChecked()assertChecked() / assertUnchecked()Toggle / switch state
toBeEditable()assertEditable() / assertReadonly()Input is editable
toBeFocused()assertFocused()Element has keyboard focus
toBeAttached()assertAttached()Element exists in the UI tree
toBeInViewport()assertInViewport()Element intersects the viewport
toBeEmpty()assertEmpty()No children and no text
toHaveText(s | RegExp)assertText(s | RegExp)Exact text or regex match
toContainText(s)assertContainsText(s)Substring match
toHaveValue(s | RegExp)assertValue(s | RegExp)Input value match
toHaveCount(n)assertCount(n)The chain matches exactly n elements
toHaveAttribute(name, s | RegExp)assertAttribute(name, s | RegExp)Attribute matches

Every one accepts a { timeout } option (see Per-assertion timeout).

Non-retrying value assertions

For plain values, strings, numbers, arrays, expect is Playwright's expect unchanged, so the usual matchers (toBe, toEqual, toContain, toHaveLength, …) all work:

tests/totals.spec.ts
import { test, expect } from '@taqwright/taqwright';

test('totals match', async ({ mobile }) => {
const total = await mobile.getById('total').getText();
expect(total).toBe('$69.99');

const items = await mobile.getByType('CartItem').all();
expect(items).toHaveLength(3);
});

These run once and do not retry. When you are asserting UI state that settles asynchronously, prefer a locator matcher so the assertion auto-waits.

Negating with .not

State matchers support .not:

await expect(mobile.getById('spinner')).not.toBeVisible();
await expect(mobile.getById('darkMode')).not.toBeChecked();
await expect(mobile.getById('save')).not.toBeEnabled();

.not is available on toBeVisible / toBeHidden, toBeEnabled / toBeDisabled, toBeChecked, and toBeEditable. For the value-style matchers (toHaveText, toContainText, toHaveValue, toHaveCount, toHaveAttribute) and toBeFocused / toBeAttached / toBeInViewport / toBeEmpty, .not throws a clear error. Use the positive form, or the paired assert* method, instead.

Soft assertions

A soft assertion records a failure but lets the test keep running, so you can collect several checks before the test ends:

tests/status.spec.ts
import { test, expect } from '@taqwright/taqwright';

test('summary screen', async ({ mobile }) => {
await expect.soft(mobile.getById('status')).toHaveText('Success');
await expect.soft(mobile.getById('eta')).toHaveText('1 day');

// Inspect accumulated soft failures if you need to branch.
expect(test.info().errors).toHaveLength(0);
});

Custom failure message

Pass a message as the second argument to expect to make failures self-explanatory in the report:

await expect(mobile.getById('VIEW CART'), 'cart should be visible after add').toBeVisible();

Per-assertion timeout

Override the default expect timeout for a single assertion with { timeout } (it works on both the matcher and the assert* form):

await expect(mobile.getByText('Order confirmed')).toBeVisible({ timeout: 20_000 });
await mobile.getById('Status').assertText('Paid', { timeout: 5_000 });

See Timeouts for the default and how to change it globally.

Polling a condition

When you need to wait on something that is not a single locator matcher, use Playwright's expect.poll, which re-runs your function until the value matches:

await expect
.poll(() => mobile.getById('VIEW CART').isVisible(), { timeout: 10_000 })
.toBe(true);

expect(async () => { ... }).toPass() similarly retries a whole block of assertions until they pass.

Web-only matchers are not available

Matchers that only make sense on the web, toHaveScreenshot, toHaveCSS, toHaveClass, toHaveId, toHaveRole, toMatchAriaSnapshot, toHaveTitle, toHaveURL, toBeOK, and similar, throw a clear error on a mobile locator rather than misfire. Custom locator matchers via expect.extend are not supported (the mobile expect is a standalone wrapper, not an extension); write a small async helper function instead. A few web-only options such as ignoreCase are also rejected.