Comprehensive Playwright test matchers for strings, numbers, dates, arrays, objects, and locators. Simplify your E2E tests with intuitive assertions.
- π― 50+ Custom Matchers - Extensive validation for all data types
- π€ String Validation - Email, URL, UUID, alphanumeric, and more
- π’ Number Arrays - Sorting, statistics, ranges, and patterns
- π Date Operations - Comparisons, ranges, quarters, and business logic
- π¨ Locator Assertions - DOM element validation and text formatting
- π¦ Object Arrays - Sorting, uniqueness, and property validation
- π€ Fuzzy Matching - AI-generated text validation with configurable similarity threshold (separate package)
- πͺ Type-Safe - Full TypeScript support
- β‘ Lightweight - Only Playwright required. @cerios/playwright-expectly-fuzzy uses
fuzzballas an optional dependency
npm install @cerios/playwright-expectly --save-devFor fuzzy matching support (AI-generated text) β @cerios/playwright-expectly-fuzzy:
npm install @cerios/playwright-expectly-fuzzy --save-devimport { expectly } from "@cerios/playwright-expectly";
// String validation
expectly("user@example.com").toBeValidEmail();
// Number array validation
expectly([1, 2, 3, 4, 5]).toHaveAscendingOrder();
// Date validation
expectly(new Date()).toBeInTheFuture(new Date("2020-01-01"));
// Locator validation
await expectly(page.locator(".username")).toBeAlphanumeric();The simplest way to add all matchers to Playwright's native expect. Call setupExpectly() once in your Playwright config and every test file gets full IntelliSense and type support automatically β no per-file imports needed.
// playwright.config.ts
import { setupExpectly } from "@cerios/playwright-expectly";
setupExpectly();Then use expect as usual in your tests β no extra imports needed:
import { expect, test } from "@playwright/test";
test("extended expect example", async ({ page }) => {
expect("john@example.com").toBeValidEmail();
expect([1, 2, 3, 4]).toHaveAscendingOrder();
await expect(page.locator(".username")).toBeAlphanumeric();
});If your playwright.config is JavaScript or is not included in your tsconfig.json, add one ambient import in a .d.ts or shared test file so IntelliSense picks up the matcher types:
import "@cerios/playwright-expectly";To also add toMatchFuzzy() to expect, call setupExpectlyFuzzy() alongside setupExpectly():
// playwright.config.ts
import { setupExpectly } from "@cerios/playwright-expectly";
import { setupExpectlyFuzzy } from "@cerios/playwright-expectly-fuzzy";
setupExpectly();
setupExpectlyFuzzy();Both calls register their matchers globally β setupExpectlyFuzzy() also augments Playwright's Matchers interface automatically when the package is imported.
If you prefer explicit control, extend expect in a shared fixtures file and re-export it:
// tests/fixtures.ts
import { expect, test as base } from "@playwright/test";
import { expectlyMatchers } from "@cerios/playwright-expectly";
import { expectlyFuzzyMatchers } from "@cerios/playwright-expectly-fuzzy"; // optional
expect.extend(expectlyMatchers);
expect.extend(expectlyFuzzyMatchers); // optional β adds toMatchFuzzy
export { expect };
export const test = base;Then import expect from your fixtures file in every test:
import { expect, test } from "./fixtures";
test("extended expect example", async ({ page }) => {
expect("john@example.com").toBeValidEmail();
expect([1, 2, 3, 4]).toHaveAscendingOrder();
expect("Hello Wrold").toMatchFuzzy("Hello World");
await expect(page.locator(".username")).toBeAlphanumeric();
});toBeValidEmail()- Validate email formattoBeValidUrl()- Validate URL formattoBeUUID(version?)- Validate UUID (optionally specific version)toBeAlphanumeric()- Only letters and numberstoBeNumericString()- Only digitstoStartWith(prefix)/toEndWith(suffix)- String boundariestoMatchPattern(regex)- Regular expression matching
π View all string matchers β
toHaveAscendingOrder()/toHaveDescendingOrder()- Sort validationtoHaveAverage(value)/toHaveMedian(value)- Statistical validationtoHaveMin(value)/toHaveMax(value)- Boundary validationtoBeAllPositive()/toBeAllNegative()- Sign validationtoBeMonotonic()- Consistent directiontoHaveConsecutiveIntegers()- Sequential validation
π View all number array matchers β
toBeCloseTo(date, deviation)- Within time deviationtoBeInTheFuture(refDate?)/toBeInThePast(refDate?)- Temporal validationtoBeSameDay(date)/toBeSameMonth(date)/toBeSameYear(date)- Date comparisontoBeInQuarter(quarter)- Quarter validationtoBeLeapYear()- Leap year checktoHaveConsecutiveDates(unit)- Sequential dates
π View all date matchers β
toBeAlphanumeric()- Alphanumeric texttoBeNumericString()- Numeric texttoBeUUID(version?)- UUID formattoBeUpperCase()/toBeLowerCase()- Case validationtoBeTitleCase()- Title case formattoHaveSrc(value)/toHaveHref(value)/toHaveAlt(value)- Attribute validation
π View all locator matchers β
toHaveObjectsInAscendingOrderBy(property)- Sort by propertytoHaveObjectsInDescendingOrderBy(property)- Reverse sort by propertytoHaveOnlyUniqueObjects()- Uniqueness validation
π View all object array matchers β
toHaveAscendingOrder()/toHaveDescendingOrder()- Alphabetical ordertoHaveStrictlyAscendingOrder()- No duplicates ascendingtoBeMonotonic()- Consistent directiontoHaveUniqueValues()- No duplicates
π View all string array matchers β
toBeInteger()/toBeFloat()- Number type validationtoBeAnyOf(...values)- Multiple value matchingtoEqualPartially(expected)- Partial object matchingtoBeNullish()- Null or undefined checktoBePrimitive()/toBeArray()/toBeObject()- Type checking
π View all generic matchers β
toMatchFuzzy(expected, threshold?)- Fuzzy string matching using fuzzball's token-sort ratio. Works on strings and locators. Ideal for AI-generated text validation.
import { expectly } from "@cerios/playwright-expectly";
test("validate user input", async () => {
expectly("john.doe@example.com").toBeValidEmail();
expectly("https://example.com").toBeValidUrl();
expectly("550e8400-e29b-41d4-a716-446655440000").toBeUUID(4);
});test("validate sorted data", async () => {
const scores = [85, 90, 92, 95];
expectly(scores).toHaveAscendingOrder();
expectly(scores).toHaveAverage(90.5);
expectly(scores).toBeAllPositive();
});test("validate dates", async () => {
const now = new Date();
const tomorrow = new Date(now.getTime() + 86400000);
expectly(tomorrow).toBeInTheFuture(now);
expectly(tomorrow).toBeCloseTo(now, { hours: 24 });
});test("validate form elements", async ({ page }) => {
await expectly(page.locator(".email")).toBeValidEmail();
await expectly(page.locator(".username")).toBeAlphanumeric();
await expectly(page.locator("img")).toHaveAlt("Company Logo");
});Use this when you want all tests to use the extra matchers without importing expectly everywhere.
// e.g. tests/fixtures.ts or a shared setup module imported by your tests
import { expect } from "@playwright/test";
import { expectlyMatchers } from "@cerios/playwright-expectly";
expect.extend(expectlyMatchers);All matcher objects are exported, so you can extend expect with everything or only specific families.
import { expectlyDateMatchers, expectlyMatchers, expectlyStringMatchers } from "@cerios/playwright-expectly";
// All matchers
expect.extend(expectlyMatchers);
// Or only selected matcher families
expect.extend({
...expectlyStringMatchers,
...expectlyDateMatchers,
});Use this when you want a smaller, explicit API per matcher family.
import { expectlyDate, expectlyLocator, expectlyNumberArray, expectlyString } from "@cerios/playwright-expectly";
expectlyString("ABC123").toBeAlphanumeric();
expectlyNumberArray([10, 20, 30]).toHaveAscendingOrder();
expectlyDate(new Date()).toBeSameYear(new Date("2026-01-01"));
await expectlyLocator(page.locator(".email")).toBeValidEmail();For tree-shaking optimization, import only what you need:
import { expectlyString } from "@cerios/playwright-expectly";
import { expectlyNumberArray } from "@cerios/playwright-expectly";
import { expectlyDate } from "@cerios/playwright-expectly";
expectlyString("test@example.com").toBeValidEmail();
expectlyNumberArray([1, 2, 3]).toHaveAscendingOrder();
expectlyDate(new Date()).toBeInTheFuture(new Date("2020-01-01"));All matchers support .not for inverse assertions:
expectly("not-an-email").not.toBeValidEmail();
expectly([5, 3, 1]).not.toHaveAscendingOrder();
await expectly(page.locator(".text")).not.toBeNumericString();- π String Matchers - Email, URL, UUID, alphanumeric validation
- π Number Array Matchers - Sorting, statistics, range checks
- π Date Matchers - Date comparisons, quarters, business days
- π Locator Matchers - DOM element text and attribute validation
- π Object Array Matchers - Sorting and uniqueness by property
- π String Array Matchers - Alphabetical sorting and uniqueness
- π Generic Matchers - Type checking and partial matching
- π Fuzzy Matchers - AI-generated text validation with fuzzy string matching
Contributions are welcome! Feel free to open an issue or submit a pull request.
MIT Β© Cerios
- π« Report Issues
- π¬ Discussions
- π Website
Built with β€οΈ by Cerios