@cerios/playwright-expectly

中文文档
2.1.0发布于 2026/11/06MITTypeScriptESM + CJS构建来源已验证近 30 天下载 2804

Comprehensive Playwright test matchers for strings, numbers, dates, arrays, objects, and locators. Simplify your E2E tests with intuitive assertions like toBeAlphanumeric, toHaveAscendingOrder, toBeInTheFuture, and 130+ more matchers.

原始使用文档
文档目录10 节
  1. Features
  2. Installation
  3. Quick Start
  4. Recommended: a single tests/support module for native expect
  5. Standalone expectly
  6. Available Matchers
  7. Links
  8. License
  9. Returning values from retrying assertions
  10. Edge-case behavior

🎭 Playwright Expectly | By Cerios

npm version License: MIT

Comprehensive Playwright test matchers for strings, numbers, dates, arrays, objects, locators, and page state. Simplify your E2E tests with intuitive assertions like toBeAlphanumeric, toHaveAscendingOrder, toBeInTheFuture, and 130+ more matchers.

Features

  • 🎯 130+ Custom Matchers — extensive validation for all data types
  • 🔤 String Validation — email, URL, UUID, alphanumeric, hexadecimal, case-insensitive equality, and more
  • 🔢 Number Arrays — sorting, statistics, ranges, and patterns
  • 📅 Date & Time — Date, ISO strings and Temporal; time zones, DST, nanosecond precision, durations
  • 🎨 Locator Assertions — DOM element validation, text formatting, count ranges, sorted texts, and computed styles
  • 🍪 Page State — retrying cookie, localStorage and sessionStorage assertions
  • 📦 Object Arrays — sorting, uniqueness, and property validation
  • 🧺 Collections & Functions — array members, object keys and entries, promises, and thrown errors
  • 🤖 Fuzzy Matching — AI-generated text validation (separate @cerios/playwright-expectly-fuzzy package)
  • 💪 Type-Safe — full TypeScript support
  • ⚡ Lightweight — only Playwright required

Installation

npm install @cerios/playwright-expectly --save-dev

Peer dependency: requires @playwright/test to be installed.

Quick Start

Create ONE shared module in your own project that extends Playwright's expect and captures the return value, then re-exports it. Every fixture file and spec file imports test/expect from this module — never straight from @playwright/test.

// tests/support/expect.ts
import "@cerios/playwright-expectly";

import { expectlyMatchers } from "@cerios/playwright-expectly";
import { expect as baseExpect, test as base } from "@playwright/test";

// MUST capture the return value — never call `.extend()` and discard it.
export const expect = baseExpect.extend(expectlyMatchers);
export const test = base;
import { expect, test } from "./support/expect";

test("extended expect example", async ({ page }) => {
    expect("[email protected]").toBeValidEmail();
    expect([1, 2, 3, 4]).toHaveAscendingOrder();
    expect(new Date("2025-01-02")).toBeDateCloseTo(new Date("2025-01-01"), { days: 1 });
    await expect(page.locator(".username")).toBeAlphanumeric();
});

Capturing the return value is the key detail: the value returned by .extend(...) is the fully typed expect that carries the Expectly matchers. Expectly never overrides a Playwright built-in matcher, so Playwright's own matchers (including numeric toBeCloseTo) keep working on it unchanged.

Standalone expectly

import { expectly } from "@cerios/playwright-expectly";

expectly("[email protected]").toBeValidEmail();
expectly([1, 2, 3, 4, 5]).toHaveAscendingOrder();
expectly(subscription.expiresAt).toBeInTheFuture();
await expectly(page.locator(".username")).toBeAlphanumeric();

Combining with @cerios/playwright-expectly-fuzzy, or your own matchers, via mergeExpects():

import { expectlyMatchers } from "@cerios/playwright-expectly";
import { expectlyFuzzyMatchers } from "@cerios/playwright-expectly-fuzzy";
// tests/support/expect.ts
import { expect as baseExpect, mergeExpects, test as base } from "@playwright/test";

const expectlyExpect = baseExpect.extend(expectlyMatchers);
const fuzzyExpect = baseExpect.extend(expectlyFuzzyMatchers);

export const expect = mergeExpects(baseExpect, expectlyExpect, fuzzyExpect);
export const test = base;

If you only need the standalone package exports, the shorter form is also valid:

