@cerios/playwright-expectly
v1.3.2
Published
Comprehensive Playwright test matchers for strings, numbers, dates, arrays, objects, and locators. Simplify your E2E tests with intuitive assertions like toBeAlphanumeric, toHaveAscendingOrder, toBeInTheFuture, and 50+ more matchers.
Readme
🎭 Playwright Expectly | By Cerios
Comprehensive Playwright test matchers for strings, numbers, dates, arrays, objects, and locators. Simplify your E2E tests with intuitive assertions.
Features
- 🎯 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
- 💪 Type-Safe - Full TypeScript support
- ⚡ Zero Dependencies - Only Playwright required
Installation
npm install @cerios/playwright-expectly --save-devQuick Start
Option 1: Use expectly directly
import { expectly } from "@cerios/playwright-expectly";
// String validation
expectly("[email protected]").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();Option 2: Extend Playwright expect with setupExpectly
The simplest way to add all matchers to Playwright's native expect. Call setupExpectly() once and every test file gets full type support automatically.
// 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("[email protected]").toBeValidEmail();
expect([1, 2, 3, 4]).toHaveAscendingOrder();
await expect(page.locator(".username")).toBeAlphanumeric();
});If your playwright.config is JavaScript or not included in your TypeScript project, add one ambient import once so IntelliSense sees the matcher types:
import "@cerios/playwright-expectly";Option 3: Extend Playwright expect manually
If you prefer more control, extend expect yourself in a shared fixtures file:
// tests/fixtures.ts
import { expect, test as base } from "@playwright/test";
import { expectlyMatchers } from "@cerios/playwright-expectly";
expect.extend(expectlyMatchers);
export { expect };
export const test = base;Then use the re-exported expect in tests:
import { expect, test } from "./fixtures";
test("extended expect example", async ({ page }) => {
expect("[email protected]").toBeValidEmail();
expect([1, 2, 3, 4]).toHaveAscendingOrder();
await expect(page.locator(".username")).toBeAlphanumeric();
});Available Matchers
String Matchers
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
Number Array 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 →
Date 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
Locator Matchers
toBeAlphanumeric()- Alphanumeric texttoBeNumericString()- Numeric texttoBeUUID(version?)- UUID formattoBeUpperCase()/toBeLowerCase()- Case validationtoBeTitleCase()- Title case formattoHaveSrc(value)/toHaveHref(value)/toHaveAlt(value)- Attribute validation
Object Array Matchers
toHaveObjectsInAscendingOrderBy(property)- Sort by propertytoHaveObjectsInDescendingOrderBy(property)- Reverse sort by propertytoHaveOnlyUniqueObjects()- Uniqueness validation
📖 View all object array matchers →
String Array Matchers
toHaveAscendingOrder()/toHaveDescendingOrder()- Alphabetical ordertoHaveStrictlyAscendingOrder()- No duplicates ascendingtoBeMonotonic()- Consistent directiontoHaveUniqueValues()- No duplicates
📖 View all string array matchers →
Generic Matchers
toBeInteger()/toBeFloat()- Number type validationtoBeAnyOf(...values)- Multiple value matchingtoEqualPartially(expected)- Partial object matchingtoBeNullish()- Null or undefined checktoBePrimitive()/toBeArray()/toBeObject()- Type checking
Usage Examples
Basic String Validation
import { expectly } from "@cerios/playwright-expectly";
test("validate user input", async () => {
expectly("[email protected]").toBeValidEmail();
expectly("https://example.com").toBeValidUrl();
expectly("550e8400-e29b-41d4-a716-446655440000").toBeUUID(4);
});Number Array Assertions
test("validate sorted data", async () => {
const scores = [85, 90, 92, 95];
expectly(scores).toHaveAscendingOrder();
expectly(scores).toHaveAverage(90.5);
expectly(scores).toBeAllPositive();
});Date Comparisons
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 });
});DOM Element Validation
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");
});Advanced Usage
Extend in one place (global)
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);Exported matcher objects
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 expectly families directly
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();Individual Matcher Imports
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("[email protected]").toBeValidEmail();
expectlyNumberArray([1, 2, 3]).toHaveAscendingOrder();
expectlyDate(new Date()).toBeInTheFuture(new Date("2020-01-01"));Negation
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();Documentation
- 📖 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
Contributing
Contributions are welcome! Feel free to open an issue or submit a pull request.
License
MIT © Cerios
Support
Built with ❤️ by Cerios
