Practice Widgets Assertions (expect)
7 flavours
Widget practice · Assertions

Every expect() flavour on TTA targets

Seven categories of Playwright assertions, every snippet runs against our own hosted pages — no third-party URLs. Value · locator · soft · not · screenshot · URL/title · visible / enabled / disabled.

① Value assertions

Pure-JS comparisons. No browser needed — these are the same matchers you'd see in Jest. Synchronous; no await on the outer expect.

Target: any local value
tests/value.spec.ts
import { test, expect } from '@playwright/test';

test('value assertions', async () => {
  expect(1 + 1).toBe(2);
  expect('playwright').toContain('play');
  expect([1, 2, 3]).toEqual([1, 2, 3]);
  expect(true).toBeTruthy();
  expect(false).toBeFalsy();
  expect(null).toBeNull();
  expect(50).toBeGreaterThan(10);
  expect({ role: 'admin' }).toEqual({ role: 'admin' });
  expect({ age: 20, role: 'admin' }).toEqual({ role: 'admin', age: 20 });
});

② Locator-based assertions

Auto-retrying. Default timeout 5s; override per-call. Targets a live element via page.locator(...), getByRole, etc.

Target: /playwright/multiple_element_filter.html
tests/locator.spec.ts
import { test, expect } from '@playwright/test';

test('locator-based assertions', async ({ page }) => {
  await page.goto('https://app.thetestingacademy.com/playwright/multiple_element_filter.html');

  const heading = page.getByText('Multiple element filter', { exact: false });
  await expect(heading).toBeVisible();
  await expect(heading).toContainText('filter', { timeout: 10000 });

  const email = page.getByRole('textbox', { name: 'Email Address' });
  await expect(email).toHaveAttribute('id', 'email');
  await expect(email).toHaveAttribute('type', 'email');

  const footerLinks = page.locator('footer a');
  await expect(footerLinks).toHaveCount(16);
});

③ Soft assertions

Don't abort the test on failure — collect all errors and report at the end. Useful for asserting many values without re-running on each failure.

Target: /playwright/tables/practice.html
tests/soft.spec.ts
import { test, expect } from '@playwright/test';

test('soft assertions', async ({ page }) => {
  await page.goto('https://app.thetestingacademy.com/playwright/tables/practice.html');

  const firstName = page.getByLabel('First name');

  // Soft: each line records its own failure; test continues either way.
  await expect.soft(firstName).toHaveAttribute('id', 'first-name');
  await expect.soft(firstName).toBeVisible();
  await expect.soft(firstName).toHaveValue('');

  // Final hard assertion still runs after the soft block.
  await expect(firstName).toBeEnabled();
});

④ Negation — .not

Flip any matcher. Useful for "this error toast must NOT appear" or "URL must NOT contain /error".

Target: /playwright/webtable.html
tests/not.spec.ts
import { test, expect } from '@playwright/test';

test('not assertions', async ({ page }) => {
  await page.goto('https://app.thetestingacademy.com/playwright/webtable.html');

  await expect(page.locator('#error')).not.toBeVisible();

  const title = await page.title();
  expect(title).not.toContain('error');
});

⑤ Screenshot assertions (visual diff)

Pixel diff against a baseline. First run creates the baseline; later runs fail if the rendered image differs beyond maxDiffPixels / threshold.

Target: /playwright/widgets/calendar.html
tests/screenshot.spec.ts
import { test, expect } from '@playwright/test';

test('screenshot assertions', async ({ page }) => {
  await page.goto('https://app.thetestingacademy.com/playwright/widgets/calendar.html');

  const header = page.getByText('two-month range', { exact: false });
  await expect(header).toHaveScreenshot('header.png');

  // Full-page snapshot with tolerance for tiny anti-alias drift
  await expect(page).toHaveScreenshot('calendar-fullpage.png', { maxDiffPixels: 80 });
});

⑥ URL & title assertions

Auto-retrying matchers on the Page itself.

Target: /playwright/index.html
tests/url-title.spec.ts
import { test, expect } from '@playwright/test';

test('url and title assertions', async ({ page }) => {
  await page.goto('https://app.thetestingacademy.com/playwright/');

  await expect(page).toHaveTitle(/Playwright Practice/);
  await expect(page).toHaveURL(/\/playwright\/?$/);

  const appUrl = page.url();
  expect(appUrl).toContain('/playwright');
});

⑦ Visible · enabled · disabled · checked

All four are auto-retrying. Default 5s timeout; override when the UI is slow to settle.

Target: /playwright/tables/practice.html
tests/state.spec.ts
import { test, expect } from '@playwright/test';

test('visible · enabled · disabled · checked', async ({ page }) => {
  await page.goto('https://app.thetestingacademy.com/playwright/tables/practice.html');

  const agreeCheckbox = page.getByRole('checkbox', { name: /UFT/ });
  const submitBtn = page.getByTestId('profile-submit');

  await expect(agreeCheckbox).not.toBeChecked();
  await expect(submitBtn).toBeVisible();
  await expect(submitBtn).toBeEnabled();

  await agreeCheckbox.check();
  await expect(agreeCheckbox).toBeChecked();
});