import { expectly } from "@cerios/playwright-expectly";
import { expectlyFuzzy } from "@cerios/playwright-expectly-fuzzy";
import { expect as baseExpect, mergeExpects, test as base } from "@playwright/test";

export const expect = mergeExpects(baseExpect, expectly, expectlyFuzzy);
export const test = base;

Upgrading from 1.x: the Date matcher toBeCloseTo is renamed to toBeDateCloseTo, the deprecated setupExpectly() is removed (use the tests/support pattern above instead), and the date matchers are rebuilt on Temporal with exact calendar semantics: toBeValidISODate() now validates YYYY-MM-DD and toMatchTimeZone() is replaced by toHaveOffset() / toHaveTimeZone(). See the root README for migration examples.

Available Matchers

  • String — toBeValidEmail(), toBeValidUrl(), toBeUUID(), toBeAlphanumeric(), toBeHexadecimal(), toEqualCaseInsensitive(), toEqualIgnoringWhitespace(), toMatchPattern(), and more — 📖 docs
  • Number Array — toHaveAscendingOrder(), toHaveAverage(), toBeAllPositive(), toBeMonotonic(), and more — 📖 docs
  • Date & Time — Date, ISO strings and Temporal values: toBeWithinLast(), toBeWithinDurationAfter(), toBeSameInstant(), toBeSameDay(), toBeWithinTimeOfDay(), toHaveOffset(), duration matchers, plus parseISO*() / isISO*() and typed ISO strings — 📖 docs
  • Locator — toBeAlphanumeric(), toBeUpperCase(), toHaveSrc(), toHaveStyles(), toHaveCountGreaterThan(), toHaveCountBetween(), toHaveTextsInAscendingOrder(), and more — 📖 docs
  • Page — toHaveCookie() on a Page or BrowserContext, toHaveLocalStorageItem(), toHaveSessionStorageItem() — 📖 docs
  • Object Array — toHaveObjectsInAscendingOrderBy(), toHaveOnlyUniqueObjects(), and more — 📖 docs
  • String Array — toHaveAscendingOrder(), toHaveStrictlyAscendingOrder(), toHaveUniqueValues(), and more — 📖 docs
  • Generic — toBeInteger(), toBeAnyOf(), toSatisfy(), toBeEven(), toBeFinite(), toEqualPartially(), toBeNullish(), and more — 📖 docs
  • Collection & Function — toSatisfyAll(), toIncludeSameMembers(), toContainKeys(), toContainEntry(), toBeEmptyObject(), toResolve(), toReject(), toThrowWithMessage(), and more — 📖 docs

License

MIT © Cerios

Returning values from retrying assertions

expectly.pollAndReturn() returns the value that satisfied the matcher. expectly(callback).toPassAndReturn() returns the result of the first callback attempt that completes without throwing. Both support synchronous and asynchronous callbacks without calling them again after success.

import { expectly } from "@cerios/playwright-expectly";

const order = await expectly
    .pollAndReturn(() => fetchOrder(), { timeout: 5_000, intervals: [100, 250] })
    .toMatchObject({ status: "COMPLETED" });

const readyOrder = await expectly(async () => {
    const current = await fetchOrder();
    expectly(current.status).toBe("COMPLETED");
    return current;
}).toPassAndReturn({ timeout: 5_000, intervals: [100, 250] });

Here, fetchOrder() is your application helper. Polling supports .not and registered custom matchers. Retry options and custom messages follow the corresponding Playwright APIs; toPassAndReturn() uses native toPass() timeout behavior, so provide an explicit timeout when you need a bound.

For your own configured or extended expect instance, apply withReturn() after composing matcher sources:

import { expectlyMatchers, withReturn } from "@cerios/playwright-expectly";
import { expect as baseExpect } from "@playwright/test";

export const expect = withReturn(baseExpect.extend(expectlyMatchers));
const uuid = await expect.pollAndReturn(() => fetchUuid()).toBeUUID(4);

Subsequent .soft, .configure() and .extend() calls preserve the return-aware methods and custom matcher types. When using mergeExpects(), wrap its result with withReturn().

Failure behavior: by default, return-aware assertions throw on failure, like other Playwright assertions.

