From f46883e58e12847db71cadfc9364289e71278ee3 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Wed, 1 Feb 2023 16:55:52 -0800 Subject: [PATCH] feat(expect): add GenericAssertions documentation (#20564) References #20432. --- docs/src/api/class-genericassertions.md | 534 ++++++++++++++++++ docs/src/api/class-playwrightassertions.md | 14 + .../playwright-test/types/expect-types.d.ts | 257 --------- packages/playwright-test/types/test.d.ts | 416 +++++++++++++- tests/playwright-test/expect.spec.ts | 76 ++- utils/doclint/missingDocs.js | 2 +- utils/generate_types/index.js | 2 +- utils/generate_types/overrides-test.d.ts | 30 +- 8 files changed, 1067 insertions(+), 264 deletions(-) create mode 100644 docs/src/api/class-genericassertions.md diff --git a/docs/src/api/class-genericassertions.md b/docs/src/api/class-genericassertions.md new file mode 100644 index 0000000000..575c46e58b --- /dev/null +++ b/docs/src/api/class-genericassertions.md @@ -0,0 +1,534 @@ +# class: GenericAssertions +* since: v1.9 +* langs: js + +The [GenericAssertions] class provides assertion methods that can be used to make assertions about any values in the tests. A new instance of [GenericAssertions] is created by calling [`method: PlaywrightAssertions.expectGeneric`]: + +```js +import { test, expect } from '@playwright/test'; + +test('assert a value', async ({ page }) => { + const value = 1; + await expect(value).toBe(2); +}); +``` + +## property: GenericAssertions.not +* since: v1.9 +- returns: <[GenericAssertions]> + +Makes the assertion check for the opposite condition. For example, the following code passes: + +```js +const value = 1; +await expect(value).not.toBe(2); +``` + + +## method: GenericAssertions.toBe +* since: v1.9 + +Compares value with [`param: expected`] by calling `Object.is`. This method compares objects by reference instead of their contents, similarly to the strict equality operator `===`. + +**Usage** + +```js +const value = { prop: 1 }; +expect(value).toBe(value); +expect(value).not.toBe({}); +expect(value.prop).toBe(1); +``` + +### param: GenericAssertions.toBe.expected +* since: v1.9 +- `expected` <[any]> + +Expected value. + + + +## method: GenericAssertions.toBeCloseTo +* since: v1.9 + +Compares floating point numbers for approximate equality. Use this method instead of [`method: GenericAssertions.toBe`] when comparing floating point numbers. + +**Usage** + +```js +expect(0.1 + 0.2).not.toBe(0.3); +expect(0.1 + 0.2).toBeCloseTo(0.3, 5); +``` + +### param: GenericAssertions.toBeCloseTo.expected +* since: v1.9 +- `expected` <[float]> + +Expected value. + +### param: GenericAssertions.toBeCloseTo.numDigits +* since: v1.9 +- `numDigits` ?<[int]> + +The number of decimal digits after the decimal point that must be equal. + + + +## method: GenericAssertions.toBeDefined +* since: v1.9 + +Ensures that value is not `undefined`. + +**Usage** + +```js +const value = null; +expect(value).toBeDefined(); +``` + + +## method: GenericAssertions.toBeFalsy +* since: v1.9 + +Ensures that value is false in a boolean context, one of `false`, `0`, `''`, `null`, `undefined` or `NaN`. Use this method when you don't care about the specific value. + +**Usage** + +```js +const value = null; +expect(value).toBeFalsy(); +``` + + +## method: GenericAssertions.toBeGreaterThan +* since: v1.9 + +Ensures that `value > expected` for number or big integer values. + +**Usage** + +```js +const value = 42; +expect(value).toBeGreaterThan(1); +``` + +### param: GenericAssertions.toBeGreaterThan.expected +* since: v1.9 +- `expected` <[float]|[bigint]> + +The value to compare to. + + + +## method: GenericAssertions.toBeGreaterThanOrEqual +* since: v1.9 + +Ensures that `value >= expected` for number or big integer values. + +**Usage** + +```js +const value = 42; +expect(value).toBeGreaterThanOrEqual(42); +``` + +### param: GenericAssertions.toBeGreaterThanOrEqual.expected +* since: v1.9 +- `expected` <[float]|[bigint]> + +The value to compare to. + + + +## method: GenericAssertions.toBeInstanceOf +* since: v1.9 + +Ensures that value is an instance of a class. Uses `instanceof` operator. + +**Usage** + +```js +expect(page).toBeInstanceOf(Page); + +class Example {} +expect(new Example()).toBeInstanceOf(Example); +``` + +### param: GenericAssertions.toBeInstanceOf.expected +* since: v1.9 +- `expected` <[Function]> + +The class or constructor function. + + + +## method: GenericAssertions.toBeLessThan +* since: v1.9 + +Ensures that `value < expected` for number or big integer values. + +**Usage** + +```js +const value = 42; +expect(value).toBeLessThan(100); +``` + +### param: GenericAssertions.toBeLessThan.expected +* since: v1.9 +- `expected` <[float]|[bigint]> + +The value to compare to. + + + +## method: GenericAssertions.toBeLessThanOrEqual +* since: v1.9 + +Ensures that `value <= expected` for number or big integer values. + +**Usage** + +```js +const value = 42; +expect(value).toBeLessThanOrEqual(42); +``` + +### param: GenericAssertions.toBeLessThanOrEqual.expected +* since: v1.9 +- `expected` <[float]|[bigint]> + +The value to compare to. + + + +## method: GenericAssertions.toBeNaN +* since: v1.9 + +Ensures that value is `NaN`. + +**Usage** + +```js +const value = NaN; +expect(value).toBeNaN(); +``` + + +## method: GenericAssertions.toBeNull +* since: v1.9 + +Ensures that value is `null`. + +**Usage** + +```js +const value = null; +expect(value).toBeNull(); +``` + + + +## method: GenericAssertions.toBeTruthy +* since: v1.9 + +Ensures that value is true in a boolean context, **anything but** `false`, `0`, `''`, `null`, `undefined` or `NaN`. Use this method when you don't care about the specific value. + +**Usage** + +```js +const value = { example: 'value' }; +expect(value).toBeTruthy(); +``` + + +## method: GenericAssertions.toBeUndefined +* since: v1.9 + +Ensures that value is `undefined`. + +**Usage** + +```js +const value = undefined; +expect(value).toBeUndefined(); +``` + + +## method: GenericAssertions.toContain#1 +* since: v1.9 + +Ensures that string value contains an expected substring. Comparison is case-sensitive. + +**Usage** + +```js +const value = 'Hello, World'; +expect(value).toContain('World'); +expect(value).toContain(','); +``` + +### param: GenericAssertions.toContain#1.expected +* since: v1.9 +- `expected` <[string]> + +Expected substring. + + + +## method: GenericAssertions.toContain#2 +* since: v1.9 + +Ensures that value is an `Array` or `Set` and contains an expected item. + +**Usage** + +```js +const value = [1, 2, 3]; +expect(value).toContain(2); +expect(new Set(value)).toContain(2); +``` + +### param: GenericAssertions.toContain#2.expected +* since: v1.9 +- `expected` <[any]> + +Expected value in the collection. + + + +## method: GenericAssertions.toContainEqual +* since: v1.9 + +Ensures that value is an `Array` or `Set` and contains an item equal to the expected. + +For objects, this method recursively checks equality of all fields, rather than comparing objects by reference as performed by [`method: GenericAssertions.toContain#2`]. + +For primitive values, this method is equivalent to [`method: GenericAssertions.toContain#2`]. + +**Usage** + +```js +const value = [ + { example: 1 }, + { another: 2 }, + { more: 3 }, +]; +expect(value).toContainEqual({ another: 2 }); +expect(new Set(value)).toContainEqual({ another: 2 }); +``` + +### param: GenericAssertions.toContainEqual.expected +* since: v1.9 +- `expected` <[any]> + +Expected value in the collection. + + + +## method: GenericAssertions.toEqual +* since: v1.9 + +Compares contents of the value with contents of [`param: expected`], performing "deep equality" check. + +For objects, this method recursively checks equality of all fields, rather than comparing objects by reference as performed by [`method: GenericAssertions.toBe`]. + +For primitive values, this method is equivalent to [`method: GenericAssertions.toBe`]. + +**Usage** + +```js +const value = { prop: 1 }; +expect(value).toEqual({ prop: 1 }); +``` + +### param: GenericAssertions.toEqual.expected +* since: v1.9 +- `expected` <[any]> + +Expected value. + + + +## method: GenericAssertions.toHaveLength +* since: v1.9 + +Ensures that value has a `.length` property equal to [`param: expected`]. Useful for arrays and strings. + +**Usage** + +```js +expect('Hello, World').toHaveLength(12); +expect([1, 2, 3]).toHaveLength(3); +``` + +### param: GenericAssertions.toHaveLength.expected +* since: v1.9 +- `expected` <[int]> + +Expected length. + + + +## method: GenericAssertions.toHaveProperty +* since: v1.9 + +Ensures that property at provided `keyPath` exists on the object and optionally checks that property is equal to the [`param: expected`]. Equality is checked recursively, similarly to [`method: GenericAssertions.toEqual`]. + +**Usage** + +```js +const value = { + a: { + b: [42], + }, + c: true, +}; +expect(value).toHaveProperty('a.b'); +expect(value).toHaveProperty('a.b', [42]); +expect(value).toHaveProperty('a.b[0]', 42); +expect(value).toHaveProperty('c'); +expect(value).toHaveProperty('c', true); +``` + +### param: GenericAssertions.toHaveProperty.keyPath +* since: v1.9 +- `keyPath` <[string]> + +Path to the property. Use dot notation `a.b` to check nested properties and indexed `a[2]` notation to check nested array items. + +### param: GenericAssertions.toHaveProperty.expected +* since: v1.9 +- `expected` ?<[any]> + +Optional expected value to compare the property to. + + + +## method: GenericAssertions.toMatch +* since: v1.9 + +Ensures that string value matches a regular expression. + +**Usage** + +```js +const value = 'Is 42 enough?'; +expect(value).toMatches(/Is \d+ enough/); +``` + +### param: GenericAssertions.toMatch.expected +* since: v1.9 +- `expected` <[RegExp]> + +Regular expression to match against. + + + +## method: GenericAssertions.toMatchObject +* since: v1.9 + +Compares contents of the value with contents of [`param: expected`], performing "deep equality" check. Allows extra properties to be present in the value, unlike [`method: GenericAssertions.toEqual`], so you can check just a subset of object properties. + +When comparing arrays, the number of items must match, and each item is checked recursively. + +**Usage** + +```js +const value = { + a: 1, + b: 2, + c: true, +}; +expect(value).toMatchObject({ a: 1, c: true }); +expect(value).toMatchObject({ b: 2, c: true }); + +expect([{ a: 1, b: 2 }]).toMatchObject([{ a: 1 }]); +``` + +### param: GenericAssertions.toMatchObject.expected +* since: v1.9 +- `expected` <[Object]|[Array]> + +The expected object value to match against. + + + +## method: GenericAssertions.toStrictEqual +* since: v1.9 + +Compares contents of the value with contents of [`param: expected`] **and** their types. + +Differences from [`method: GenericAssertions.toEqual`]: + +* Keys with undefined properties are checked. For example, `{ a: undefined, b: 2 }` does not match `{ b: 2 }`. +* Array sparseness is checked. For example, `[, 1]` does not match `[undefined, 1]`. +* Object types are checked to be equal. For example, a class instance with fields `a` and `b` will not equal a literal object with fields `a` and `b`. + +**Usage** + +```js +const value = { prop: 1 }; +expect(value).toStrictEqual({ prop: 1 }); +``` + +### param: GenericAssertions.toStrictEqual.expected +* since: v1.9 +- `expected` <[any]> + +Expected value. + + + +## method: GenericAssertions.toThrow +* since: v1.9 + +Calls the function and ensures it throws an error. + +Optionally compares the error with [`param: expected`]. Allowed expected values: +* Regular expression - error message should **match** the pattern. +* String - error message should **include** the substring. +* Error object - error message should be **equal to** the message property of the object. +* Error class - error object should be an **instance of** the class. + +**Usage** + +```js +expect(() => { + throw new Error('Something bad'); +}).toThrow(); + +expect(() => { + throw new Error('Something bad'); +}).toThrow(/something/); + +expect(() => { + throw new Error('Something bad'); +}).toThrow(Error); +``` + +### param: GenericAssertions.toThrow.expected +* since: v1.9 +- `expected` ?<[any]> + +Expected error message or error object. + + + +## method: GenericAssertions.toThrowError +* since: v1.9 + +An alias for [`method: GenericAssertions.toThrow`]. + +**Usage** + +```js +expect(() => { + throw new Error('Something bad'); +}).toThrowError(); +``` + +### param: GenericAssertions.toThrowError.expected +* since: v1.9 +- `expected` ?<[any]> + +Expected error message or error object. diff --git a/docs/src/api/class-playwrightassertions.md b/docs/src/api/class-playwrightassertions.md index 62f12df971..4495277a4c 100644 --- a/docs/src/api/class-playwrightassertions.md +++ b/docs/src/api/class-playwrightassertions.md @@ -96,6 +96,20 @@ PlaywrightAssertions.assertThat(response).isOK(); [APIResponse] object to use for assertions. +## method: PlaywrightAssertions.expectGeneric +* since: v1.9 +* langs: + - alias-js: expect +- returns: <[GenericAssertions]> + +Creates a [GenericAssertions] object for the given value. + +### param: PlaywrightAssertions.expectGeneric.value +* since: v1.9 +- `value` <[any]> + +Value that will be asserted. + ## method: PlaywrightAssertions.expectLocator * since: v1.18 * langs: diff --git a/packages/playwright-test/types/expect-types.d.ts b/packages/playwright-test/types/expect-types.d.ts index c08dc5f0c5..272488eb1f 100644 --- a/packages/playwright-test/types/expect-types.d.ts +++ b/packages/playwright-test/types/expect-types.d.ts @@ -108,261 +108,4 @@ export declare type MatcherState = { // }; // --------------------------------------- -// -------------- Playwright ------------- -// - Some of the removed matchers below require jest.fn -// - Some are overridden. -// - Some are missing (inline snapshot). -// --------------------------------------- -export interface Matchers { - // /** - // * Ensures the last call to a mock function was provided specific args. - // */ - // lastCalledWith(...args: Array): R; - // /** - // * Ensure that the last call to a mock function has returned a specified value. - // */ - // lastReturnedWith(value: unknown): R; - // /** - // * If you know how to test something, `.not` lets you test its opposite. - // */ - // not: Matchers; - // /** - // * Ensure that a mock function is called with specific arguments on an Nth call. - // */ - // nthCalledWith(nthCall: number, ...args: Array): R; - // /** - // * Ensure that the nth call to a mock function has returned a specified value. - // */ - // nthReturnedWith(n: number, value: unknown): R; - // /** - // * Use resolves to unwrap the value of a fulfilled promise so any other - // * matcher can be chained. If the promise is rejected the assertion fails. - // */ - // resolves: Matchers>; - // /** - // * Unwraps the reason of a rejected promise so any other matcher can be chained. - // * If the promise is fulfilled the assertion fails. - // */ - // rejects: Matchers>; - /** - * Checks that a value is what you expect. It uses `===` to check strict equality. - * Don't use `toBe` with floating-point numbers. - */ - toBe(expected: unknown): R; - // /** - // * Ensures that a mock function is called. - // */ - // toBeCalled(): R; - // /** - // * Ensures that a mock function is called an exact number of times. - // */ - // toBeCalledTimes(expected: number): R; - // /** - // * Ensure that a mock function is called with specific arguments. - // */ - // toBeCalledWith(...args: Array): R; - /** - * Using exact equality with floating point numbers is a bad idea. - * Rounding means that intuitive things fail. - * The default for numDigits is 2. - */ - toBeCloseTo(expected: number, numDigits?: number): R; - /** - * Ensure that a variable is not undefined. - */ - toBeDefined(): R; - /** - * When you don't care what a value is, you just want to - * ensure a value is false in a boolean context. - */ - toBeFalsy(): R; - /** - * For comparing floating point numbers. - */ - toBeGreaterThan(expected: number | bigint): R; - /** - * For comparing floating point numbers. - */ - toBeGreaterThanOrEqual(expected: number | bigint): R; - /** - * Ensure that an object is an instance of a class. - * This matcher uses `instanceof` underneath. - */ - toBeInstanceOf(expected: Function): R; - /** - * For comparing floating point numbers. - */ - toBeLessThan(expected: number | bigint): R; - /** - * For comparing floating point numbers. - */ - toBeLessThanOrEqual(expected: number | bigint): R; - /** - * This is the same as `.toBe(null)` but the error messages are a bit nicer. - * So use `.toBeNull()` when you want to check that something is null. - */ - toBeNull(): R; - /** - * Use when you don't care what a value is, you just want to ensure a value - * is true in a boolean context. In JavaScript, there are six falsy values: - * `false`, `0`, `''`, `null`, `undefined`, and `NaN`. Everything else is truthy. - */ - toBeTruthy(): R; - /** - * Used to check that a variable is undefined. - */ - toBeUndefined(): R; - /** - * Used to check that a variable is NaN. - */ - toBeNaN(): R; - /** - * Used when you want to check that an item is in a list. - * For testing the items in the list, this uses `===`, a strict equality check. - */ - toContain(expected: unknown): R; - /** - * Used when you want to check that an item is in a list. - * For testing the items in the list, this matcher recursively checks the - * equality of all fields, rather than checking for object identity. - */ - toContainEqual(expected: unknown): R; - /** - * Used when you want to check that two objects have the same value. - * This matcher recursively checks the equality of all fields, rather than checking for object identity. - */ - toEqual(expected: unknown): R; - // /** - // * Ensures that a mock function is called. - // */ - // toHaveBeenCalled(): R; - // /** - // * Ensures that a mock function is called an exact number of times. - // */ - // toHaveBeenCalledTimes(expected: number): R; - // /** - // * Ensure that a mock function is called with specific arguments. - // */ - // toHaveBeenCalledWith(...args: Array): R; - // /** - // * Ensure that a mock function is called with specific arguments on an Nth call. - // */ - // toHaveBeenNthCalledWith(nthCall: number, ...args: Array): R; - // /** - // * If you have a mock function, you can use `.toHaveBeenLastCalledWith` - // * to test what arguments it was last called with. - // */ - // toHaveBeenLastCalledWith(...args: Array): R; - // /** - // * Use to test the specific value that a mock function last returned. - // * If the last call to the mock function threw an error, then this matcher will fail - // * no matter what value you provided as the expected return value. - // */ - // toHaveLastReturnedWith(expected: unknown): R; - /** - * Used to check that an object has a `.length` property - * and it is set to a certain numeric value. - */ - toHaveLength(expected: number): R; - // /** - // * Use to test the specific value that a mock function returned for the nth call. - // * If the nth call to the mock function threw an error, then this matcher will fail - // * no matter what value you provided as the expected return value. - // */ - // toHaveNthReturnedWith(nthCall: number, expected: unknown): R; - /** - * Use to check if property at provided reference keyPath exists for an object. - * For checking deeply nested properties in an object you may use dot notation or an array containing - * the keyPath for deep references. - * - * Optionally, you can provide a value to check if it's equal to the value present at keyPath - * on the target object. This matcher uses 'deep equality' (like `toEqual()`) and recursively checks - * the equality of all fields. - * - * @example - * - * expect(houseForSale).toHaveProperty('kitchen.area', 20); - */ - toHaveProperty(keyPath: string | Array, value?: unknown): R; - // /** - // * Use to test that the mock function successfully returned (i.e., did not throw an error) at least one time - // */ - // toHaveReturned(): R; - // /** - // * Use to ensure that a mock function returned successfully (i.e., did not throw an error) an exact number of times. - // * Any calls to the mock function that throw an error are not counted toward the number of times the function returned. - // */ - // toHaveReturnedTimes(expected: number): R; - // /** - // * Use to ensure that a mock function returned a specific value. - // */ - // toHaveReturnedWith(expected: unknown): R; - /** - * Check that a string matches a regular expression. - */ - toMatch(expected: string | RegExp): R; - /** - * Used to check that a JavaScript object matches a subset of the properties of an object - */ - toMatchObject(expected: Record | Array): R; - // /** - // * Ensure that a mock function has returned (as opposed to thrown) at least once. - // */ - // toReturn(): R; - // /** - // * Ensure that a mock function has returned (as opposed to thrown) a specified number of times. - // */ - // toReturnTimes(count: number): R; - // /** - // * Ensure that a mock function has returned a specified value at least once. - // */ - // toReturnWith(value: unknown): R; - /** - * Use to test that objects have the same types as well as structure. - */ - toStrictEqual(expected: unknown): R; - /** - * Used to test that a function throws when it is called. - */ - toThrow(error?: unknown): R; - /** - * If you want to test that a specific error is thrown inside a function. - */ - toThrowError(error?: unknown): R; - // /** - // * This ensures that a value matches the most recent snapshot with property matchers. - // * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - // */ - // toMatchSnapshot(propertyMatchers: Partial, snapshotName?: string): R; - // /** - // * This ensures that a value matches the most recent snapshot. - // * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - // */ - // toMatchSnapshot(snapshotName?: string): R; - // /** - // * This ensures that a value matches the most recent snapshot with property matchers. - // * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. - // * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - // */ - // toMatchInlineSnapshot(propertyMatchers: Partial, snapshot?: string): R; - // /** - // * This ensures that a value matches the most recent snapshot with property matchers. - // * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. - // * Check out [the Snapshot Testing guide](https://jestjs.io/docs/snapshot-testing) for more information. - // */ - // toMatchInlineSnapshot(snapshot?: string): R; - // /** - // * Used to test that a function throws a error matching the most recent snapshot when it is called. - // */ - // toThrowErrorMatchingSnapshot(): R; - // /** - // * Used to test that a function throws a error matching the most recent snapshot when it is called. - // * Instead of writing the snapshot value to a .snap file, it will be written into the source code automatically. - // */ - // toThrowErrorMatchingInlineSnapshot(snapshot?: string): R; -} export {}; diff --git a/packages/playwright-test/types/test.d.ts b/packages/playwright-test/types/test.d.ts index f26b382f9b..6afe389f07 100644 --- a/packages/playwright-test/types/test.d.ts +++ b/packages/playwright-test/types/test.d.ts @@ -3780,7 +3780,421 @@ type Inverse = { type IfAny = 0 extends (1 & T) ? Y : N; type ExtraMatchers = T extends Type ? Matchers : IfAny; -type BaseMatchers = expectType.Matchers & PlaywrightTest.Matchers; +/** + * The [GenericAssertions] class provides assertion methods that can be used to make assertions about any values in + * the tests. A new instance of [GenericAssertions] is created by calling + * [expect(value)](https://playwright.dev/docs/api/class-playwrightassertions#playwright-assertions-expect-generic): + * + * ```js + * import { test, expect } from '@playwright/test'; + * + * test('assert a value', async ({ page }) => { + * const value = 1; + * await expect(value).toBe(2); + * }); + * ``` + * + */ +interface GenericAssertions { + /** + * Makes the assertion check for the opposite condition. For example, the following code passes: + * + * ```js + * const value = 1; + * await expect(value).not.toBe(2); + * ``` + * + */ + not: GenericAssertions; + /** + * Compares value with `expected` by calling `Object.is`. This method compares objects by reference instead of their + * contents, similarly to the strict equality operator `===`. + * + * **Usage** + * + * ```js + * const value = { prop: 1 }; + * expect(value).toBe(value); + * expect(value).not.toBe({}); + * expect(value.prop).toBe(1); + * ``` + * + * @param expected Expected value. + */ + toBe(expected: unknown): R; + /** + * Compares floating point numbers for approximate equality. Use this method instead of + * [genericAssertions.toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be) + * when comparing floating point numbers. + * + * **Usage** + * + * ```js + * expect(0.1 + 0.2).not.toBe(0.3); + * expect(0.1 + 0.2).toBeCloseTo(0.3, 5); + * ``` + * + * @param expected Expected value. + * @param numDigits The number of decimal digits after the decimal point that must be equal. + */ + toBeCloseTo(expected: number, numDigits?: number): R; + /** + * Ensures that value is not `undefined`. + * + * **Usage** + * + * ```js + * const value = null; + * expect(value).toBeDefined(); + * ``` + * + */ + toBeDefined(): R; + /** + * Ensures that value is false in a boolean context, one of `false`, `0`, `''`, `null`, `undefined` or `NaN`. Use this + * method when you don't care about the specific value. + * + * **Usage** + * + * ```js + * const value = null; + * expect(value).toBeFalsy(); + * ``` + * + */ + toBeFalsy(): R; + /** + * Ensures that `value > expected` for number or big integer values. + * + * **Usage** + * + * ```js + * const value = 42; + * expect(value).toBeGreaterThan(1); + * ``` + * + * @param expected The value to compare to. + */ + toBeGreaterThan(expected: number | bigint): R; + /** + * Ensures that `value >= expected` for number or big integer values. + * + * **Usage** + * + * ```js + * const value = 42; + * expect(value).toBeGreaterThanOrEqual(42); + * ``` + * + * @param expected The value to compare to. + */ + toBeGreaterThanOrEqual(expected: number | bigint): R; + /** + * Ensures that value is an instance of a class. Uses `instanceof` operator. + * + * **Usage** + * + * ```js + * expect(page).toBeInstanceOf(Page); + * + * class Example {} + * expect(new Example()).toBeInstanceOf(Example); + * ``` + * + * @param expected The class or constructor function. + */ + toBeInstanceOf(expected: Function): R; + /** + * Ensures that `value < expected` for number or big integer values. + * + * **Usage** + * + * ```js + * const value = 42; + * expect(value).toBeLessThan(100); + * ``` + * + * @param expected The value to compare to. + */ + toBeLessThan(expected: number | bigint): R; + /** + * Ensures that `value <= expected` for number or big integer values. + * + * **Usage** + * + * ```js + * const value = 42; + * expect(value).toBeLessThanOrEqual(42); + * ``` + * + * @param expected The value to compare to. + */ + toBeLessThanOrEqual(expected: number | bigint): R; + /** + * Ensures that value is `NaN`. + * + * **Usage** + * + * ```js + * const value = NaN; + * expect(value).toBeNaN(); + * ``` + * + */ + toBeNaN(): R; + /** + * Ensures that value is `null`. + * + * **Usage** + * + * ```js + * const value = null; + * expect(value).toBeNull(); + * ``` + * + */ + toBeNull(): R; + /** + * Ensures that value is true in a boolean context, **anything but** `false`, `0`, `''`, `null`, `undefined` or `NaN`. + * Use this method when you don't care about the specific value. + * + * **Usage** + * + * ```js + * const value = { example: 'value' }; + * expect(value).toBeTruthy(); + * ``` + * + */ + toBeTruthy(): R; + /** + * Ensures that value is `undefined`. + * + * **Usage** + * + * ```js + * const value = undefined; + * expect(value).toBeUndefined(); + * ``` + * + */ + toBeUndefined(): R; + /** + * Ensures that string value contains an expected substring. Comparison is case-sensitive. + * + * **Usage** + * + * ```js + * const value = 'Hello, World'; + * expect(value).toContain('World'); + * expect(value).toContain(','); + * ``` + * + * @param expected Expected substring. + */ + toContain(expected: string): R; + /** + * Ensures that value is an `Array` or `Set` and contains an expected item. + * + * **Usage** + * + * ```js + * const value = [1, 2, 3]; + * expect(value).toContain(2); + * expect(new Set(value)).toContain(2); + * ``` + * + * @param expected Expected value in the collection. + */ + toContain(expected: unknown): R; + /** + * Ensures that value is an `Array` or `Set` and contains an item equal to the expected. + * + * For objects, this method recursively checks equality of all fields, rather than comparing objects by reference as + * performed by + * [genericAssertions.toContain(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-contain-2). + * + * For primitive values, this method is equivalent to + * [genericAssertions.toContain(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-contain-2). + * + * **Usage** + * + * ```js + * const value = [ + * { example: 1 }, + * { another: 2 }, + * { more: 3 }, + * ]; + * expect(value).toContainEqual({ another: 2 }); + * expect(new Set(value)).toContainEqual({ another: 2 }); + * ``` + * + * @param expected Expected value in the collection. + */ + toContainEqual(expected: unknown): R; + /** + * Compares contents of the value with contents of `expected`, performing "deep equality" check. + * + * For objects, this method recursively checks equality of all fields, rather than comparing objects by reference as + * performed by + * [genericAssertions.toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be). + * + * For primitive values, this method is equivalent to + * [genericAssertions.toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be). + * + * **Usage** + * + * ```js + * const value = { prop: 1 }; + * expect(value).toEqual({ prop: 1 }); + * ``` + * + * @param expected Expected value. + */ + toEqual(expected: unknown): R; + /** + * Ensures that value has a `.length` property equal to `expected`. Useful for arrays and strings. + * + * **Usage** + * + * ```js + * expect('Hello, World').toHaveLength(12); + * expect([1, 2, 3]).toHaveLength(3); + * ``` + * + * @param expected Expected length. + */ + toHaveLength(expected: number): R; + /** + * Ensures that property at provided `keyPath` exists on the object and optionally checks that property is equal to + * the `expected`. Equality is checked recursively, similarly to + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal). + * + * **Usage** + * + * ```js + * const value = { + * a: { + * b: [42], + * }, + * c: true, + * }; + * expect(value).toHaveProperty('a.b'); + * expect(value).toHaveProperty('a.b', [42]); + * expect(value).toHaveProperty('a.b[0]', 42); + * expect(value).toHaveProperty('c'); + * expect(value).toHaveProperty('c', true); + * ``` + * + * @param keyPath Path to the property. Use dot notation `a.b` to check nested properties and indexed `a[2]` notation to check nested + * array items. + * @param expected Optional expected value to compare the property to. + */ + toHaveProperty(keyPath: string | Array, value?: unknown): R; + /** + * Ensures that string value matches a regular expression. + * + * **Usage** + * + * ```js + * const value = 'Is 42 enough?'; + * expect(value).toMatches(/Is \d+ enough/); + * ``` + * + * @param expected Regular expression to match against. + */ + toMatch(expected: RegExp): R; + /** + * Compares contents of the value with contents of `expected`, performing "deep equality" check. Allows extra + * properties to be present in the value, unlike + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal), + * so you can check just a subset of object properties. + * + * When comparing arrays, the number of items must match, and each item is checked recursively. + * + * **Usage** + * + * ```js + * const value = { + * a: 1, + * b: 2, + * c: true, + * }; + * expect(value).toMatchObject({ a: 1, c: true }); + * expect(value).toMatchObject({ b: 2, c: true }); + * + * expect([{ a: 1, b: 2 }]).toMatchObject([{ a: 1 }]); + * ``` + * + * @param expected The expected object value to match against. + */ + toMatchObject(expected: Record | Array): R; + /** + * Compares contents of the value with contents of `expected` **and** their types. + * + * Differences from + * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal): + * - Keys with undefined properties are checked. For example, `{ a: undefined, b: 2 }` does not match `{ b: 2 }`. + * - Array sparseness is checked. For example, `[, 1]` does not match `[undefined, 1]`. + * - Object types are checked to be equal. For example, a class instance with fields `a` and `b` will not equal a + * literal object with fields `a` and `b`. + * + * **Usage** + * + * ```js + * const value = { prop: 1 }; + * expect(value).toStrictEqual({ prop: 1 }); + * ``` + * + * @param expected Expected value. + */ + toStrictEqual(expected: unknown): R; + /** + * Calls the function and ensures it throws an error. + * + * Optionally compares the error with `expected`. Allowed expected values: + * - Regular expression - error message should **match** the pattern. + * - String - error message should **include** the substring. + * - Error object - error message should be **equal to** the message property of the object. + * - Error class - error object should be an **instance of** the class. + * + * **Usage** + * + * ```js + * expect(() => { + * throw new Error('Something bad'); + * }).toThrow(); + * + * expect(() => { + * throw new Error('Something bad'); + * }).toThrow(/something/); + * + * expect(() => { + * throw new Error('Something bad'); + * }).toThrow(Error); + * ``` + * + * @param expected Expected error message or error object. + */ + toThrow(error?: unknown): R; + /** + * An alias for + * [genericAssertions.toThrow([expected])](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-throw). + * + * **Usage** + * + * ```js + * expect(() => { + * throw new Error('Something bad'); + * }).toThrowError(); + * ``` + * + * @param expected Expected error message or error object. + */ + toThrowError(error?: unknown): R; +} + +type BaseMatchers = GenericAssertions & PlaywrightTest.Matchers; type MakeMatchers = BaseMatchers & { /** diff --git a/tests/playwright-test/expect.spec.ts b/tests/playwright-test/expect.spec.ts index 1802a08eb5..a86be8af53 100644 --- a/tests/playwright-test/expect.spec.ts +++ b/tests/playwright-test/expect.spec.ts @@ -133,16 +133,86 @@ test('should work with default expect prototype functions', async ({ runTSC, run } }); -test('should work with default expect matchers', async ({ runTSC }) => { +test('should work with generic matchers', async ({ runTSC }) => { const result = await runTSC({ 'a.spec.ts': ` - const { test } = pwt; - test.expect(42).toBe(42); + expect(42).toBe(42); + expect(0.1 + 0.2).toBeCloseTo(0.3, 5); + expect(null).toBeDefined(); + expect(null).toBeFalsy(); + expect(42).toBeGreaterThan(1); + expect(42).toBeGreaterThanOrEqual(42); + expect({}).toBeInstanceOf(Object); + expect(42).toBeLessThan(100); + expect(42).toBeLessThanOrEqual(42); + expect(null).toBeNull(); + expect(42).toBeTruthy(); + expect(undefined).toBeUndefined(); + expect(NaN).toBeNaN(); + expect('abc').toContain('a'); + expect(['abc']).toContain('abc'); + expect(['abc']).toContainEqual('abc'); + expect({}).toEqual({}); + expect([1, 2]).toHaveLength(2); + expect('abc').toMatch(/a.?c/); + expect({ a: 1, b: 2 }).toMatchObject({ a: 1 }); + expect({}).toStrictEqual({}); + expect(() => { throw new Error('Something bad'); }).toThrow('something'); + expect(() => { throw new Error('Something bad'); }).toThrowError('something'); ` }); expect(result.exitCode).toBe(0); }); +test('should compile generic matchers', async ({ runTSC }) => { + const result = await runTSC({ + 'a.spec.ts': ` + expect(42).toBe(42); + expect(42).toBeCloseTo(42); + expect(42).toBeCloseTo(42, 5); + expect(42).toBeDefined(); + expect(42).toBeFalsy(); + expect(42).toBeGreaterThan(1); + expect(42n).toBeGreaterThan(1n); + expect(42).toBeGreaterThanOrEqual(1); + expect(42n).toBeGreaterThanOrEqual(1n); + expect({}).toBeInstanceOf(Object); + expect(42).toBeLessThan(1); + expect(42n).toBeLessThan(1n); + expect(42).toBeLessThanOrEqual(1); + expect(42n).toBeLessThanOrEqual(1n); + expect(42).toBeNull(); + expect(42).toBeTruthy(); + expect(42).toBeUndefined(); + expect(42).toBeNaN(); + expect('abc').toContain('b'); + expect([1, 2]).toContain(1); + expect(new Set([1, 2])).toContain(1); + expect([{}, { a: 1 }]).toContainEqual({}); + expect({}).toEqual({}); + expect([1, 2]).toHaveLength(2); + expect('abc').toMatch(/a.?c/); + expect({ a: 1, b: 2 }).toMatchObject({ a: 1 }); + expect([]).toMatchObject([]); + expect({}).toStrictEqual({}); + expect(() => { throw new Error('Something bad'); }).toThrow('something'); + expect(() => { throw new Error('Something bad'); }).toThrow(); + expect(() => { throw new Error('Something bad'); }).toThrowError('something'); + expect(() => { throw new Error('Something bad'); }).toThrowError(); + + // @ts-expect-error + expect(42).toBe(123, 456); + // @ts-expect-error + expect(42).toBeCloseTo(42, '5'); + // @ts-expect-error + expect(42).toBeFalsy(123); + // @ts-expect-error + expect({}).toBeInstanceOf({}); + `, + }); + expect(result.exitCode).toBe(0); +}); + test('should work with expect message', async ({ runTSC }) => { const result = await runTSC({ 'a.spec.ts': ` diff --git a/utils/doclint/missingDocs.js b/utils/doclint/missingDocs.js index 7ea77b3afd..1baad4360e 100644 --- a/utils/doclint/missingDocs.js +++ b/utils/doclint/missingDocs.js @@ -22,7 +22,7 @@ const path = require('path'); /** @typedef {import('../../markdown').MarkdownNode} MarkdownNode */ -const IGNORE_CLASSES = ['PlaywrightAssertions', 'LocatorAssertions', 'PageAssertions', 'APIResponseAssertions', 'SnapshotAssertions']; +const IGNORE_CLASSES = ['PlaywrightAssertions', 'GenericAssertions', 'LocatorAssertions', 'PageAssertions', 'APIResponseAssertions', 'SnapshotAssertions']; module.exports = function lint(documentation, jsSources, apiFileName) { const errors = []; diff --git a/utils/generate_types/index.js b/utils/generate_types/index.js index 3104e2a49f..f326d0f898 100644 --- a/utils/generate_types/index.js +++ b/utils/generate_types/index.js @@ -521,7 +521,7 @@ class TypesGenerator { const coreDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'api')); const testDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-api'), path.join(PROJECT_DIR, 'docs', 'src', 'api', 'params.md')); const reporterDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-reporter-api')); - const assertionClasses = new Set(['LocatorAssertions', 'PageAssertions', 'APIResponseAssertions', 'SnapshotAssertions', 'PlaywrightAssertions']); + const assertionClasses = new Set(['GenericAssertions', 'LocatorAssertions', 'PageAssertions', 'APIResponseAssertions', 'SnapshotAssertions', 'PlaywrightAssertions']); /** * @param {boolean} includeExperimental diff --git a/utils/generate_types/overrides-test.d.ts b/utils/generate_types/overrides-test.d.ts index 756728c30f..ef765b698b 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -286,7 +286,35 @@ type Inverse = { type IfAny = 0 extends (1 & T) ? Y : N; type ExtraMatchers = T extends Type ? Matchers : IfAny; -type BaseMatchers = expectType.Matchers & PlaywrightTest.Matchers; +interface GenericAssertions { + not: GenericAssertions; + toBe(expected: unknown): R; + toBeCloseTo(expected: number, numDigits?: number): R; + toBeDefined(): R; + toBeFalsy(): R; + toBeGreaterThan(expected: number | bigint): R; + toBeGreaterThanOrEqual(expected: number | bigint): R; + toBeInstanceOf(expected: Function): R; + toBeLessThan(expected: number | bigint): R; + toBeLessThanOrEqual(expected: number | bigint): R; + toBeNaN(): R; + toBeNull(): R; + toBeTruthy(): R; + toBeUndefined(): R; + toContain(expected: string): R; + toContain(expected: unknown): R; + toContainEqual(expected: unknown): R; + toEqual(expected: unknown): R; + toHaveLength(expected: number): R; + toHaveProperty(keyPath: string | Array, value?: unknown): R; + toMatch(expected: RegExp): R; + toMatchObject(expected: Record | Array): R; + toStrictEqual(expected: unknown): R; + toThrow(error?: unknown): R; + toThrowError(error?: unknown): R; +} + +type BaseMatchers = GenericAssertions & PlaywrightTest.Matchers; type MakeMatchers = BaseMatchers & { /**