aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/@vitest/expect
diff options
context:
space:
mode:
Diffstat (limited to 'vanilla/node_modules/@vitest/expect')
-rw-r--r--vanilla/node_modules/@vitest/expect/LICENSE21
-rw-r--r--vanilla/node_modules/@vitest/expect/README.md21
-rw-r--r--vanilla/node_modules/@vitest/expect/dist/index.d.ts806
-rw-r--r--vanilla/node_modules/@vitest/expect/dist/index.js1875
-rw-r--r--vanilla/node_modules/@vitest/expect/package.json46
5 files changed, 2769 insertions, 0 deletions
diff --git a/vanilla/node_modules/@vitest/expect/LICENSE b/vanilla/node_modules/@vitest/expect/LICENSE
new file mode 100644
index 0000000..0e5771d
--- /dev/null
+++ b/vanilla/node_modules/@vitest/expect/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021-Present VoidZero Inc. and Vitest contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vanilla/node_modules/@vitest/expect/README.md b/vanilla/node_modules/@vitest/expect/README.md
new file mode 100644
index 0000000..4d7143b
--- /dev/null
+++ b/vanilla/node_modules/@vitest/expect/README.md
@@ -0,0 +1,21 @@
+# @vitest/expect
+
+Jest's expect matchers as a Chai plugin.
+
+## Usage
+
+```js
+import {
+ JestAsymmetricMatchers,
+ JestChaiExpect,
+ JestExtend,
+} from '@vitest/expect'
+import * as chai from 'chai'
+
+// allows using expect.extend instead of chai.use to extend plugins
+chai.use(JestExtend)
+// adds all jest matchers to expect
+chai.use(JestChaiExpect)
+// adds asymmetric matchers like stringContaining, objectContaining
+chai.use(JestAsymmetricMatchers)
+```
diff --git a/vanilla/node_modules/@vitest/expect/dist/index.d.ts b/vanilla/node_modules/@vitest/expect/dist/index.d.ts
new file mode 100644
index 0000000..a296d58
--- /dev/null
+++ b/vanilla/node_modules/@vitest/expect/dist/index.d.ts
@@ -0,0 +1,806 @@
+import { Test } from '@vitest/runner';
+import { MockInstance } from '@vitest/spy';
+import { Constructable } from '@vitest/utils';
+import { Formatter } from 'tinyrainbow';
+import { StandardSchemaV1 } from '@standard-schema/spec';
+import { diff, printDiffOrStringify } from '@vitest/utils/diff';
+export { DiffOptions } from '@vitest/utils/diff';
+import { stringify } from '@vitest/utils/display';
+import * as chai from 'chai';
+export { chai };
+
+declare const MATCHERS_OBJECT: unique symbol;
+declare const JEST_MATCHERS_OBJECT: unique symbol;
+declare const GLOBAL_EXPECT: unique symbol;
+declare const ASYMMETRIC_MATCHERS_OBJECT: unique symbol;
+
+interface AsymmetricMatcherInterface {
+ asymmetricMatch: (other: unknown, customTesters?: Array<Tester>) => boolean;
+ toString: () => string;
+ getExpectedType?: () => string;
+ toAsymmetricMatcher?: () => string;
+}
+declare abstract class AsymmetricMatcher<
+ T,
+ State extends MatcherState = MatcherState
+> implements AsymmetricMatcherInterface {
+ protected sample: T;
+ protected inverse: boolean;
+ $$typeof: symbol;
+ constructor(sample: T, inverse?: boolean);
+ protected getMatcherContext(expect?: Chai.ExpectStatic): State;
+ abstract asymmetricMatch(other: unknown, customTesters?: Array<Tester>): boolean;
+ abstract toString(): string;
+ getExpectedType?(): string;
+ toAsymmetricMatcher?(): string;
+}
+declare class StringContaining extends AsymmetricMatcher<string> {
+ constructor(sample: string, inverse?: boolean);
+ asymmetricMatch(other: string): boolean;
+ toString(): string;
+ getExpectedType(): string;
+}
+declare class Anything extends AsymmetricMatcher<void> {
+ asymmetricMatch(other: unknown): boolean;
+ toString(): string;
+ toAsymmetricMatcher(): string;
+}
+declare class ObjectContaining extends AsymmetricMatcher<Record<string | symbol | number, unknown>> {
+ constructor(sample: Record<string, unknown>, inverse?: boolean);
+ getPrototype(obj: object): any;
+ hasProperty(obj: object | null, property: string | symbol): boolean;
+ getProperties(obj: object): (string | symbol)[];
+ asymmetricMatch(other: any, customTesters?: Array<Tester>): boolean;
+ toString(): string;
+ getExpectedType(): string;
+}
+declare class ArrayContaining<T = unknown> extends AsymmetricMatcher<Array<T>> {
+ constructor(sample: Array<T>, inverse?: boolean);
+ asymmetricMatch(other: Array<T>, customTesters?: Array<Tester>): boolean;
+ toString(): string;
+ getExpectedType(): string;
+}
+declare class Any extends AsymmetricMatcher<any> {
+ constructor(sample: unknown);
+ fnNameFor(func: Function): string;
+ asymmetricMatch(other: unknown): boolean;
+ toString(): string;
+ getExpectedType(): string;
+ toAsymmetricMatcher(): string;
+}
+declare class StringMatching extends AsymmetricMatcher<RegExp> {
+ constructor(sample: string | RegExp, inverse?: boolean);
+ asymmetricMatch(other: string): boolean;
+ toString(): string;
+ getExpectedType(): string;
+}
+declare class SchemaMatching extends AsymmetricMatcher<StandardSchemaV1<unknown, unknown>> {
+ private result;
+ constructor(sample: StandardSchemaV1<unknown, unknown>, inverse?: boolean);
+ asymmetricMatch(other: unknown): boolean;
+ toString(): string;
+ getExpectedType(): string;
+ toAsymmetricMatcher(): string;
+}
+declare const JestAsymmetricMatchers: ChaiPlugin;
+
+declare function matcherHint(matcherName: string, received?: string, expected?: string, options?: MatcherHintOptions): string;
+declare function printReceived(object: unknown): string;
+declare function printExpected(value: unknown): string;
+declare function getMatcherUtils(): {
+ EXPECTED_COLOR: Formatter;
+ RECEIVED_COLOR: Formatter;
+ INVERTED_COLOR: Formatter;
+ BOLD_WEIGHT: Formatter;
+ DIM_COLOR: Formatter;
+ diff: typeof diff;
+ matcherHint: typeof matcherHint;
+ printReceived: typeof printReceived;
+ printExpected: typeof printExpected;
+ printDiffOrStringify: typeof printDiffOrStringify;
+ printWithType: typeof printWithType;
+};
+declare function printWithType<T>(name: string, value: T, print: (value: T) => string): string;
+declare function addCustomEqualityTesters(newTesters: Array<Tester>): void;
+
+/**
+* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*
+*/
+
+type ChaiPlugin = Chai.ChaiPlugin;
+type Tester = (this: TesterContext, a: any, b: any, customTesters: Array<Tester>) => boolean | undefined;
+interface TesterContext {
+ equals: (a: unknown, b: unknown, customTesters?: Array<Tester>, strictCheck?: boolean) => boolean;
+}
+
+interface MatcherHintOptions {
+ comment?: string;
+ expectedColor?: Formatter;
+ isDirectExpectCall?: boolean;
+ isNot?: boolean;
+ promise?: string;
+ receivedColor?: Formatter;
+ secondArgument?: string;
+ secondArgumentColor?: Formatter;
+}
+interface MatcherState {
+ customTesters: Array<Tester>;
+ assertionCalls: number;
+ currentTestName?: string;
+ dontThrow?: () => void;
+ error?: Error;
+ equals: (a: unknown, b: unknown, customTesters?: Array<Tester>, strictCheck?: boolean) => boolean;
+ expand?: boolean;
+ expectedAssertionsNumber?: number | null;
+ expectedAssertionsNumberErrorGen?: (() => Error) | null;
+ isExpectingAssertions?: boolean;
+ isExpectingAssertionsError?: Error | null;
+ isNot: boolean;
+ promise: string;
+ suppressedErrors: Array<Error>;
+ testPath?: string;
+ utils: ReturnType<typeof getMatcherUtils> & {
+ diff: typeof diff;
+ stringify: typeof stringify;
+ iterableEquality: Tester;
+ subsetEquality: Tester;
+ };
+ soft?: boolean;
+ poll?: boolean;
+ task?: Readonly<Test>;
+}
+interface SyncExpectationResult {
+ pass: boolean;
+ message: () => string;
+ actual?: any;
+ expected?: any;
+}
+type AsyncExpectationResult = Promise<SyncExpectationResult>;
+type ExpectationResult = SyncExpectationResult | AsyncExpectationResult;
+interface RawMatcherFn<
+ T extends MatcherState = MatcherState,
+ E extends Array<any> = Array<any>
+> {
+ (this: T, received: any, ...expected: E): ExpectationResult;
+}
+interface Matchers<T = any> {}
+type MatchersObject<T extends MatcherState = MatcherState> = Record<string, RawMatcherFn<T>> & ThisType<T> & { [K in keyof Matchers<T>]? : RawMatcherFn<T, Parameters<Matchers<T>[K]>> };
+interface ExpectStatic extends Chai.ExpectStatic, Matchers, AsymmetricMatchersContaining {
+ <T>(actual: T, message?: string): Assertion<T>;
+ extend: (expects: MatchersObject) => void;
+ anything: () => any;
+ any: (constructor: unknown) => any;
+ getState: () => MatcherState;
+ setState: (state: Partial<MatcherState>) => void;
+ not: AsymmetricMatchersContaining;
+}
+interface CustomMatcher {
+ /**
+ * Checks that a value satisfies a custom matcher function.
+ *
+ * @param matcher - A function returning a boolean based on the custom condition
+ * @param message - Optional custom error message on failure
+ *
+ * @example
+ * expect(age).toSatisfy(val => val >= 18, 'Age must be at least 18');
+ * expect(age).toEqual(expect.toSatisfy(val => val >= 18, 'Age must be at least 18'));
+ */
+ toSatisfy: (matcher: (value: any) => boolean, message?: string) => any;
+ /**
+ * Matches if the received value is one of the values in the expected array or set.
+ *
+ * @example
+ * expect(1).toBeOneOf([1, 2, 3])
+ * expect('foo').toBeOneOf([expect.any(String)])
+ * expect({ a: 1 }).toEqual({ a: expect.toBeOneOf(['1', '2', '3']) })
+ */
+ toBeOneOf: <T>(sample: Array<T> | Set<T>) => any;
+}
+interface AsymmetricMatchersContaining extends CustomMatcher {
+ /**
+ * Matches if the received string contains the expected substring.
+ *
+ * @example
+ * expect('I have an apple').toEqual(expect.stringContaining('apple'));
+ * expect({ a: 'test string' }).toEqual({ a: expect.stringContaining('test') });
+ */
+ stringContaining: (expected: string) => any;
+ /**
+ * Matches if the received object contains all properties of the expected object.
+ *
+ * @example
+ * expect({ a: '1', b: 2 }).toEqual(expect.objectContaining({ a: '1' }))
+ */
+ objectContaining: <T = any>(expected: DeeplyAllowMatchers<T>) => any;
+ /**
+ * Matches if the received array contains all elements in the expected array.
+ *
+ * @example
+ * expect(['a', 'b', 'c']).toEqual(expect.arrayContaining(['b', 'a']));
+ */
+ arrayContaining: <T = unknown>(expected: Array<DeeplyAllowMatchers<T>>) => any;
+ /**
+ * Matches if the received string or regex matches the expected pattern.
+ *
+ * @example
+ * expect('hello world').toEqual(expect.stringMatching(/^hello/));
+ * expect('hello world').toEqual(expect.stringMatching('hello'));
+ */
+ stringMatching: (expected: string | RegExp) => any;
+ /**
+ * Matches if the received number is within a certain precision of the expected number.
+ *
+ * @param precision - Optional decimal precision for comparison. Default is 2.
+ *
+ * @example
+ * expect(10.45).toEqual(expect.closeTo(10.5, 1));
+ * expect(5.11).toEqual(expect.closeTo(5.12)); // with default precision
+ */
+ closeTo: (expected: number, precision?: number) => any;
+ /**
+ * Matches if the received value validates against a Standard Schema.
+ *
+ * @param schema - A Standard Schema V1 compatible schema object
+ *
+ * @example
+ * expect(user).toEqual(expect.schemaMatching(z.object({ name: z.string() })))
+ * expect(['hello', 'world']).toEqual([expect.schemaMatching(z.string()), expect.schemaMatching(z.string())])
+ */
+ schemaMatching: (schema: unknown) => any;
+}
+type WithAsymmetricMatcher<T> = T | AsymmetricMatcher<unknown>;
+type DeeplyAllowMatchers<T> = T extends Array<infer Element> ? WithAsymmetricMatcher<T> | DeeplyAllowMatchers<Element>[] : T extends object ? WithAsymmetricMatcher<T> | { [K in keyof T] : DeeplyAllowMatchers<T[K]> } : WithAsymmetricMatcher<T>;
+interface JestAssertion<T = any> extends jest.Matchers<void, T>, CustomMatcher {
+ /**
+ * 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.
+ *
+ * @example
+ * expect(user).toEqual({ name: 'Alice', age: 30 });
+ */
+ toEqual: <E>(expected: E) => void;
+ /**
+ * Use to test that objects have the same types as well as structure.
+ *
+ * @example
+ * expect(user).toStrictEqual({ name: 'Alice', age: 30 });
+ */
+ toStrictEqual: <E>(expected: E) => void;
+ /**
+ * Checks that a value is what you expect. It calls `Object.is` to compare values.
+ * Don't use `toBe` with floating-point numbers.
+ *
+ * @example
+ * expect(result).toBe(42);
+ * expect(status).toBe(true);
+ */
+ toBe: <E>(expected: E) => void;
+ /**
+ * Check that a string matches a regular expression.
+ *
+ * @example
+ * expect(message).toMatch(/hello/);
+ * expect(greeting).toMatch('world');
+ */
+ toMatch: (expected: string | RegExp) => void;
+ /**
+ * Used to check that a JavaScript object matches a subset of the properties of an object
+ *
+ * @example
+ * expect(user).toMatchObject({
+ * name: 'Alice',
+ * address: { city: 'Wonderland' }
+ * });
+ */
+ toMatchObject: <E extends object | any[]>(expected: E) => void;
+ /**
+ * 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.
+ *
+ * @example
+ * expect(items).toContain('apple');
+ * expect(numbers).toContain(5);
+ */
+ toContain: <E>(item: E) => void;
+ /**
+ * 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.
+ *
+ * @example
+ * expect(items).toContainEqual({ name: 'apple', quantity: 1 });
+ */
+ toContainEqual: <E>(item: E) => void;
+ /**
+ * 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.
+ *
+ * @example
+ * expect(user.isActive).toBeTruthy();
+ */
+ toBeTruthy: () => void;
+ /**
+ * When you don't care what a value is, you just want to
+ * ensure a value is false in a boolean context.
+ *
+ * @example
+ * expect(user.isActive).toBeFalsy();
+ */
+ toBeFalsy: () => void;
+ /**
+ * For comparing floating point numbers.
+ *
+ * @example
+ * expect(score).toBeGreaterThan(10);
+ */
+ toBeGreaterThan: (num: number | bigint) => void;
+ /**
+ * For comparing floating point numbers.
+ *
+ * @example
+ * expect(score).toBeGreaterThanOrEqual(10);
+ */
+ toBeGreaterThanOrEqual: (num: number | bigint) => void;
+ /**
+ * For comparing floating point numbers.
+ *
+ * @example
+ * expect(score).toBeLessThan(10);
+ */
+ toBeLessThan: (num: number | bigint) => void;
+ /**
+ * For comparing floating point numbers.
+ *
+ * @example
+ * expect(score).toBeLessThanOrEqual(10);
+ */
+ toBeLessThanOrEqual: (num: number | bigint) => void;
+ /**
+ * Used to check that a variable is NaN.
+ *
+ * @example
+ * expect(value).toBeNaN();
+ */
+ toBeNaN: () => void;
+ /**
+ * Used to check that a variable is undefined.
+ *
+ * @example
+ * expect(value).toBeUndefined();
+ */
+ toBeUndefined: () => void;
+ /**
+ * 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.
+ *
+ * @example
+ * expect(value).toBeNull();
+ */
+ toBeNull: () => void;
+ /**
+ * Used to check that a variable is nullable (null or undefined).
+ *
+ * @example
+ * expect(value).toBeNullable();
+ */
+ toBeNullable: () => void;
+ /**
+ * Ensure that a variable is not undefined.
+ *
+ * @example
+ * expect(value).toBeDefined();
+ */
+ toBeDefined: () => void;
+ /**
+ * Ensure that an object is an instance of a class.
+ * This matcher uses `instanceof` underneath.
+ *
+ * @example
+ * expect(new Date()).toBeInstanceOf(Date);
+ */
+ toBeInstanceOf: <E>(expected: E) => void;
+ /**
+ * Used to check that an object has a `.length` property
+ * and it is set to a certain numeric value.
+ *
+ * @example
+ * expect([1, 2, 3]).toHaveLength(3);
+ * expect('hello').toHaveLength(5);
+ */
+ toHaveLength: (length: number) => void;
+ /**
+ * Use to check if a property at the specified path exists on an object.
+ * For checking deeply nested properties, you may use dot notation or an array containing
+ * the path segments for deep references.
+ *
+ * Optionally, you can provide a value to check if it matches the value present at the path
+ * on the target object. This matcher uses 'deep equality' (like `toEqual()`) and recursively checks
+ * the equality of all fields.
+ *
+ * @example
+ * expect(user).toHaveProperty('address.city', 'New York');
+ * expect(config).toHaveProperty(['settings', 'theme'], 'dark');
+ */
+ toHaveProperty: <E>(property: string | (string | number)[], value?: E) => void;
+ /**
+ * Using exact equality with floating point numbers is a bad idea.
+ * Rounding means that intuitive things fail.
+ * The default for `numDigits` is 2.
+ *
+ * @example
+ * expect(price).toBeCloseTo(9.99, 2);
+ */
+ toBeCloseTo: (number: number, numDigits?: number) => void;
+ /**
+ * Ensures that a mock function is called an exact number of times.
+ *
+ * Also under the alias `expect.toBeCalledTimes`.
+ *
+ * @example
+ * expect(mockFunc).toHaveBeenCalledTimes(2);
+ */
+ toHaveBeenCalledTimes: (times: number) => void;
+ /**
+ * Ensures that a mock function is called an exact number of times.
+ *
+ * Alias for `expect.toHaveBeenCalledTimes`.
+ *
+ * @example
+ * expect(mockFunc).toBeCalledTimes(2);
+ */
+ toBeCalledTimes: (times: number) => void;
+ /**
+ * Ensures that a mock function is called.
+ *
+ * Also under the alias `expect.toBeCalled`.
+ *
+ * @example
+ * expect(mockFunc).toHaveBeenCalled();
+ */
+ toHaveBeenCalled: () => void;
+ /**
+ * Ensures that a mock function is called.
+ *
+ * Alias for `expect.toHaveBeenCalled`.
+ *
+ * @example
+ * expect(mockFunc).toBeCalled();
+ */
+ toBeCalled: () => void;
+ /**
+ * Ensure that a mock function is called with specific arguments.
+ *
+ * Also under the alias `expect.toBeCalledWith`.
+ *
+ * @example
+ * expect(mockFunc).toHaveBeenCalledWith('arg1', 42);
+ */
+ toHaveBeenCalledWith: <E extends any[]>(...args: E) => void;
+ /**
+ * Ensure that a mock function is called with specific arguments.
+ *
+ * Alias for `expect.toHaveBeenCalledWith`.
+ *
+ * @example
+ * expect(mockFunc).toBeCalledWith('arg1', 42);
+ */
+ toBeCalledWith: <E extends any[]>(...args: E) => void;
+ /**
+ * Ensure that a mock function is called with specific arguments on an Nth call.
+ *
+ * Also under the alias `expect.nthCalledWith`.
+ *
+ * @example
+ * expect(mockFunc).toHaveBeenNthCalledWith(2, 'secondArg');
+ */
+ toHaveBeenNthCalledWith: <E extends any[]>(n: number, ...args: E) => void;
+ /**
+ * Ensure that a mock function is called with specific arguments on an Nth call.
+ *
+ * Alias for `expect.toHaveBeenNthCalledWith`.
+ *
+ * @example
+ * expect(mockFunc).nthCalledWith(2, 'secondArg');
+ */
+ nthCalledWith: <E extends any[]>(nthCall: number, ...args: E) => void;
+ /**
+ * If you have a mock function, you can use `.toHaveBeenLastCalledWith`
+ * to test what arguments it was last called with.
+ *
+ * Also under the alias `expect.lastCalledWith`.
+ *
+ * @example
+ * expect(mockFunc).toHaveBeenLastCalledWith('lastArg');
+ */
+ toHaveBeenLastCalledWith: <E extends any[]>(...args: E) => void;
+ /**
+ * If you have a mock function, you can use `.lastCalledWith`
+ * to test what arguments it was last called with.
+ *
+ * Alias for `expect.toHaveBeenLastCalledWith`.
+ *
+ * @example
+ * expect(mockFunc).lastCalledWith('lastArg');
+ */
+ lastCalledWith: <E extends any[]>(...args: E) => void;
+ /**
+ * Used to test that a function throws when it is called.
+ *
+ * Also under the alias `expect.toThrowError`.
+ *
+ * @example
+ * expect(() => functionWithError()).toThrow('Error message');
+ * expect(() => parseJSON('invalid')).toThrow(SyntaxError);
+ */
+ toThrow: (expected?: string | Constructable | RegExp | Error) => void;
+ /**
+ * Used to test that a function throws when it is called.
+ *
+ * Alias for `expect.toThrow`.
+ *
+ * @example
+ * expect(() => functionWithError()).toThrowError('Error message');
+ * expect(() => parseJSON('invalid')).toThrowError(SyntaxError);
+ */
+ toThrowError: (expected?: string | Constructable | RegExp | Error) => void;
+ /**
+ * Use to test that the mock function successfully returned (i.e., did not throw an error) at least one time
+ *
+ * Alias for `expect.toHaveReturned`.
+ *
+ * @example
+ * expect(mockFunc).toReturn();
+ */
+ toReturn: () => void;
+ /**
+ * Use to test that the mock function successfully returned (i.e., did not throw an error) at least one time
+ *
+ * Also under the alias `expect.toReturn`.
+ *
+ * @example
+ * expect(mockFunc).toHaveReturned();
+ */
+ toHaveReturned: () => void;
+ /**
+ * 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.
+ *
+ * Alias for `expect.toHaveReturnedTimes`.
+ *
+ * @example
+ * expect(mockFunc).toReturnTimes(3);
+ */
+ toReturnTimes: (times: number) => void;
+ /**
+ * 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.
+ *
+ * Also under the alias `expect.toReturnTimes`.
+ *
+ * @example
+ * expect(mockFunc).toHaveReturnedTimes(3);
+ */
+ toHaveReturnedTimes: (times: number) => void;
+ /**
+ * Use to ensure that a mock function returned a specific value.
+ *
+ * Alias for `expect.toHaveReturnedWith`.
+ *
+ * @example
+ * expect(mockFunc).toReturnWith('returnValue');
+ */
+ toReturnWith: <E>(value: E) => void;
+ /**
+ * Use to ensure that a mock function returned a specific value.
+ *
+ * Also under the alias `expect.toReturnWith`.
+ *
+ * @example
+ * expect(mockFunc).toHaveReturnedWith('returnValue');
+ */
+ toHaveReturnedWith: <E>(value: E) => void;
+ /**
+ * 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.
+ *
+ * Also under the alias `expect.lastReturnedWith`.
+ *
+ * @example
+ * expect(mockFunc).toHaveLastReturnedWith('lastValue');
+ */
+ toHaveLastReturnedWith: <E>(value: E) => void;
+ /**
+ * 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.
+ *
+ * Alias for `expect.toHaveLastReturnedWith`.
+ *
+ * @example
+ * expect(mockFunc).lastReturnedWith('lastValue');
+ */
+ lastReturnedWith: <E>(value: E) => void;
+ /**
+ * 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.
+ *
+ * Also under the alias `expect.nthReturnedWith`.
+ *
+ * @example
+ * expect(mockFunc).toHaveNthReturnedWith(2, 'nthValue');
+ */
+ toHaveNthReturnedWith: <E>(nthCall: number, value: E) => void;
+ /**
+ * 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.
+ *
+ * Alias for `expect.toHaveNthReturnedWith`.
+ *
+ * @example
+ * expect(mockFunc).nthReturnedWith(2, 'nthValue');
+ */
+ nthReturnedWith: <E>(nthCall: number, value: E) => void;
+}
+type VitestAssertion<
+ A,
+ T
+> = { [K in keyof A] : A[K] extends Chai.Assertion ? Assertion<T> : A[K] extends (...args: any[]) => any ? A[K] : VitestAssertion<A[K], T> } & ((type: string, message?: string) => Assertion);
+type Promisify<O> = { [K in keyof O] : O[K] extends (...args: infer A) => infer R ? Promisify<O[K]> & ((...args: A) => Promise<R>) : O[K] };
+type PromisifyAssertion<T> = Promisify<Assertion<T>>;
+interface Assertion<T = any> extends VitestAssertion<Chai.Assertion, T>, JestAssertion<T>, Matchers<T> {
+ /**
+ * Ensures a value is of a specific type.
+ *
+ * @example
+ * expect(value).toBeTypeOf('string');
+ * expect(number).toBeTypeOf('number');
+ */
+ toBeTypeOf: (expected: "bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined") => void;
+ /**
+ * Asserts that a mock function was called exactly once.
+ *
+ * @example
+ * expect(mockFunc).toHaveBeenCalledOnce();
+ */
+ toHaveBeenCalledOnce: () => void;
+ /**
+ * Ensure that a mock function is called with specific arguments and called
+ * exactly once.
+ *
+ * @example
+ * expect(mockFunc).toHaveBeenCalledExactlyOnceWith('arg1', 42);
+ */
+ toHaveBeenCalledExactlyOnceWith: <E extends any[]>(...args: E) => void;
+ /**
+ * This assertion checks if a `Mock` was called before another `Mock`.
+ * @param mock - A mock function created by `vi.spyOn` or `vi.fn`
+ * @param failIfNoFirstInvocation - Fail if the first mock was never called
+ * @example
+ * const mock1 = vi.fn()
+ * const mock2 = vi.fn()
+ *
+ * mock1()
+ * mock2()
+ * mock1()
+ *
+ * expect(mock1).toHaveBeenCalledBefore(mock2)
+ */
+ toHaveBeenCalledBefore: (mock: MockInstance, failIfNoFirstInvocation?: boolean) => void;
+ /**
+ * This assertion checks if a `Mock` was called after another `Mock`.
+ * @param mock - A mock function created by `vi.spyOn` or `vi.fn`
+ * @param failIfNoFirstInvocation - Fail if the first mock was never called
+ * @example
+ * const mock1 = vi.fn()
+ * const mock2 = vi.fn()
+ *
+ * mock2()
+ * mock1()
+ * mock2()
+ *
+ * expect(mock1).toHaveBeenCalledAfter(mock2)
+ */
+ toHaveBeenCalledAfter: (mock: MockInstance, failIfNoFirstInvocation?: boolean) => void;
+ /**
+ * Checks that a promise resolves successfully at least once.
+ *
+ * @example
+ * await expect(promise).toHaveResolved();
+ */
+ toHaveResolved: () => void;
+ /**
+ * Checks that a promise resolves to a specific value.
+ *
+ * @example
+ * await expect(promise).toHaveResolvedWith('success');
+ */
+ toHaveResolvedWith: <E>(value: E) => void;
+ /**
+ * Ensures a promise resolves a specific number of times.
+ *
+ * @example
+ * expect(mockAsyncFunc).toHaveResolvedTimes(3);
+ */
+ toHaveResolvedTimes: (times: number) => void;
+ /**
+ * Asserts that the last resolved value of a promise matches an expected value.
+ *
+ * @example
+ * await expect(mockAsyncFunc).toHaveLastResolvedWith('finalResult');
+ */
+ toHaveLastResolvedWith: <E>(value: E) => void;
+ /**
+ * Ensures a specific value was returned by a promise on the nth resolution.
+ *
+ * @example
+ * await expect(mockAsyncFunc).toHaveNthResolvedWith(2, 'secondResult');
+ */
+ toHaveNthResolvedWith: <E>(nthCall: number, value: E) => void;
+ /**
+ * Verifies that a promise resolves.
+ *
+ * @example
+ * await expect(someAsyncFunc).resolves.toBe(42);
+ */
+ resolves: PromisifyAssertion<T>;
+ /**
+ * Verifies that a promise rejects.
+ *
+ * @example
+ * await expect(someAsyncFunc).rejects.toThrow('error');
+ */
+ rejects: PromisifyAssertion<T>;
+}
+declare global {
+ namespace jest {
+ interface Matchers<
+ R,
+ T = {}
+ > {}
+ }
+}
+
+declare const customMatchers: MatchersObject;
+
+declare const JestChaiExpect: ChaiPlugin;
+
+declare const JestExtend: ChaiPlugin;
+
+declare function equals(a: unknown, b: unknown, customTesters?: Array<Tester>, strictCheck?: boolean): boolean;
+declare function isAsymmetric(obj: any): obj is AsymmetricMatcher<any>;
+declare function hasAsymmetric(obj: any, seen?: Set<any>): boolean;
+declare function isA(typeName: string, value: unknown): boolean;
+declare function fnNameFor(func: Function): string;
+declare function hasProperty(obj: object | null, property: string): boolean;
+declare function isImmutableUnorderedKeyed(maybeKeyed: any): boolean;
+declare function isImmutableUnorderedSet(maybeSet: any): boolean;
+declare function iterableEquality(a: any, b: any, customTesters?: Array<Tester>, aStack?: Array<any>, bStack?: Array<any>): boolean | undefined;
+declare function subsetEquality(object: unknown, subset: unknown, customTesters?: Array<Tester>): boolean | undefined;
+declare function typeEquality(a: any, b: any): boolean | undefined;
+declare function arrayBufferEquality(a: unknown, b: unknown): boolean | undefined;
+declare function sparseArrayEquality(a: unknown, b: unknown, customTesters?: Array<Tester>): boolean | undefined;
+declare function generateToBeMessage(deepEqualityName: string, expected?: string, actual?: string): string;
+declare function pluralize(word: string, count: number): string;
+declare function getObjectKeys(object: object): Array<string | symbol>;
+declare function getObjectSubset(object: any, subset: any, customTesters: Array<Tester>): {
+ subset: any;
+ stripped: number;
+};
+/**
+* Detects if an object is a Standard Schema V1 compatible schema
+*/
+declare function isStandardSchema(obj: any): obj is StandardSchemaV1;
+
+declare function getState<State extends MatcherState = MatcherState>(expect: ExpectStatic): State;
+declare function setState<State extends MatcherState = MatcherState>(state: Partial<State>, expect: ExpectStatic): void;
+
+export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, ObjectContaining, SchemaMatching, StringContaining, StringMatching, addCustomEqualityTesters, arrayBufferEquality, customMatchers, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, isStandardSchema, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
+export type { Assertion, AsymmetricMatcherInterface, AsymmetricMatchersContaining, AsyncExpectationResult, ChaiPlugin, DeeplyAllowMatchers, ExpectStatic, ExpectationResult, JestAssertion, MatcherHintOptions, MatcherState, Matchers, MatchersObject, PromisifyAssertion, RawMatcherFn, SyncExpectationResult, Tester, TesterContext };
diff --git a/vanilla/node_modules/@vitest/expect/dist/index.js b/vanilla/node_modules/@vitest/expect/dist/index.js
new file mode 100644
index 0000000..ec7e5f9
--- /dev/null
+++ b/vanilla/node_modules/@vitest/expect/dist/index.js
@@ -0,0 +1,1875 @@
+import { printDiffOrStringify, diff } from '@vitest/utils/diff';
+import { stringify } from '@vitest/utils/display';
+import { getType, isObject, noop, assertTypes } from '@vitest/utils/helpers';
+import c from 'tinyrainbow';
+import { isMockFunction } from '@vitest/spy';
+import { processError } from '@vitest/utils/error';
+import { use, util } from 'chai';
+import * as chai from 'chai';
+export { chai };
+
+const MATCHERS_OBJECT = Symbol.for("matchers-object");
+const JEST_MATCHERS_OBJECT = Symbol.for("$$jest-matchers-object");
+const GLOBAL_EXPECT = Symbol.for("expect-global");
+const ASYMMETRIC_MATCHERS_OBJECT = Symbol.for("asymmetric-matchers-object");
+
+// selectively ported from https://github.com/jest-community/jest-extended
+const customMatchers = {
+ toSatisfy(actual, expected, message) {
+ const { printReceived, printExpected, matcherHint } = this.utils;
+ const pass = expected(actual);
+ return {
+ pass,
+ message: () => pass ? `\
+${matcherHint(".not.toSatisfy", "received", "")}
+
+Expected value to not satisfy:
+${message || printExpected(expected)}
+Received:
+${printReceived(actual)}` : `\
+${matcherHint(".toSatisfy", "received", "")}
+
+Expected value to satisfy:
+${message || printExpected(expected)}
+
+Received:
+${printReceived(actual)}`
+ };
+ },
+ toBeOneOf(actual, expected) {
+ const { equals, customTesters } = this;
+ const { printReceived, printExpected, matcherHint } = this.utils;
+ let pass;
+ if (Array.isArray(expected)) {
+ pass = expected.length === 0 || expected.some((item) => equals(item, actual, customTesters));
+ } else if (expected instanceof Set) {
+ pass = expected.size === 0 || expected.has(actual) || [...expected].some((item) => equals(item, actual, customTesters));
+ } else {
+ throw new TypeError(`You must provide an array or set to ${matcherHint(".toBeOneOf")}, not '${typeof expected}'.`);
+ }
+ return {
+ pass,
+ message: () => pass ? `\
+${matcherHint(".not.toBeOneOf", "received", "")}
+
+Expected value to not be one of:
+${printExpected(expected)}
+Received:
+${printReceived(actual)}` : `\
+${matcherHint(".toBeOneOf", "received", "")}
+
+Expected value to be one of:
+${printExpected(expected)}
+
+Received:
+${printReceived(actual)}`
+ };
+ }
+};
+
+const EXPECTED_COLOR = c.green;
+const RECEIVED_COLOR = c.red;
+const INVERTED_COLOR = c.inverse;
+const BOLD_WEIGHT = c.bold;
+const DIM_COLOR = c.dim;
+function matcherHint(matcherName, received = "received", expected = "expected", options = {}) {
+ const { comment = "", isDirectExpectCall = false, isNot = false, promise = "", secondArgument = "", expectedColor = EXPECTED_COLOR, receivedColor = RECEIVED_COLOR, secondArgumentColor = EXPECTED_COLOR } = options;
+ let hint = "";
+ let dimString = "expect";
+ if (!isDirectExpectCall && received !== "") {
+ hint += DIM_COLOR(`${dimString}(`) + receivedColor(received);
+ dimString = ")";
+ }
+ if (promise !== "") {
+ hint += DIM_COLOR(`${dimString}.`) + promise;
+ dimString = "";
+ }
+ if (isNot) {
+ hint += `${DIM_COLOR(`${dimString}.`)}not`;
+ dimString = "";
+ }
+ if (matcherName.includes(".")) {
+ // Old format: for backward compatibility,
+ // especially without promise or isNot options
+ dimString += matcherName;
+ } else {
+ // New format: omit period from matcherName arg
+ hint += DIM_COLOR(`${dimString}.`) + matcherName;
+ dimString = "";
+ }
+ if (expected === "") {
+ dimString += "()";
+ } else {
+ hint += DIM_COLOR(`${dimString}(`) + expectedColor(expected);
+ if (secondArgument) {
+ hint += DIM_COLOR(", ") + secondArgumentColor(secondArgument);
+ }
+ dimString = ")";
+ }
+ if (comment !== "") {
+ dimString += ` // ${comment}`;
+ }
+ if (dimString !== "") {
+ hint += DIM_COLOR(dimString);
+ }
+ return hint;
+}
+const SPACE_SYMBOL = "·";
+// Instead of inverse highlight which now implies a change,
+// replace common spaces with middle dot at the end of any line.
+function replaceTrailingSpaces(text) {
+ return text.replace(/\s+$/gm, (spaces) => SPACE_SYMBOL.repeat(spaces.length));
+}
+function printReceived(object) {
+ return RECEIVED_COLOR(replaceTrailingSpaces(stringify(object)));
+}
+function printExpected(value) {
+ return EXPECTED_COLOR(replaceTrailingSpaces(stringify(value)));
+}
+function getMatcherUtils() {
+ return {
+ EXPECTED_COLOR,
+ RECEIVED_COLOR,
+ INVERTED_COLOR,
+ BOLD_WEIGHT,
+ DIM_COLOR,
+ diff,
+ matcherHint,
+ printReceived,
+ printExpected,
+ printDiffOrStringify,
+ printWithType
+ };
+}
+function printWithType(name, value, print) {
+ const type = getType(value);
+ const hasType = type !== "null" && type !== "undefined" ? `${name} has type: ${type}\n` : "";
+ const hasValue = `${name} has value: ${print(value)}`;
+ return hasType + hasValue;
+}
+function addCustomEqualityTesters(newTesters) {
+ if (!Array.isArray(newTesters)) {
+ throw new TypeError(`expect.customEqualityTesters: Must be set to an array of Testers. Was given "${getType(newTesters)}"`);
+ }
+ globalThis[JEST_MATCHERS_OBJECT].customEqualityTesters.push(...newTesters);
+}
+function getCustomEqualityTesters() {
+ return globalThis[JEST_MATCHERS_OBJECT].customEqualityTesters;
+}
+
+// Extracted out of jasmine 2.5.2
+function equals(a, b, customTesters, strictCheck) {
+ customTesters = customTesters || [];
+ return eq(a, b, [], [], customTesters, strictCheck ? hasKey : hasDefinedKey);
+}
+const functionToString = Function.prototype.toString;
+function isAsymmetric(obj) {
+ return !!obj && typeof obj === "object" && "asymmetricMatch" in obj && isA("Function", obj.asymmetricMatch);
+}
+function hasAsymmetric(obj, seen = new Set()) {
+ if (seen.has(obj)) {
+ return false;
+ }
+ seen.add(obj);
+ if (isAsymmetric(obj)) {
+ return true;
+ }
+ if (Array.isArray(obj)) {
+ return obj.some((i) => hasAsymmetric(i, seen));
+ }
+ if (obj instanceof Set) {
+ return Array.from(obj).some((i) => hasAsymmetric(i, seen));
+ }
+ if (isObject(obj)) {
+ return Object.values(obj).some((v) => hasAsymmetric(v, seen));
+ }
+ return false;
+}
+function asymmetricMatch(a, b, customTesters) {
+ const asymmetricA = isAsymmetric(a);
+ const asymmetricB = isAsymmetric(b);
+ if (asymmetricA && asymmetricB) {
+ return undefined;
+ }
+ if (asymmetricA) {
+ return a.asymmetricMatch(b, customTesters);
+ }
+ if (asymmetricB) {
+ return b.asymmetricMatch(a, customTesters);
+ }
+}
+// Equality function lovingly adapted from isEqual in
+// [Underscore](http://underscorejs.org)
+function eq(a, b, aStack, bStack, customTesters, hasKey) {
+ let result = true;
+ const asymmetricResult = asymmetricMatch(a, b, customTesters);
+ if (asymmetricResult !== undefined) {
+ return asymmetricResult;
+ }
+ const testerContext = { equals };
+ for (let i = 0; i < customTesters.length; i++) {
+ const customTesterResult = customTesters[i].call(testerContext, a, b, customTesters);
+ if (customTesterResult !== undefined) {
+ return customTesterResult;
+ }
+ }
+ if (typeof URL === "function" && a instanceof URL && b instanceof URL) {
+ return a.href === b.href;
+ }
+ if (Object.is(a, b)) {
+ return true;
+ }
+ // A strict comparison is necessary because `null == undefined`.
+ if (a === null || b === null) {
+ return a === b;
+ }
+ const className = Object.prototype.toString.call(a);
+ if (className !== Object.prototype.toString.call(b)) {
+ return false;
+ }
+ switch (className) {
+ case "[object Boolean]":
+ case "[object String]":
+ case "[object Number]": if (typeof a !== typeof b) {
+ // One is a primitive, one a `new Primitive()`
+ return false;
+ } else if (typeof a !== "object" && typeof b !== "object") {
+ // both are proper primitives
+ return Object.is(a, b);
+ } else {
+ // both are `new Primitive()`s
+ return Object.is(a.valueOf(), b.valueOf());
+ }
+ case "[object Date]": {
+ const numA = +a;
+ const numB = +b;
+ // Coerce dates to numeric primitive values. Dates are compared by their
+ // millisecond representations. Note that invalid dates with millisecond representations
+ // of `NaN` are equivalent.
+ return numA === numB || Number.isNaN(numA) && Number.isNaN(numB);
+ }
+ case "[object RegExp]": return a.source === b.source && a.flags === b.flags;
+ case "[object Temporal.Instant]":
+ case "[object Temporal.ZonedDateTime]":
+ case "[object Temporal.PlainDateTime]":
+ case "[object Temporal.PlainDate]":
+ case "[object Temporal.PlainTime]":
+ case "[object Temporal.PlainYearMonth]":
+ case "[object Temporal.PlainMonthDay]": return a.equals(b);
+ case "[object Temporal.Duration]": return a.toString() === b.toString();
+ }
+ if (typeof a !== "object" || typeof b !== "object") {
+ return false;
+ }
+ // Use DOM3 method isEqualNode (IE>=9)
+ if (isDomNode(a) && isDomNode(b)) {
+ return a.isEqualNode(b);
+ }
+ // Used to detect circular references.
+ let length = aStack.length;
+ while (length--) {
+ // Linear search. Performance is inversely proportional to the number of
+ // unique nested structures.
+ // circular references at same depth are equal
+ // circular reference is not equal to non-circular one
+ if (aStack[length] === a) {
+ return bStack[length] === b;
+ } else if (bStack[length] === b) {
+ return false;
+ }
+ }
+ // Add the first object to the stack of traversed objects.
+ aStack.push(a);
+ bStack.push(b);
+ // Recursively compare objects and arrays.
+ // Compare array lengths to determine if a deep comparison is necessary.
+ if (className === "[object Array]" && a.length !== b.length) {
+ return false;
+ }
+ if (a instanceof Error && b instanceof Error) {
+ try {
+ return isErrorEqual(a, b, aStack, bStack, customTesters, hasKey);
+ } finally {
+ aStack.pop();
+ bStack.pop();
+ }
+ }
+ // Deep compare objects.
+ const aKeys = keys(a, hasKey);
+ let key;
+ let size = aKeys.length;
+ // Ensure that both objects contain the same number of properties before comparing deep equality.
+ if (keys(b, hasKey).length !== size) {
+ return false;
+ }
+ while (size--) {
+ key = aKeys[size];
+ // Deep compare each member
+ result = hasKey(b, key) && eq(a[key], b[key], aStack, bStack, customTesters, hasKey);
+ if (!result) {
+ return false;
+ }
+ }
+ // Remove the first object from the stack of traversed objects.
+ aStack.pop();
+ bStack.pop();
+ return result;
+}
+function isErrorEqual(a, b, aStack, bStack, customTesters, hasKey) {
+ // https://nodejs.org/docs/latest-v22.x/api/assert.html#comparison-details
+ // - [[Prototype]] of objects are compared using the === operator.
+ // - Only enumerable "own" properties are considered.
+ // - Error names, messages, causes, and errors are always compared, even if these are not enumerable properties. errors is also compared.
+ let result = Object.getPrototypeOf(a) === Object.getPrototypeOf(b) && a.name === b.name && a.message === b.message;
+ // check Error.cause asymmetrically
+ if (typeof b.cause !== "undefined") {
+ result && (result = eq(a.cause, b.cause, aStack, bStack, customTesters, hasKey));
+ }
+ // AggregateError.errors
+ if (a instanceof AggregateError && b instanceof AggregateError) {
+ result && (result = eq(a.errors, b.errors, aStack, bStack, customTesters, hasKey));
+ }
+ // spread to compare enumerable properties
+ result && (result = eq({ ...a }, { ...b }, aStack, bStack, customTesters, hasKey));
+ return result;
+}
+function keys(obj, hasKey) {
+ const keys = [];
+ for (const key in obj) {
+ if (hasKey(obj, key)) {
+ keys.push(key);
+ }
+ }
+ return keys.concat(Object.getOwnPropertySymbols(obj).filter((symbol) => Object.getOwnPropertyDescriptor(obj, symbol).enumerable));
+}
+function hasDefinedKey(obj, key) {
+ return hasKey(obj, key) && obj[key] !== undefined;
+}
+function hasKey(obj, key) {
+ return Object.hasOwn(obj, key);
+}
+function isA(typeName, value) {
+ return Object.prototype.toString.apply(value) === `[object ${typeName}]`;
+}
+function isDomNode(obj) {
+ return obj !== null && typeof obj === "object" && "nodeType" in obj && typeof obj.nodeType === "number" && "nodeName" in obj && typeof obj.nodeName === "string" && "isEqualNode" in obj && typeof obj.isEqualNode === "function";
+}
+function fnNameFor(func) {
+ if (func.name) {
+ return func.name;
+ }
+ const matches = functionToString.call(func).match(/^(?:async)?\s*function\s*(?:\*\s*)?([\w$]+)\s*\(/);
+ return matches ? matches[1] : "<anonymous>";
+}
+function getPrototype(obj) {
+ if (Object.getPrototypeOf) {
+ return Object.getPrototypeOf(obj);
+ }
+ if (obj.constructor.prototype === obj) {
+ return null;
+ }
+ return obj.constructor.prototype;
+}
+function hasProperty(obj, property) {
+ if (!obj) {
+ return false;
+ }
+ if (Object.hasOwn(obj, property)) {
+ return true;
+ }
+ return hasProperty(getPrototype(obj), property);
+}
+// SENTINEL constants are from https://github.com/facebook/immutable-js
+const IS_KEYED_SENTINEL = "@@__IMMUTABLE_KEYED__@@";
+const IS_SET_SENTINEL = "@@__IMMUTABLE_SET__@@";
+const IS_LIST_SENTINEL = "@@__IMMUTABLE_LIST__@@";
+const IS_ORDERED_SENTINEL = "@@__IMMUTABLE_ORDERED__@@";
+const IS_RECORD_SYMBOL = "@@__IMMUTABLE_RECORD__@@";
+function isImmutableUnorderedKeyed(maybeKeyed) {
+ return !!(maybeKeyed && maybeKeyed[IS_KEYED_SENTINEL] && !maybeKeyed[IS_ORDERED_SENTINEL]);
+}
+function isImmutableUnorderedSet(maybeSet) {
+ return !!(maybeSet && maybeSet[IS_SET_SENTINEL] && !maybeSet[IS_ORDERED_SENTINEL]);
+}
+function isObjectLiteral(source) {
+ return source != null && typeof source === "object" && !Array.isArray(source);
+}
+function isImmutableList(source) {
+ return Boolean(source && isObjectLiteral(source) && source[IS_LIST_SENTINEL]);
+}
+function isImmutableOrderedKeyed(source) {
+ return Boolean(source && isObjectLiteral(source) && source[IS_KEYED_SENTINEL] && source[IS_ORDERED_SENTINEL]);
+}
+function isImmutableOrderedSet(source) {
+ return Boolean(source && isObjectLiteral(source) && source[IS_SET_SENTINEL] && source[IS_ORDERED_SENTINEL]);
+}
+function isImmutableRecord(source) {
+ return Boolean(source && isObjectLiteral(source) && source[IS_RECORD_SYMBOL]);
+}
+/**
+* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*
+*/
+const IteratorSymbol = Symbol.iterator;
+function hasIterator(object) {
+ return !!(object != null && object[IteratorSymbol]);
+}
+function iterableEquality(a, b, customTesters = [], aStack = [], bStack = []) {
+ if (typeof a !== "object" || typeof b !== "object" || Array.isArray(a) || Array.isArray(b) || !hasIterator(a) || !hasIterator(b)) {
+ return undefined;
+ }
+ if (a.constructor !== b.constructor) {
+ return false;
+ }
+ let length = aStack.length;
+ while (length--) {
+ // Linear search. Performance is inversely proportional to the number of
+ // unique nested structures.
+ // circular references at same depth are equal
+ // circular reference is not equal to non-circular one
+ if (aStack[length] === a) {
+ return bStack[length] === b;
+ }
+ }
+ aStack.push(a);
+ bStack.push(b);
+ const filteredCustomTesters = [...customTesters.filter((t) => t !== iterableEquality), iterableEqualityWithStack];
+ function iterableEqualityWithStack(a, b) {
+ return iterableEquality(a, b, [...customTesters], [...aStack], [...bStack]);
+ }
+ if (a.size !== undefined) {
+ if (a.size !== b.size) {
+ return false;
+ } else if (isA("Set", a) || isImmutableUnorderedSet(a)) {
+ let allFound = true;
+ for (const aValue of a) {
+ if (!b.has(aValue)) {
+ let has = false;
+ for (const bValue of b) {
+ const isEqual = equals(aValue, bValue, filteredCustomTesters);
+ if (isEqual === true) {
+ has = true;
+ }
+ }
+ if (has === false) {
+ allFound = false;
+ break;
+ }
+ }
+ }
+ // Remove the first value from the stack of traversed values.
+ aStack.pop();
+ bStack.pop();
+ return allFound;
+ } else if (isA("Map", a) || isImmutableUnorderedKeyed(a)) {
+ let allFound = true;
+ for (const aEntry of a) {
+ if (!b.has(aEntry[0]) || !equals(aEntry[1], b.get(aEntry[0]), filteredCustomTesters)) {
+ let has = false;
+ for (const bEntry of b) {
+ const matchedKey = equals(aEntry[0], bEntry[0], filteredCustomTesters);
+ let matchedValue = false;
+ if (matchedKey === true) {
+ matchedValue = equals(aEntry[1], bEntry[1], filteredCustomTesters);
+ }
+ if (matchedValue === true) {
+ has = true;
+ }
+ }
+ if (has === false) {
+ allFound = false;
+ break;
+ }
+ }
+ }
+ // Remove the first value from the stack of traversed values.
+ aStack.pop();
+ bStack.pop();
+ return allFound;
+ }
+ }
+ const bIterator = b[IteratorSymbol]();
+ for (const aValue of a) {
+ const nextB = bIterator.next();
+ if (nextB.done || !equals(aValue, nextB.value, filteredCustomTesters)) {
+ return false;
+ }
+ }
+ if (!bIterator.next().done) {
+ return false;
+ }
+ if (!isImmutableList(a) && !isImmutableOrderedKeyed(a) && !isImmutableOrderedSet(a) && !isImmutableRecord(a)) {
+ const aEntries = Object.entries(a);
+ const bEntries = Object.entries(b);
+ if (!equals(aEntries, bEntries, filteredCustomTesters)) {
+ return false;
+ }
+ }
+ // Remove the first value from the stack of traversed values.
+ aStack.pop();
+ bStack.pop();
+ return true;
+}
+/**
+* Checks if `hasOwnProperty(object, key)` up the prototype chain, stopping at `Object.prototype`.
+*/
+function hasPropertyInObject(object, key) {
+ const shouldTerminate = !object || typeof object !== "object" || object === Object.prototype;
+ if (shouldTerminate) {
+ return false;
+ }
+ return Object.hasOwn(object, key) || hasPropertyInObject(Object.getPrototypeOf(object), key);
+}
+function isObjectWithKeys(a) {
+ return isObject(a) && !(a instanceof Error) && !Array.isArray(a) && !(a instanceof Date);
+}
+function subsetEquality(object, subset, customTesters = []) {
+ const filteredCustomTesters = customTesters.filter((t) => t !== subsetEquality);
+ // subsetEquality needs to keep track of the references
+ // it has already visited to avoid infinite loops in case
+ // there are circular references in the subset passed to it.
+ const subsetEqualityWithContext = (seenReferences = new WeakMap()) => (object, subset) => {
+ if (!isObjectWithKeys(subset)) {
+ return undefined;
+ }
+ return Object.keys(subset).every((key) => {
+ if (subset[key] != null && typeof subset[key] === "object") {
+ if (seenReferences.has(subset[key])) {
+ return equals(object[key], subset[key], filteredCustomTesters);
+ }
+ seenReferences.set(subset[key], true);
+ }
+ const result = object != null && hasPropertyInObject(object, key) && equals(object[key], subset[key], [...filteredCustomTesters, subsetEqualityWithContext(seenReferences)]);
+ // The main goal of using seenReference is to avoid circular node on tree.
+ // It will only happen within a parent and its child, not a node and nodes next to it (same level)
+ // We should keep the reference for a parent and its child only
+ // Thus we should delete the reference immediately so that it doesn't interfere
+ // other nodes within the same level on tree.
+ seenReferences.delete(subset[key]);
+ return result;
+ });
+ };
+ return subsetEqualityWithContext()(object, subset);
+}
+function typeEquality(a, b) {
+ if (a == null || b == null || a.constructor === b.constructor) {
+ return undefined;
+ }
+ return false;
+}
+function arrayBufferEquality(a, b) {
+ let dataViewA = a;
+ let dataViewB = b;
+ if (!(a instanceof DataView && b instanceof DataView)) {
+ if (!(a instanceof ArrayBuffer) || !(b instanceof ArrayBuffer)) {
+ return undefined;
+ }
+ try {
+ dataViewA = new DataView(a);
+ dataViewB = new DataView(b);
+ } catch {
+ return undefined;
+ }
+ }
+ // Buffers are not equal when they do not have the same byte length
+ if (dataViewA.byteLength !== dataViewB.byteLength) {
+ return false;
+ }
+ // Check if every byte value is equal to each other
+ for (let i = 0; i < dataViewA.byteLength; i++) {
+ if (dataViewA.getUint8(i) !== dataViewB.getUint8(i)) {
+ return false;
+ }
+ }
+ return true;
+}
+function sparseArrayEquality(a, b, customTesters = []) {
+ if (!Array.isArray(a) || !Array.isArray(b)) {
+ return undefined;
+ }
+ // A sparse array [, , 1] will have keys ["2"] whereas [undefined, undefined, 1] will have keys ["0", "1", "2"]
+ const aKeys = Object.keys(a);
+ const bKeys = Object.keys(b);
+ const filteredCustomTesters = customTesters.filter((t) => t !== sparseArrayEquality);
+ return equals(a, b, filteredCustomTesters, true) && equals(aKeys, bKeys);
+}
+function generateToBeMessage(deepEqualityName, expected = "#{this}", actual = "#{exp}") {
+ const toBeMessage = `expected ${expected} to be ${actual} // Object.is equality`;
+ if (["toStrictEqual", "toEqual"].includes(deepEqualityName)) {
+ return `${toBeMessage}\n\nIf it should pass with deep equality, replace "toBe" with "${deepEqualityName}"\n\nExpected: ${expected}\nReceived: serializes to the same string\n`;
+ }
+ return toBeMessage;
+}
+function pluralize(word, count) {
+ return `${count} ${word}${count === 1 ? "" : "s"}`;
+}
+function getObjectKeys(object) {
+ return [...Object.keys(object), ...Object.getOwnPropertySymbols(object).filter((s) => {
+ var _Object$getOwnPropert;
+ return (_Object$getOwnPropert = Object.getOwnPropertyDescriptor(object, s)) === null || _Object$getOwnPropert === void 0 ? void 0 : _Object$getOwnPropert.enumerable;
+ })];
+}
+function getObjectSubset(object, subset, customTesters) {
+ let stripped = 0;
+ const getObjectSubsetWithContext = (seenReferences = new WeakMap()) => (object, subset) => {
+ if (Array.isArray(object)) {
+ if (Array.isArray(subset) && subset.length === object.length) {
+ // The map method returns correct subclass of subset.
+ return subset.map((sub, i) => getObjectSubsetWithContext(seenReferences)(object[i], sub));
+ }
+ } else if (object instanceof Date) {
+ return object;
+ } else if (isObject(object) && isObject(subset)) {
+ if (equals(object, subset, [
+ ...customTesters,
+ iterableEquality,
+ subsetEquality
+ ])) {
+ // return "expected" subset to avoid showing irrelevant toMatchObject diff
+ return subset;
+ }
+ const trimmed = {};
+ seenReferences.set(object, trimmed);
+ // preserve constructor for toMatchObject diff
+ if (typeof object.constructor === "function" && typeof object.constructor.name === "string") {
+ Object.defineProperty(trimmed, "constructor", {
+ enumerable: false,
+ value: object.constructor
+ });
+ }
+ for (const key of getObjectKeys(object)) {
+ if (hasPropertyInObject(subset, key)) {
+ trimmed[key] = seenReferences.has(object[key]) ? seenReferences.get(object[key]) : getObjectSubsetWithContext(seenReferences)(object[key], subset[key]);
+ } else {
+ if (!seenReferences.has(object[key])) {
+ stripped += 1;
+ if (isObject(object[key])) {
+ stripped += getObjectKeys(object[key]).length;
+ }
+ getObjectSubsetWithContext(seenReferences)(object[key], subset[key]);
+ }
+ }
+ }
+ if (getObjectKeys(trimmed).length > 0) {
+ return trimmed;
+ }
+ }
+ return object;
+ };
+ return {
+ subset: getObjectSubsetWithContext()(object, subset),
+ stripped
+ };
+}
+/**
+* Detects if an object is a Standard Schema V1 compatible schema
+*/
+function isStandardSchema(obj) {
+ return !!obj && (typeof obj === "object" || typeof obj === "function") && obj["~standard"] && typeof obj["~standard"].validate === "function";
+}
+
+if (!Object.hasOwn(globalThis, MATCHERS_OBJECT)) {
+ const globalState = new WeakMap();
+ const matchers = Object.create(null);
+ const customEqualityTesters = [];
+ const asymmetricMatchers = Object.create(null);
+ Object.defineProperty(globalThis, MATCHERS_OBJECT, { get: () => globalState });
+ Object.defineProperty(globalThis, JEST_MATCHERS_OBJECT, {
+ configurable: true,
+ get: () => ({
+ state: globalState.get(globalThis[GLOBAL_EXPECT]),
+ matchers,
+ customEqualityTesters
+ })
+ });
+ Object.defineProperty(globalThis, ASYMMETRIC_MATCHERS_OBJECT, { get: () => asymmetricMatchers });
+}
+function getState(expect) {
+ return globalThis[MATCHERS_OBJECT].get(expect);
+}
+function setState(state, expect) {
+ const map = globalThis[MATCHERS_OBJECT];
+ const current = map.get(expect) || {};
+ // so it keeps getters from `testPath`
+ const results = Object.defineProperties(current, {
+ ...Object.getOwnPropertyDescriptors(current),
+ ...Object.getOwnPropertyDescriptors(state)
+ });
+ map.set(expect, results);
+}
+
+class AsymmetricMatcher {
+ // should have "jest" to be compatible with its ecosystem
+ $$typeof = Symbol.for("jest.asymmetricMatcher");
+ constructor(sample, inverse = false) {
+ this.sample = sample;
+ this.inverse = inverse;
+ }
+ getMatcherContext(expect) {
+ return {
+ ...getState(expect || globalThis[GLOBAL_EXPECT]),
+ equals,
+ isNot: this.inverse,
+ customTesters: getCustomEqualityTesters(),
+ utils: {
+ ...getMatcherUtils(),
+ diff,
+ stringify,
+ iterableEquality,
+ subsetEquality
+ }
+ };
+ }
+}
+// implement custom chai/loupe inspect for better AssertionError.message formatting
+// https://github.com/chaijs/loupe/blob/9b8a6deabcd50adc056a64fb705896194710c5c6/src/index.ts#L29
+// @ts-expect-error computed properties is not supported when isolatedDeclarations is enabled
+// FIXME: https://github.com/microsoft/TypeScript/issues/61068
+AsymmetricMatcher.prototype[Symbol.for("chai/inspect")] = function(options) {
+ // minimal pretty-format with simple manual truncation
+ const result = stringify(this, options.depth, { min: true });
+ if (result.length <= options.truncate) {
+ return result;
+ }
+ return `${this.toString()}{…}`;
+};
+class StringContaining extends AsymmetricMatcher {
+ constructor(sample, inverse = false) {
+ if (!isA("String", sample)) {
+ throw new Error("Expected is not a string");
+ }
+ super(sample, inverse);
+ }
+ asymmetricMatch(other) {
+ const result = isA("String", other) && other.includes(this.sample);
+ return this.inverse ? !result : result;
+ }
+ toString() {
+ return `String${this.inverse ? "Not" : ""}Containing`;
+ }
+ getExpectedType() {
+ return "string";
+ }
+}
+class Anything extends AsymmetricMatcher {
+ asymmetricMatch(other) {
+ return other != null;
+ }
+ toString() {
+ return "Anything";
+ }
+ toAsymmetricMatcher() {
+ return "Anything";
+ }
+}
+class ObjectContaining extends AsymmetricMatcher {
+ constructor(sample, inverse = false) {
+ super(sample, inverse);
+ }
+ getPrototype(obj) {
+ if (Object.getPrototypeOf) {
+ return Object.getPrototypeOf(obj);
+ }
+ if (obj.constructor.prototype === obj) {
+ return null;
+ }
+ return obj.constructor.prototype;
+ }
+ hasProperty(obj, property) {
+ if (!obj) {
+ return false;
+ }
+ if (Object.hasOwn(obj, property)) {
+ return true;
+ }
+ return this.hasProperty(this.getPrototype(obj), property);
+ }
+ getProperties(obj) {
+ return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj).filter((s) => {
+ var _Object$getOwnPropert;
+ return (_Object$getOwnPropert = Object.getOwnPropertyDescriptor(obj, s)) === null || _Object$getOwnPropert === void 0 ? void 0 : _Object$getOwnPropert.enumerable;
+ })];
+ }
+ asymmetricMatch(other, customTesters) {
+ if (typeof this.sample !== "object") {
+ throw new TypeError(`You must provide an object to ${this.toString()}, not '${typeof this.sample}'.`);
+ }
+ let result = true;
+ const properties = this.getProperties(this.sample);
+ for (const property of properties) {
+ var _Object$getOwnPropert2, _Object$getOwnPropert3;
+ if (!this.hasProperty(other, property)) {
+ result = false;
+ break;
+ }
+ const value = ((_Object$getOwnPropert2 = Object.getOwnPropertyDescriptor(this.sample, property)) === null || _Object$getOwnPropert2 === void 0 ? void 0 : _Object$getOwnPropert2.value) ?? this.sample[property];
+ const otherValue = ((_Object$getOwnPropert3 = Object.getOwnPropertyDescriptor(other, property)) === null || _Object$getOwnPropert3 === void 0 ? void 0 : _Object$getOwnPropert3.value) ?? other[property];
+ if (!equals(value, otherValue, customTesters)) {
+ result = false;
+ break;
+ }
+ }
+ return this.inverse ? !result : result;
+ }
+ toString() {
+ return `Object${this.inverse ? "Not" : ""}Containing`;
+ }
+ getExpectedType() {
+ return "object";
+ }
+}
+class ArrayContaining extends AsymmetricMatcher {
+ constructor(sample, inverse = false) {
+ super(sample, inverse);
+ }
+ asymmetricMatch(other, customTesters) {
+ if (!Array.isArray(this.sample)) {
+ throw new TypeError(`You must provide an array to ${this.toString()}, not '${typeof this.sample}'.`);
+ }
+ const result = this.sample.length === 0 || Array.isArray(other) && this.sample.every((item) => other.some((another) => equals(item, another, customTesters)));
+ return this.inverse ? !result : result;
+ }
+ toString() {
+ return `Array${this.inverse ? "Not" : ""}Containing`;
+ }
+ getExpectedType() {
+ return "array";
+ }
+}
+class Any extends AsymmetricMatcher {
+ constructor(sample) {
+ if (typeof sample === "undefined") {
+ throw new TypeError("any() expects to be passed a constructor function. " + "Please pass one or use anything() to match any object.");
+ }
+ super(sample);
+ }
+ fnNameFor(func) {
+ if (func.name) {
+ return func.name;
+ }
+ const functionToString = Function.prototype.toString;
+ const matches = functionToString.call(func).match(/^(?:async)?\s*function\s*(?:\*\s*)?([\w$]+)\s*\(/);
+ return matches ? matches[1] : "<anonymous>";
+ }
+ asymmetricMatch(other) {
+ if (this.sample === String) {
+ return typeof other == "string" || other instanceof String;
+ }
+ if (this.sample === Number) {
+ return typeof other == "number" || other instanceof Number;
+ }
+ if (this.sample === Function) {
+ return typeof other == "function" || typeof other === "function";
+ }
+ if (this.sample === Boolean) {
+ return typeof other == "boolean" || other instanceof Boolean;
+ }
+ if (this.sample === BigInt) {
+ return typeof other == "bigint" || other instanceof BigInt;
+ }
+ if (this.sample === Symbol) {
+ return typeof other == "symbol" || other instanceof Symbol;
+ }
+ if (this.sample === Object) {
+ return typeof other == "object";
+ }
+ return other instanceof this.sample;
+ }
+ toString() {
+ return "Any";
+ }
+ getExpectedType() {
+ if (this.sample === String) {
+ return "string";
+ }
+ if (this.sample === Number) {
+ return "number";
+ }
+ if (this.sample === Function) {
+ return "function";
+ }
+ if (this.sample === Object) {
+ return "object";
+ }
+ if (this.sample === Boolean) {
+ return "boolean";
+ }
+ return this.fnNameFor(this.sample);
+ }
+ toAsymmetricMatcher() {
+ return `Any<${this.fnNameFor(this.sample)}>`;
+ }
+}
+class StringMatching extends AsymmetricMatcher {
+ constructor(sample, inverse = false) {
+ if (!isA("String", sample) && !isA("RegExp", sample)) {
+ throw new Error("Expected is not a String or a RegExp");
+ }
+ super(new RegExp(sample), inverse);
+ }
+ asymmetricMatch(other) {
+ const result = isA("String", other) && this.sample.test(other);
+ return this.inverse ? !result : result;
+ }
+ toString() {
+ return `String${this.inverse ? "Not" : ""}Matching`;
+ }
+ getExpectedType() {
+ return "string";
+ }
+}
+class CloseTo extends AsymmetricMatcher {
+ precision;
+ constructor(sample, precision = 2, inverse = false) {
+ if (!isA("Number", sample)) {
+ throw new Error("Expected is not a Number");
+ }
+ if (!isA("Number", precision)) {
+ throw new Error("Precision is not a Number");
+ }
+ super(sample);
+ this.inverse = inverse;
+ this.precision = precision;
+ }
+ asymmetricMatch(other) {
+ if (!isA("Number", other)) {
+ return false;
+ }
+ let result = false;
+ if (other === Number.POSITIVE_INFINITY && this.sample === Number.POSITIVE_INFINITY) {
+ result = true;
+ } else if (other === Number.NEGATIVE_INFINITY && this.sample === Number.NEGATIVE_INFINITY) {
+ result = true;
+ } else {
+ result = Math.abs(this.sample - other) < 10 ** -this.precision / 2;
+ }
+ return this.inverse ? !result : result;
+ }
+ toString() {
+ return `Number${this.inverse ? "Not" : ""}CloseTo`;
+ }
+ getExpectedType() {
+ return "number";
+ }
+ toAsymmetricMatcher() {
+ return [
+ this.toString(),
+ this.sample,
+ `(${pluralize("digit", this.precision)})`
+ ].join(" ");
+ }
+}
+class SchemaMatching extends AsymmetricMatcher {
+ result;
+ constructor(sample, inverse = false) {
+ if (!isStandardSchema(sample)) {
+ throw new TypeError("SchemaMatching expected to receive a Standard Schema.");
+ }
+ super(sample, inverse);
+ }
+ asymmetricMatch(other) {
+ const result = this.sample["~standard"].validate(other);
+ // Check if the result is a Promise (async validation)
+ if (result instanceof Promise) {
+ throw new TypeError("Async schema validation is not supported in asymmetric matchers.");
+ }
+ this.result = result;
+ const pass = !this.result.issues || this.result.issues.length === 0;
+ return this.inverse ? !pass : pass;
+ }
+ toString() {
+ return `Schema${this.inverse ? "Not" : ""}Matching`;
+ }
+ getExpectedType() {
+ return "object";
+ }
+ toAsymmetricMatcher() {
+ var _this$result;
+ const { utils } = this.getMatcherContext();
+ const issues = ((_this$result = this.result) === null || _this$result === void 0 ? void 0 : _this$result.issues) || [];
+ if (issues.length > 0) {
+ return `${this.toString()} ${utils.stringify(this.result, undefined, { printBasicPrototype: false })}`;
+ }
+ return this.toString();
+ }
+}
+const JestAsymmetricMatchers = (chai, utils) => {
+ utils.addMethod(chai.expect, "anything", () => new Anything());
+ utils.addMethod(chai.expect, "any", (expected) => new Any(expected));
+ utils.addMethod(chai.expect, "stringContaining", (expected) => new StringContaining(expected));
+ utils.addMethod(chai.expect, "objectContaining", (expected) => new ObjectContaining(expected));
+ utils.addMethod(chai.expect, "arrayContaining", (expected) => new ArrayContaining(expected));
+ utils.addMethod(chai.expect, "stringMatching", (expected) => new StringMatching(expected));
+ utils.addMethod(chai.expect, "closeTo", (expected, precision) => new CloseTo(expected, precision));
+ utils.addMethod(chai.expect, "schemaMatching", (expected) => new SchemaMatching(expected));
+ // defineProperty does not work
+ chai.expect.not = {
+ stringContaining: (expected) => new StringContaining(expected, true),
+ objectContaining: (expected) => new ObjectContaining(expected, true),
+ arrayContaining: (expected) => new ArrayContaining(expected, true),
+ stringMatching: (expected) => new StringMatching(expected, true),
+ closeTo: (expected, precision) => new CloseTo(expected, precision, true),
+ schemaMatching: (expected) => new SchemaMatching(expected, true)
+ };
+};
+
+function createAssertionMessage(util, assertion, hasArgs) {
+ const not = util.flag(assertion, "negate") ? "not." : "";
+ const name = `${util.flag(assertion, "_name")}(${hasArgs ? "expected" : ""})`;
+ const promiseName = util.flag(assertion, "promise");
+ const promise = promiseName ? `.${promiseName}` : "";
+ return `expect(actual)${promise}.${not}${name}`;
+}
+function recordAsyncExpect(_test, promise, assertion, error) {
+ const test = _test;
+ // record promise for test, that resolves before test ends
+ if (test && promise instanceof Promise) {
+ // if promise is explicitly awaited, remove it from the list
+ promise = promise.finally(() => {
+ if (!test.promises) {
+ return;
+ }
+ const index = test.promises.indexOf(promise);
+ if (index !== -1) {
+ test.promises.splice(index, 1);
+ }
+ });
+ // record promise
+ if (!test.promises) {
+ test.promises = [];
+ }
+ test.promises.push(promise);
+ let resolved = false;
+ test.onFinished ?? (test.onFinished = []);
+ test.onFinished.push(() => {
+ if (!resolved) {
+ var _vitest_worker__;
+ const processor = ((_vitest_worker__ = globalThis.__vitest_worker__) === null || _vitest_worker__ === void 0 ? void 0 : _vitest_worker__.onFilterStackTrace) || ((s) => s || "");
+ const stack = processor(error.stack);
+ console.warn([
+ `Promise returned by \`${assertion}\` was not awaited. `,
+ "Vitest currently auto-awaits hanging assertions at the end of the test, but this will cause the test to fail in Vitest 3. ",
+ "Please remember to await the assertion.\n",
+ stack
+ ].join(""));
+ }
+ });
+ return {
+ then(onFulfilled, onRejected) {
+ resolved = true;
+ return promise.then(onFulfilled, onRejected);
+ },
+ catch(onRejected) {
+ return promise.catch(onRejected);
+ },
+ finally(onFinally) {
+ return promise.finally(onFinally);
+ },
+ [Symbol.toStringTag]: "Promise"
+ };
+ }
+ return promise;
+}
+function handleTestError(test, err) {
+ var _test$result;
+ test.result || (test.result = { state: "fail" });
+ test.result.state = "fail";
+ (_test$result = test.result).errors || (_test$result.errors = []);
+ test.result.errors.push(processError(err));
+}
+function wrapAssertion(utils, name, fn) {
+ return function(...args) {
+ // private
+ if (name !== "withTest") {
+ utils.flag(this, "_name", name);
+ }
+ if (!utils.flag(this, "soft")) {
+ return fn.apply(this, args);
+ }
+ const test = utils.flag(this, "vitest-test");
+ if (!test) {
+ throw new Error("expect.soft() can only be used inside a test");
+ }
+ try {
+ const result = fn.apply(this, args);
+ if (result && typeof result === "object" && typeof result.then === "function") {
+ return result.then(noop, (err) => {
+ handleTestError(test, err);
+ });
+ }
+ return result;
+ } catch (err) {
+ handleTestError(test, err);
+ }
+ };
+}
+
+// Jest Expect Compact
+const JestChaiExpect = (chai, utils) => {
+ const { AssertionError } = chai;
+ const customTesters = getCustomEqualityTesters();
+ function def(name, fn) {
+ const addMethod = (n) => {
+ const softWrapper = wrapAssertion(utils, n, fn);
+ utils.addMethod(chai.Assertion.prototype, n, softWrapper);
+ utils.addMethod(globalThis[JEST_MATCHERS_OBJECT].matchers, n, softWrapper);
+ };
+ if (Array.isArray(name)) {
+ name.forEach((n) => addMethod(n));
+ } else {
+ addMethod(name);
+ }
+ }
+ [
+ "throw",
+ "throws",
+ "Throw"
+ ].forEach((m) => {
+ utils.overwriteMethod(chai.Assertion.prototype, m, (_super) => {
+ return function(...args) {
+ const promise = utils.flag(this, "promise");
+ const object = utils.flag(this, "object");
+ const isNot = utils.flag(this, "negate");
+ if (promise === "rejects") {
+ utils.flag(this, "object", () => {
+ throw object;
+ });
+ } else if (promise === "resolves" && typeof object !== "function") {
+ if (!isNot) {
+ const message = utils.flag(this, "message") || "expected promise to throw an error, but it didn't";
+ const error = { showDiff: false };
+ throw new AssertionError(message, error, utils.flag(this, "ssfi"));
+ } else {
+ return;
+ }
+ }
+ _super.apply(this, args);
+ };
+ });
+ });
+ // @ts-expect-error @internal
+ def("withTest", function(test) {
+ utils.flag(this, "vitest-test", test);
+ return this;
+ });
+ def("toEqual", function(expected) {
+ const actual = utils.flag(this, "object");
+ const equal = equals(actual, expected, [...customTesters, iterableEquality]);
+ return this.assert(equal, "expected #{this} to deeply equal #{exp}", "expected #{this} to not deeply equal #{exp}", expected, actual);
+ });
+ def("toStrictEqual", function(expected) {
+ const obj = utils.flag(this, "object");
+ const equal = equals(obj, expected, [
+ ...customTesters,
+ iterableEquality,
+ typeEquality,
+ sparseArrayEquality,
+ arrayBufferEquality
+ ], true);
+ return this.assert(equal, "expected #{this} to strictly equal #{exp}", "expected #{this} to not strictly equal #{exp}", expected, obj);
+ });
+ def("toBe", function(expected) {
+ const actual = this._obj;
+ const pass = Object.is(actual, expected);
+ let deepEqualityName = "";
+ if (!pass) {
+ const toStrictEqualPass = equals(actual, expected, [
+ ...customTesters,
+ iterableEquality,
+ typeEquality,
+ sparseArrayEquality,
+ arrayBufferEquality
+ ], true);
+ if (toStrictEqualPass) {
+ deepEqualityName = "toStrictEqual";
+ } else {
+ const toEqualPass = equals(actual, expected, [...customTesters, iterableEquality]);
+ if (toEqualPass) {
+ deepEqualityName = "toEqual";
+ }
+ }
+ }
+ return this.assert(pass, generateToBeMessage(deepEqualityName), "expected #{this} not to be #{exp} // Object.is equality", expected, actual);
+ });
+ def("toMatchObject", function(expected) {
+ const actual = this._obj;
+ const pass = equals(actual, expected, [
+ ...customTesters,
+ iterableEquality,
+ subsetEquality
+ ]);
+ const isNot = utils.flag(this, "negate");
+ const { subset: actualSubset, stripped } = getObjectSubset(actual, expected, customTesters);
+ if (pass && isNot || !pass && !isNot) {
+ const msg = utils.getMessage(this, [
+ pass,
+ "expected #{this} to match object #{exp}",
+ "expected #{this} to not match object #{exp}",
+ expected,
+ actualSubset,
+ false
+ ]);
+ const message = stripped === 0 ? msg : `${msg}\n(${stripped} matching ${stripped === 1 ? "property" : "properties"} omitted from actual)`;
+ throw new AssertionError(message, {
+ showDiff: true,
+ expected,
+ actual: actualSubset
+ });
+ }
+ });
+ def("toMatch", function(expected) {
+ const actual = this._obj;
+ if (typeof actual !== "string") {
+ throw new TypeError(`.toMatch() expects to receive a string, but got ${typeof actual}`);
+ }
+ return this.assert(typeof expected === "string" ? actual.includes(expected) : actual.match(expected), `expected #{this} to match #{exp}`, `expected #{this} not to match #{exp}`, expected, actual);
+ });
+ def("toContain", function(item) {
+ const actual = this._obj;
+ if (typeof Node !== "undefined" && actual instanceof Node) {
+ if (!(item instanceof Node)) {
+ throw new TypeError(`toContain() expected a DOM node as the argument, but got ${typeof item}`);
+ }
+ return this.assert(actual.contains(item), "expected #{this} to contain element #{exp}", "expected #{this} not to contain element #{exp}", item, actual);
+ }
+ if (typeof DOMTokenList !== "undefined" && actual instanceof DOMTokenList) {
+ assertTypes(item, "class name", ["string"]);
+ const isNot = utils.flag(this, "negate");
+ const expectedClassList = isNot ? actual.value.replace(item, "").trim() : `${actual.value} ${item}`;
+ return this.assert(actual.contains(item), `expected "${actual.value}" to contain "${item}"`, `expected "${actual.value}" not to contain "${item}"`, expectedClassList, actual.value);
+ }
+ // handle simple case on our own using `this.assert` to include diff in error message
+ if (typeof actual === "string" && typeof item === "string") {
+ return this.assert(actual.includes(item), `expected #{this} to contain #{exp}`, `expected #{this} not to contain #{exp}`, item, actual);
+ }
+ // make "actual" indexable to have compatibility with jest
+ if (actual != null && typeof actual !== "string") {
+ utils.flag(this, "object", Array.from(actual));
+ }
+ return this.contain(item);
+ });
+ def("toContainEqual", function(expected) {
+ const obj = utils.flag(this, "object");
+ const index = Array.from(obj).findIndex((item) => {
+ return equals(item, expected, customTesters);
+ });
+ this.assert(index !== -1, "expected #{this} to deep equally contain #{exp}", "expected #{this} to not deep equally contain #{exp}", expected);
+ });
+ def("toBeTruthy", function() {
+ const obj = utils.flag(this, "object");
+ this.assert(Boolean(obj), "expected #{this} to be truthy", "expected #{this} to not be truthy", true, obj);
+ });
+ def("toBeFalsy", function() {
+ const obj = utils.flag(this, "object");
+ this.assert(!obj, "expected #{this} to be falsy", "expected #{this} to not be falsy", false, obj);
+ });
+ def("toBeGreaterThan", function(expected) {
+ const actual = this._obj;
+ assertTypes(actual, "actual", ["number", "bigint"]);
+ assertTypes(expected, "expected", ["number", "bigint"]);
+ return this.assert(actual > expected, `expected ${actual} to be greater than ${expected}`, `expected ${actual} to be not greater than ${expected}`, expected, actual, false);
+ });
+ def("toBeGreaterThanOrEqual", function(expected) {
+ const actual = this._obj;
+ assertTypes(actual, "actual", ["number", "bigint"]);
+ assertTypes(expected, "expected", ["number", "bigint"]);
+ return this.assert(actual >= expected, `expected ${actual} to be greater than or equal to ${expected}`, `expected ${actual} to be not greater than or equal to ${expected}`, expected, actual, false);
+ });
+ def("toBeLessThan", function(expected) {
+ const actual = this._obj;
+ assertTypes(actual, "actual", ["number", "bigint"]);
+ assertTypes(expected, "expected", ["number", "bigint"]);
+ return this.assert(actual < expected, `expected ${actual} to be less than ${expected}`, `expected ${actual} to be not less than ${expected}`, expected, actual, false);
+ });
+ def("toBeLessThanOrEqual", function(expected) {
+ const actual = this._obj;
+ assertTypes(actual, "actual", ["number", "bigint"]);
+ assertTypes(expected, "expected", ["number", "bigint"]);
+ return this.assert(actual <= expected, `expected ${actual} to be less than or equal to ${expected}`, `expected ${actual} to be not less than or equal to ${expected}`, expected, actual, false);
+ });
+ def("toBeNaN", function() {
+ const obj = utils.flag(this, "object");
+ this.assert(Number.isNaN(obj), "expected #{this} to be NaN", "expected #{this} not to be NaN", Number.NaN, obj);
+ });
+ def("toBeUndefined", function() {
+ const obj = utils.flag(this, "object");
+ this.assert(undefined === obj, "expected #{this} to be undefined", "expected #{this} not to be undefined", undefined, obj);
+ });
+ def("toBeNull", function() {
+ const obj = utils.flag(this, "object");
+ this.assert(obj === null, "expected #{this} to be null", "expected #{this} not to be null", null, obj);
+ });
+ def("toBeNullable", function() {
+ const obj = utils.flag(this, "object");
+ this.assert(obj == null, "expected #{this} to be nullish", "expected #{this} not to be nullish", null, obj);
+ });
+ def("toBeDefined", function() {
+ const obj = utils.flag(this, "object");
+ this.assert(typeof obj !== "undefined", "expected #{this} to be defined", "expected #{this} to be undefined", obj);
+ });
+ def("toBeTypeOf", function(expected) {
+ const actual = typeof this._obj;
+ const equal = expected === actual;
+ return this.assert(equal, "expected #{this} to be type of #{exp}", "expected #{this} not to be type of #{exp}", expected, actual);
+ });
+ def("toBeInstanceOf", function(obj) {
+ return this.instanceOf(obj);
+ });
+ def("toHaveLength", function(length) {
+ return this.have.length(length);
+ });
+ // destructuring, because it checks `arguments` inside, and value is passing as `undefined`
+ def("toHaveProperty", function(...args) {
+ if (Array.isArray(args[0])) {
+ args[0] = args[0].map((key) => String(key).replace(/([.[\]])/g, "\\$1")).join(".");
+ }
+ const actual = this._obj;
+ const [propertyName, expected] = args;
+ const getValue = () => {
+ const hasOwn = Object.hasOwn(actual, propertyName);
+ if (hasOwn) {
+ return {
+ value: actual[propertyName],
+ exists: true
+ };
+ }
+ return utils.getPathInfo(actual, propertyName);
+ };
+ const { value, exists } = getValue();
+ const pass = exists && (args.length === 1 || equals(expected, value, customTesters));
+ const valueString = args.length === 1 ? "" : ` with value ${utils.objDisplay(expected)}`;
+ return this.assert(pass, `expected #{this} to have property "${propertyName}"${valueString}`, `expected #{this} to not have property "${propertyName}"${valueString}`, expected, exists ? value : undefined);
+ });
+ def("toBeCloseTo", function(received, precision = 2) {
+ const expected = this._obj;
+ let pass = false;
+ let expectedDiff = 0;
+ let receivedDiff = 0;
+ if (received === Number.POSITIVE_INFINITY && expected === Number.POSITIVE_INFINITY) {
+ pass = true;
+ } else if (received === Number.NEGATIVE_INFINITY && expected === Number.NEGATIVE_INFINITY) {
+ pass = true;
+ } else {
+ expectedDiff = 10 ** -precision / 2;
+ receivedDiff = Math.abs(expected - received);
+ pass = receivedDiff < expectedDiff;
+ }
+ return this.assert(pass, `expected #{this} to be close to #{exp}, received difference is ${receivedDiff}, but expected ${expectedDiff}`, `expected #{this} to not be close to #{exp}, received difference is ${receivedDiff}, but expected ${expectedDiff}`, received, expected, false);
+ });
+ function assertIsMock(assertion) {
+ if (!isMockFunction(assertion._obj)) {
+ throw new TypeError(`${utils.inspect(assertion._obj)} is not a spy or a call to a spy!`);
+ }
+ }
+ function getSpy(assertion) {
+ assertIsMock(assertion);
+ return assertion._obj;
+ }
+ def(["toHaveBeenCalledTimes", "toBeCalledTimes"], function(number) {
+ const spy = getSpy(this);
+ const spyName = spy.getMockName();
+ const callCount = spy.mock.calls.length;
+ return this.assert(callCount === number, `expected "${spyName}" to be called #{exp} times, but got ${callCount} times`, `expected "${spyName}" to not be called #{exp} times`, number, callCount, false);
+ });
+ def("toHaveBeenCalledOnce", function() {
+ const spy = getSpy(this);
+ const spyName = spy.getMockName();
+ const callCount = spy.mock.calls.length;
+ return this.assert(callCount === 1, `expected "${spyName}" to be called once, but got ${callCount} times`, `expected "${spyName}" to not be called once`, 1, callCount, false);
+ });
+ def(["toHaveBeenCalled", "toBeCalled"], function() {
+ const spy = getSpy(this);
+ const spyName = spy.getMockName();
+ const callCount = spy.mock.calls.length;
+ const called = callCount > 0;
+ const isNot = utils.flag(this, "negate");
+ let msg = utils.getMessage(this, [
+ called,
+ `expected "${spyName}" to be called at least once`,
+ `expected "${spyName}" to not be called at all, but actually been called ${callCount} times`,
+ true,
+ called
+ ]);
+ if (called && isNot) {
+ msg = formatCalls(spy, msg);
+ }
+ if (called && isNot || !called && !isNot) {
+ throw new AssertionError(msg);
+ }
+ });
+ // manually compare array elements since `jestEquals` cannot
+ // apply asymmetric matcher to `undefined` array element.
+ function equalsArgumentArray(a, b) {
+ return a.length === b.length && a.every((aItem, i) => equals(aItem, b[i], [...customTesters, iterableEquality]));
+ }
+ def(["toHaveBeenCalledWith", "toBeCalledWith"], function(...args) {
+ const spy = getSpy(this);
+ const spyName = spy.getMockName();
+ const pass = spy.mock.calls.some((callArg) => equalsArgumentArray(callArg, args));
+ const isNot = utils.flag(this, "negate");
+ const msg = utils.getMessage(this, [
+ pass,
+ `expected "${spyName}" to be called with arguments: #{exp}`,
+ `expected "${spyName}" to not be called with arguments: #{exp}`,
+ args
+ ]);
+ if (pass && isNot || !pass && !isNot) {
+ throw new AssertionError(formatCalls(spy, msg, args));
+ }
+ });
+ def("toHaveBeenCalledExactlyOnceWith", function(...args) {
+ const spy = getSpy(this);
+ const spyName = spy.getMockName();
+ const callCount = spy.mock.calls.length;
+ const hasCallWithArgs = spy.mock.calls.some((callArg) => equalsArgumentArray(callArg, args));
+ const pass = hasCallWithArgs && callCount === 1;
+ const isNot = utils.flag(this, "negate");
+ const msg = utils.getMessage(this, [
+ pass,
+ `expected "${spyName}" to be called once with arguments: #{exp}`,
+ `expected "${spyName}" to not be called once with arguments: #{exp}`,
+ args
+ ]);
+ if (pass && isNot || !pass && !isNot) {
+ throw new AssertionError(formatCalls(spy, msg, args));
+ }
+ });
+ def(["toHaveBeenNthCalledWith", "nthCalledWith"], function(times, ...args) {
+ const spy = getSpy(this);
+ const spyName = spy.getMockName();
+ const nthCall = spy.mock.calls[times - 1];
+ const callCount = spy.mock.calls.length;
+ const isCalled = times <= callCount;
+ this.assert(nthCall && equalsArgumentArray(nthCall, args), `expected ${ordinalOf(times)} "${spyName}" call to have been called with #{exp}${isCalled ? `` : `, but called only ${callCount} times`}`, `expected ${ordinalOf(times)} "${spyName}" call to not have been called with #{exp}`, args, nthCall, isCalled);
+ });
+ def(["toHaveBeenLastCalledWith", "lastCalledWith"], function(...args) {
+ const spy = getSpy(this);
+ const spyName = spy.getMockName();
+ const lastCall = spy.mock.calls.at(-1);
+ this.assert(lastCall && equalsArgumentArray(lastCall, args), `expected last "${spyName}" call to have been called with #{exp}`, `expected last "${spyName}" call to not have been called with #{exp}`, args, lastCall);
+ });
+ /**
+ * Used for `toHaveBeenCalledBefore` and `toHaveBeenCalledAfter` to determine if the expected spy was called before the result spy.
+ */
+ function isSpyCalledBeforeAnotherSpy(beforeSpy, afterSpy, failIfNoFirstInvocation) {
+ const beforeInvocationCallOrder = beforeSpy.mock.invocationCallOrder;
+ const afterInvocationCallOrder = afterSpy.mock.invocationCallOrder;
+ if (beforeInvocationCallOrder.length === 0) {
+ return !failIfNoFirstInvocation;
+ }
+ if (afterInvocationCallOrder.length === 0) {
+ return false;
+ }
+ return beforeInvocationCallOrder[0] < afterInvocationCallOrder[0];
+ }
+ def(["toHaveBeenCalledBefore"], function(resultSpy, failIfNoFirstInvocation = true) {
+ const expectSpy = getSpy(this);
+ if (!isMockFunction(resultSpy)) {
+ throw new TypeError(`${utils.inspect(resultSpy)} is not a spy or a call to a spy`);
+ }
+ this.assert(isSpyCalledBeforeAnotherSpy(expectSpy, resultSpy, failIfNoFirstInvocation), `expected "${expectSpy.getMockName()}" to have been called before "${resultSpy.getMockName()}"`, `expected "${expectSpy.getMockName()}" to not have been called before "${resultSpy.getMockName()}"`, resultSpy, expectSpy);
+ });
+ def(["toHaveBeenCalledAfter"], function(resultSpy, failIfNoFirstInvocation = true) {
+ const expectSpy = getSpy(this);
+ if (!isMockFunction(resultSpy)) {
+ throw new TypeError(`${utils.inspect(resultSpy)} is not a spy or a call to a spy`);
+ }
+ this.assert(isSpyCalledBeforeAnotherSpy(resultSpy, expectSpy, failIfNoFirstInvocation), `expected "${expectSpy.getMockName()}" to have been called after "${resultSpy.getMockName()}"`, `expected "${expectSpy.getMockName()}" to not have been called after "${resultSpy.getMockName()}"`, resultSpy, expectSpy);
+ });
+ def(["toThrow", "toThrowError"], function(expected) {
+ if (typeof expected === "string" || typeof expected === "undefined" || expected instanceof RegExp) {
+ // Fixes the issue related to `chai` <https://github.com/vitest-dev/vitest/issues/6618>
+ return this.throws(expected === "" ? /^$/ : expected);
+ }
+ const obj = this._obj;
+ const promise = utils.flag(this, "promise");
+ const isNot = utils.flag(this, "negate");
+ let thrown = null;
+ if (promise === "rejects") {
+ thrown = obj;
+ } else if (promise === "resolves" && typeof obj !== "function") {
+ if (!isNot) {
+ const message = utils.flag(this, "message") || "expected promise to throw an error, but it didn't";
+ const error = { showDiff: false };
+ throw new AssertionError(message, error, utils.flag(this, "ssfi"));
+ } else {
+ return;
+ }
+ } else {
+ let isThrow = false;
+ try {
+ obj();
+ } catch (err) {
+ isThrow = true;
+ thrown = err;
+ }
+ if (!isThrow && !isNot) {
+ const message = utils.flag(this, "message") || "expected function to throw an error, but it didn't";
+ const error = { showDiff: false };
+ throw new AssertionError(message, error, utils.flag(this, "ssfi"));
+ }
+ }
+ if (typeof expected === "function") {
+ const name = expected.name || expected.prototype.constructor.name;
+ return this.assert(thrown && thrown instanceof expected, `expected error to be instance of ${name}`, `expected error not to be instance of ${name}`, expected, thrown);
+ }
+ if (expected instanceof Error) {
+ const equal = equals(thrown, expected, [...customTesters, iterableEquality]);
+ return this.assert(equal, "expected a thrown error to be #{exp}", "expected a thrown error not to be #{exp}", expected, thrown);
+ }
+ if (typeof expected === "object" && "asymmetricMatch" in expected && typeof expected.asymmetricMatch === "function") {
+ const matcher = expected;
+ return this.assert(thrown && matcher.asymmetricMatch(thrown), "expected error to match asymmetric matcher", "expected error not to match asymmetric matcher", matcher, thrown);
+ }
+ throw new Error(`"toThrow" expects string, RegExp, function, Error instance or asymmetric matcher, got "${typeof expected}"`);
+ });
+ [{
+ name: "toHaveResolved",
+ condition: (spy) => spy.mock.settledResults.length > 0 && spy.mock.settledResults.some(({ type }) => type === "fulfilled"),
+ action: "resolved"
+ }, {
+ name: ["toHaveReturned", "toReturn"],
+ condition: (spy) => spy.mock.calls.length > 0 && spy.mock.results.some(({ type }) => type !== "throw"),
+ action: "called"
+ }].forEach(({ name, condition, action }) => {
+ def(name, function() {
+ const spy = getSpy(this);
+ const spyName = spy.getMockName();
+ const pass = condition(spy);
+ this.assert(pass, `expected "${spyName}" to be successfully ${action} at least once`, `expected "${spyName}" to not be successfully ${action}`, pass, !pass, false);
+ });
+ });
+ [{
+ name: "toHaveResolvedTimes",
+ condition: (spy, times) => spy.mock.settledResults.reduce((s, { type }) => type === "fulfilled" ? ++s : s, 0) === times,
+ action: "resolved"
+ }, {
+ name: ["toHaveReturnedTimes", "toReturnTimes"],
+ condition: (spy, times) => spy.mock.results.reduce((s, { type }) => type === "throw" ? s : ++s, 0) === times,
+ action: "called"
+ }].forEach(({ name, condition, action }) => {
+ def(name, function(times) {
+ const spy = getSpy(this);
+ const spyName = spy.getMockName();
+ const pass = condition(spy, times);
+ this.assert(pass, `expected "${spyName}" to be successfully ${action} ${times} times`, `expected "${spyName}" to not be successfully ${action} ${times} times`, `expected resolved times: ${times}`, `received resolved times: ${pass}`, false);
+ });
+ });
+ [{
+ name: "toHaveResolvedWith",
+ condition: (spy, value) => spy.mock.settledResults.some(({ type, value: result }) => type === "fulfilled" && equals(value, result)),
+ action: "resolve"
+ }, {
+ name: ["toHaveReturnedWith", "toReturnWith"],
+ condition: (spy, value) => spy.mock.results.some(({ type, value: result }) => type === "return" && equals(value, result)),
+ action: "return"
+ }].forEach(({ name, condition, action }) => {
+ def(name, function(value) {
+ const spy = getSpy(this);
+ const pass = condition(spy, value);
+ const isNot = utils.flag(this, "negate");
+ if (pass && isNot || !pass && !isNot) {
+ const spyName = spy.getMockName();
+ const msg = utils.getMessage(this, [
+ pass,
+ `expected "${spyName}" to ${action} with: #{exp} at least once`,
+ `expected "${spyName}" to not ${action} with: #{exp}`,
+ value
+ ]);
+ const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
+ throw new AssertionError(formatReturns(spy, results, msg, value));
+ }
+ });
+ });
+ [{
+ name: "toHaveLastResolvedWith",
+ condition: (spy, value) => {
+ const result = spy.mock.settledResults.at(-1);
+ return Boolean(result && result.type === "fulfilled" && equals(result.value, value));
+ },
+ action: "resolve"
+ }, {
+ name: ["toHaveLastReturnedWith", "lastReturnedWith"],
+ condition: (spy, value) => {
+ const result = spy.mock.results.at(-1);
+ return Boolean(result && result.type === "return" && equals(result.value, value));
+ },
+ action: "return"
+ }].forEach(({ name, condition, action }) => {
+ def(name, function(value) {
+ const spy = getSpy(this);
+ const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
+ const result = results.at(-1);
+ const spyName = spy.getMockName();
+ this.assert(condition(spy, value), `expected last "${spyName}" call to ${action} #{exp}`, `expected last "${spyName}" call to not ${action} #{exp}`, value, result === null || result === void 0 ? void 0 : result.value);
+ });
+ });
+ [{
+ name: "toHaveNthResolvedWith",
+ condition: (spy, index, value) => {
+ const result = spy.mock.settledResults[index - 1];
+ return result && result.type === "fulfilled" && equals(result.value, value);
+ },
+ action: "resolve"
+ }, {
+ name: ["toHaveNthReturnedWith", "nthReturnedWith"],
+ condition: (spy, index, value) => {
+ const result = spy.mock.results[index - 1];
+ return result && result.type === "return" && equals(result.value, value);
+ },
+ action: "return"
+ }].forEach(({ name, condition, action }) => {
+ def(name, function(nthCall, value) {
+ const spy = getSpy(this);
+ const spyName = spy.getMockName();
+ const results = action === "return" ? spy.mock.results : spy.mock.settledResults;
+ const result = results[nthCall - 1];
+ const ordinalCall = `${ordinalOf(nthCall)} call`;
+ this.assert(condition(spy, nthCall, value), `expected ${ordinalCall} "${spyName}" call to ${action} #{exp}`, `expected ${ordinalCall} "${spyName}" call to not ${action} #{exp}`, value, result === null || result === void 0 ? void 0 : result.value);
+ });
+ });
+ // @ts-expect-error @internal
+ def("withContext", function(context) {
+ for (const key in context) {
+ utils.flag(this, key, context[key]);
+ }
+ return this;
+ });
+ utils.addProperty(chai.Assertion.prototype, "resolves", function __VITEST_RESOLVES__() {
+ const error = new Error("resolves");
+ utils.flag(this, "promise", "resolves");
+ utils.flag(this, "error", error);
+ const test = utils.flag(this, "vitest-test");
+ const obj = utils.flag(this, "object");
+ if (utils.flag(this, "poll")) {
+ throw new SyntaxError(`expect.poll() is not supported in combination with .resolves`);
+ }
+ if (typeof (obj === null || obj === void 0 ? void 0 : obj.then) !== "function") {
+ throw new TypeError(`You must provide a Promise to expect() when using .resolves, not '${typeof obj}'.`);
+ }
+ const proxy = new Proxy(this, { get: (target, key, receiver) => {
+ const result = Reflect.get(target, key, receiver);
+ if (typeof result !== "function") {
+ return result instanceof chai.Assertion ? proxy : result;
+ }
+ return (...args) => {
+ utils.flag(this, "_name", key);
+ const promise = obj.then((value) => {
+ utils.flag(this, "object", value);
+ return result.call(this, ...args);
+ }, (err) => {
+ const _error = new AssertionError(`promise rejected "${utils.inspect(err)}" instead of resolving`, { showDiff: false });
+ _error.cause = err;
+ _error.stack = error.stack.replace(error.message, _error.message);
+ throw _error;
+ });
+ return recordAsyncExpect(test, promise, createAssertionMessage(utils, this, !!args.length), error);
+ };
+ } });
+ return proxy;
+ });
+ utils.addProperty(chai.Assertion.prototype, "rejects", function __VITEST_REJECTS__() {
+ const error = new Error("rejects");
+ utils.flag(this, "promise", "rejects");
+ utils.flag(this, "error", error);
+ const test = utils.flag(this, "vitest-test");
+ const obj = utils.flag(this, "object");
+ const wrapper = typeof obj === "function" ? obj() : obj;
+ if (utils.flag(this, "poll")) {
+ throw new SyntaxError(`expect.poll() is not supported in combination with .rejects`);
+ }
+ if (typeof (wrapper === null || wrapper === void 0 ? void 0 : wrapper.then) !== "function") {
+ throw new TypeError(`You must provide a Promise to expect() when using .rejects, not '${typeof wrapper}'.`);
+ }
+ const proxy = new Proxy(this, { get: (target, key, receiver) => {
+ const result = Reflect.get(target, key, receiver);
+ if (typeof result !== "function") {
+ return result instanceof chai.Assertion ? proxy : result;
+ }
+ return (...args) => {
+ utils.flag(this, "_name", key);
+ const promise = wrapper.then((value) => {
+ const _error = new AssertionError(`promise resolved "${utils.inspect(value)}" instead of rejecting`, {
+ showDiff: true,
+ expected: new Error("rejected promise"),
+ actual: value
+ });
+ _error.stack = error.stack.replace(error.message, _error.message);
+ throw _error;
+ }, (err) => {
+ utils.flag(this, "object", err);
+ return result.call(this, ...args);
+ });
+ return recordAsyncExpect(test, promise, createAssertionMessage(utils, this, !!args.length), error);
+ };
+ } });
+ return proxy;
+ });
+};
+function ordinalOf(i) {
+ const j = i % 10;
+ const k = i % 100;
+ if (j === 1 && k !== 11) {
+ return `${i}st`;
+ }
+ if (j === 2 && k !== 12) {
+ return `${i}nd`;
+ }
+ if (j === 3 && k !== 13) {
+ return `${i}rd`;
+ }
+ return `${i}th`;
+}
+function formatCalls(spy, msg, showActualCall) {
+ if (spy.mock.calls.length) {
+ msg += c.gray(`\n\nReceived: \n\n${spy.mock.calls.map((callArg, i) => {
+ let methodCall = c.bold(` ${ordinalOf(i + 1)} ${spy.getMockName()} call:\n\n`);
+ if (showActualCall) {
+ methodCall += diff(showActualCall, callArg, { omitAnnotationLines: true });
+ } else {
+ methodCall += stringify(callArg).split("\n").map((line) => ` ${line}`).join("\n");
+ }
+ methodCall += "\n";
+ return methodCall;
+ }).join("\n")}`);
+ }
+ msg += c.gray(`\n\nNumber of calls: ${c.bold(spy.mock.calls.length)}\n`);
+ return msg;
+}
+function formatReturns(spy, results, msg, showActualReturn) {
+ if (results.length) {
+ msg += c.gray(`\n\nReceived: \n\n${results.map((callReturn, i) => {
+ let methodCall = c.bold(` ${ordinalOf(i + 1)} ${spy.getMockName()} call return:\n\n`);
+ if (showActualReturn) {
+ methodCall += diff(showActualReturn, callReturn.value, { omitAnnotationLines: true });
+ } else {
+ methodCall += stringify(callReturn).split("\n").map((line) => ` ${line}`).join("\n");
+ }
+ methodCall += "\n";
+ return methodCall;
+ }).join("\n")}`);
+ }
+ msg += c.gray(`\n\nNumber of calls: ${c.bold(spy.mock.calls.length)}\n`);
+ return msg;
+}
+
+function getMatcherState(assertion, expect) {
+ const obj = assertion._obj;
+ const isNot = util.flag(assertion, "negate");
+ const promise = util.flag(assertion, "promise") || "";
+ const customMessage = util.flag(assertion, "message");
+ const jestUtils = {
+ ...getMatcherUtils(),
+ diff,
+ stringify,
+ iterableEquality,
+ subsetEquality
+ };
+ let task = util.flag(assertion, "vitest-test");
+ const currentTestName = (task === null || task === void 0 ? void 0 : task.fullTestName) ?? "";
+ if ((task === null || task === void 0 ? void 0 : task.type) !== "test") {
+ task = undefined;
+ }
+ const matcherState = {
+ ...getState(expect),
+ task,
+ currentTestName,
+ customTesters: getCustomEqualityTesters(),
+ isNot,
+ utils: jestUtils,
+ promise,
+ equals,
+ suppressedErrors: [],
+ soft: util.flag(assertion, "soft"),
+ poll: util.flag(assertion, "poll")
+ };
+ return {
+ state: matcherState,
+ isNot,
+ obj,
+ customMessage
+ };
+}
+class JestExtendError extends Error {
+ constructor(message, actual, expected) {
+ super(message);
+ this.actual = actual;
+ this.expected = expected;
+ }
+}
+function JestExtendPlugin(c, expect, matchers) {
+ return (_, utils) => {
+ Object.entries(matchers).forEach(([expectAssertionName, expectAssertion]) => {
+ function expectWrapper(...args) {
+ const { state, isNot, obj, customMessage } = getMatcherState(this, expect);
+ const result = expectAssertion.call(state, obj, ...args);
+ if (result && typeof result === "object" && typeof result.then === "function") {
+ const thenable = result;
+ return thenable.then(({ pass, message, actual, expected }) => {
+ if (pass && isNot || !pass && !isNot) {
+ const errorMessage = customMessage != null ? customMessage : message();
+ throw new JestExtendError(errorMessage, actual, expected);
+ }
+ });
+ }
+ const { pass, message, actual, expected } = result;
+ if (pass && isNot || !pass && !isNot) {
+ const errorMessage = customMessage != null ? customMessage : message();
+ throw new JestExtendError(errorMessage, actual, expected);
+ }
+ }
+ const softWrapper = wrapAssertion(utils, expectAssertionName, expectWrapper);
+ utils.addMethod(globalThis[JEST_MATCHERS_OBJECT].matchers, expectAssertionName, softWrapper);
+ utils.addMethod(c.Assertion.prototype, expectAssertionName, softWrapper);
+ class CustomMatcher extends AsymmetricMatcher {
+ constructor(inverse = false, ...sample) {
+ super(sample, inverse);
+ }
+ asymmetricMatch(other) {
+ const { pass } = expectAssertion.call(this.getMatcherContext(expect), other, ...this.sample);
+ return this.inverse ? !pass : pass;
+ }
+ toString() {
+ return `${this.inverse ? "not." : ""}${expectAssertionName}`;
+ }
+ getExpectedType() {
+ return "any";
+ }
+ toAsymmetricMatcher() {
+ return `${this.toString()}<${this.sample.map((item) => stringify(item)).join(", ")}>`;
+ }
+ }
+ const customMatcher = (...sample) => new CustomMatcher(false, ...sample);
+ Object.defineProperty(expect, expectAssertionName, {
+ configurable: true,
+ enumerable: true,
+ value: customMatcher,
+ writable: true
+ });
+ Object.defineProperty(expect.not, expectAssertionName, {
+ configurable: true,
+ enumerable: true,
+ value: (...sample) => new CustomMatcher(true, ...sample),
+ writable: true
+ });
+ // keep track of asymmetric matchers on global so that it can be copied over to local context's `expect`.
+ // note that the negated variant is automatically shared since it's assigned on the single `expect.not` object.
+ Object.defineProperty(globalThis[ASYMMETRIC_MATCHERS_OBJECT], expectAssertionName, {
+ configurable: true,
+ enumerable: true,
+ value: customMatcher,
+ writable: true
+ });
+ });
+ };
+}
+const JestExtend = (chai, utils) => {
+ utils.addMethod(chai.expect, "extend", (expect, expects) => {
+ use(JestExtendPlugin(chai, expect, expects));
+ });
+};
+
+export { ASYMMETRIC_MATCHERS_OBJECT, Any, Anything, ArrayContaining, AsymmetricMatcher, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, ObjectContaining, SchemaMatching, StringContaining, StringMatching, addCustomEqualityTesters, arrayBufferEquality, customMatchers, equals, fnNameFor, generateToBeMessage, getObjectKeys, getObjectSubset, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, isStandardSchema, iterableEquality, pluralize, setState, sparseArrayEquality, subsetEquality, typeEquality };
diff --git a/vanilla/node_modules/@vitest/expect/package.json b/vanilla/node_modules/@vitest/expect/package.json
new file mode 100644
index 0000000..14c0b9e
--- /dev/null
+++ b/vanilla/node_modules/@vitest/expect/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "@vitest/expect",
+ "type": "module",
+ "version": "4.0.18",
+ "description": "Jest's expect matchers as a Chai plugin",
+ "license": "MIT",
+ "funding": "https://opencollective.com/vitest",
+ "homepage": "https://github.com/vitest-dev/vitest/tree/main/packages/expect#readme",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/vitest-dev/vitest.git",
+ "directory": "packages/expect"
+ },
+ "bugs": {
+ "url": "https://github.com/vitest-dev/vitest/issues"
+ },
+ "sideEffects": false,
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/index.js"
+ },
+ "./*": "./*"
+ },
+ "main": "./dist/index.js",
+ "module": "./dist/index.js",
+ "types": "./dist/index.d.ts",
+ "files": [
+ "dist"
+ ],
+ "dependencies": {
+ "@standard-schema/spec": "^1.0.0",
+ "@types/chai": "^5.2.2",
+ "chai": "^6.2.1",
+ "tinyrainbow": "^3.0.3",
+ "@vitest/spy": "4.0.18",
+ "@vitest/utils": "4.0.18"
+ },
+ "devDependencies": {
+ "@vitest/runner": "4.0.18"
+ },
+ "scripts": {
+ "build": "premove dist && rollup -c",
+ "dev": "rollup -c --watch"
+ }
+} \ No newline at end of file