Soft assertions: use .soft or .configure({ soft: true }). A failure is then recorded and the test continues, as with native soft assertions. Because the assertion did not pass, the result may not be a passing value:

  • toPassAndReturn() resolves with undefined, because no attempt succeeded.
  • pollAndReturn() resolves with the last polled value, which did not satisfy the matcher. It resolves with undefined if the callback never returned a value.
const order = await expectly.soft.pollAndReturn(() => fetchOrder()).toMatchObject({ status: "COMPLETED" });
const readyOrder = await expectly.soft(() => fetchReadyOrder()).toPassAndReturn({ timeout: 5_000 });
// Both are typed `Order | undefined`; the test is already marked as failed when a check did not pass.

Soft return types are T | undefined. TypeScript can only track this when the soft flag is set on the wrapped instance (expectly.soft, withReturn(expect).configure({ soft: true })). withReturn(expect.configure({ soft: true })) behaves the same at runtime, but its types still say T.

Regular assertions retain their configured behavior. Inside toPassAndReturn() callbacks, use throwing assertions for conditions that must trigger retries; soft assertions do not throw.

Failure locations: return-aware assertions appear as boxed Playwright steps. The assertion step and reported failure point to the line where your test invokes the matcher, including detached matcher calls. Native retry steps remain nested underneath for diagnostics and may show internal implementation locations when expanded. Caught errors also point to the invocation while retaining their original message, matcher details, and cause. Regular assertions keep their native reporting.

Ordinary Expectly matchers also report thrown validation and locator API errors at your assertion call site. Their original error type, message, cause, and metadata are preserved. Expanded native equality, polling, and browser API steps can still show implementation locations.

Edge-case behavior

  • Object uniqueness compares current values using Node's deep strict equality, including Dates, Maps, Sets, bigint, and cycles. There is no cache across assertions. Property order does not matter; prototypes and explicit undefined properties do. This comparison can take quadratic time for large arrays.
  • Regex assertions test from index zero without modifying the supplied expression's lastIndex, including global and sticky expressions.
  • Partial matching supports shared references but rejects circular plain objects and arrays in either input with a clear error, including under .not.
  • Numeric comparisons reject NaN and infinities. Sum, average, median and range tolerate the rounding error of the whole computation, which grows with the number of values and their magnitude, so [0.01, 2.03, 1.2] sums to 3.24; pass { tolerance } for an explicit absolute bound. Empty arrays have no average or median and never match.
  • Consecutive months compare calendar months, independent of the day of month. ISO validation rejects impossible calendar dates such as 2026-02-30; see the date matchers for the accepted formats.
  • A pollAndReturn() assertion object can be reused or invoked concurrently; each matcher invocation captures its own successful value.

CI tests packaged libraries against the minimum supported Playwright version, 1.40, as well as the project's current version. The minimum-version declaration check uses TypeScript 5.9 because TypeScript 7 rejects legacy syntax in Playwright 1.40's own declarations.

版本与发布记录

@cerios/playwright-expectly 共发布 15 个版本,首次发布于 2025/12/01;过去 12 个月发布了 15 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.1.0latest2026/11/063 天前
2.0.12026/10/2911 天前
2.0.02026/10/2613 天前
1.4.12026/09/161 个月前
1.4.02026/07/163 个月前
1.3.52026/07/034 个月前

关于 @cerios/playwright-expectly 的常见问题

@cerios/playwright-expectly 是什么?

Comprehensive Playwright test matchers for strings, numbers, dates, arrays, objects, and locators. Simplify your E2E tests with intuitive assertions like toBeAlphanumeric, toHaveAscendingOrder, toBeInTheFuture, and 130+ more matchers.

如何安装 @cerios/playwright-expectly?

在项目目录运行 npm install @cerios/playwright-expectly,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@playwright/test(>=1.40.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@cerios/playwright-expectly 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cerios/playwright-expectly 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@cerios/playwright-expectly 可以商用吗?

@cerios/playwright-expectly 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cerios/playwright-expectly 的下载量有多少?

根据 npm 官方下载统计,@cerios/playwright-expectly 在 2026/10/10 – 2026/11/08 这 30 天内被下载 2,804 次,日均约 93 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cerios/playwright-expectly 还在维护吗?

最新版本 2.1.0 发布于 2026/11/06(3 天前);至今共发布 15 个版本,其中过去 12 个月发布了 15 个;首次发布于 2025/12/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。