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:
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) matcher | Locator method | Asserts |
|---|---|---|
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:
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:
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.
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.