|
- import { getColors, stringify, isObject, assertTypes } from '@vitest/utils';
- export { setupColors } from '@vitest/utils';
- import { unifiedDiff } from '@vitest/utils/diff';
- import { AssertionError, util } from 'chai';
- import { isMockFunction } from '@vitest/spy';
-
- const MATCHERS_OBJECT = Symbol.for("matchers-object");
- const JEST_MATCHERS_OBJECT = Symbol.for("$$jest-matchers-object");
- const GLOBAL_EXPECT = Symbol.for("expect-global");
-
- if (!Object.prototype.hasOwnProperty.call(globalThis, MATCHERS_OBJECT)) {
- const globalState = /* @__PURE__ */ new WeakMap();
- const matchers = /* @__PURE__ */ 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
- })
- });
- }
- const getState = (expect) => globalThis[MATCHERS_OBJECT].get(expect);
- const setState = (state, expect) => {
- const map = globalThis[MATCHERS_OBJECT];
- const current = map.get(expect) || {};
- Object.assign(current, state);
- map.set(expect, current);
- };
-
- function getMatcherUtils() {
- const c = () => getColors();
- 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(".")) {
- dimString += matcherName;
- } else {
- 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 = "\xB7";
- const replaceTrailingSpaces = (text) => text.replace(/\s+$/gm, (spaces) => SPACE_SYMBOL.repeat(spaces.length));
- const printReceived = (object) => RECEIVED_COLOR(replaceTrailingSpaces(stringify(object)));
- const printExpected = (value) => EXPECTED_COLOR(replaceTrailingSpaces(stringify(value)));
- return {
- EXPECTED_COLOR,
- RECEIVED_COLOR,
- INVERTED_COLOR,
- BOLD_WEIGHT,
- DIM_COLOR,
- matcherHint,
- printReceived,
- printExpected
- };
- }
- function diff(a, b, options) {
- const c = getColors();
- return unifiedDiff(stringify(b), stringify(a), {
- colorDim: c.dim,
- colorSuccess: c.green,
- colorError: c.red,
- showLegend: options == null ? void 0 : options.showLegend
- });
- }
-
- 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 = /* @__PURE__ */ 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) {
- const asymmetricA = isAsymmetric(a);
- const asymmetricB = isAsymmetric(b);
- if (asymmetricA && asymmetricB)
- return void 0;
- if (asymmetricA)
- return a.asymmetricMatch(b);
- if (asymmetricB)
- return b.asymmetricMatch(a);
- }
- function eq(a, b, aStack, bStack, customTesters, hasKey2) {
- let result = true;
- const asymmetricResult = asymmetricMatch(a, b);
- if (asymmetricResult !== void 0)
- return asymmetricResult;
- for (let i = 0; i < customTesters.length; i++) {
- const customTesterResult = customTesters[i](a, b);
- if (customTesterResult !== void 0)
- return customTesterResult;
- }
- if (a instanceof Error && b instanceof Error)
- return a.message === b.message;
- if (Object.is(a, b))
- return true;
- 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) {
- return false;
- } else if (typeof a !== "object" && typeof b !== "object") {
- return Object.is(a, b);
- } else {
- return Object.is(a.valueOf(), b.valueOf());
- }
- case "[object Date]":
- return isNaN(a) && isNaN(b) || +a === +b;
- case "[object RegExp]":
- return a.source === b.source && a.flags === b.flags;
- }
- if (typeof a !== "object" || typeof b !== "object")
- return false;
- if (isDomNode(a) && isDomNode(b))
- return a.isEqualNode(b);
- let length = aStack.length;
- while (length--) {
- if (aStack[length] === a)
- return bStack[length] === b;
- else if (bStack[length] === b)
- return false;
- }
- aStack.push(a);
- bStack.push(b);
- if (className === "[object Array]" && a.length !== b.length)
- return false;
- const aKeys = keys(a, hasKey2);
- let key;
- let size = aKeys.length;
- if (keys(b, hasKey2).length !== size)
- return false;
- while (size--) {
- key = aKeys[size];
- result = hasKey2(b, key) && eq(a[key], b[key], aStack, bStack, customTesters, hasKey2);
- if (!result)
- return false;
- }
- aStack.pop();
- bStack.pop();
- return result;
- }
- function keys(obj, hasKey2) {
- const keys2 = [];
- for (const key in obj) {
- if (hasKey2(obj, key))
- keys2.push(key);
- }
- return keys2.concat(
- Object.getOwnPropertySymbols(obj).filter(
- (symbol) => Object.getOwnPropertyDescriptor(obj, symbol).enumerable
- )
- );
- }
- function hasDefinedKey(obj, key) {
- return hasKey(obj, key) && obj[key] !== void 0;
- }
- function hasKey(obj, key) {
- return Object.prototype.hasOwnProperty.call(obj, key);
- }
- function isA(typeName, value) {
- return Object.prototype.toString.apply(value) === `[object ${typeName}]`;
- }
- function isDomNode(obj) {
- return obj !== null && typeof obj === "object" && typeof obj.nodeType === "number" && typeof obj.nodeName === "string" && 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.prototype.hasOwnProperty.call(obj, property))
- return true;
- return hasProperty(getPrototype(obj), property);
- }
- const IS_KEYED_SENTINEL = "@@__IMMUTABLE_KEYED__@@";
- const IS_SET_SENTINEL = "@@__IMMUTABLE_SET__@@";
- const IS_ORDERED_SENTINEL = "@@__IMMUTABLE_ORDERED__@@";
- 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]);
- }
- const IteratorSymbol = Symbol.iterator;
- const hasIterator = (object) => !!(object != null && object[IteratorSymbol]);
- const iterableEquality = (a, b, aStack = [], bStack = []) => {
- if (typeof a !== "object" || typeof b !== "object" || Array.isArray(a) || Array.isArray(b) || !hasIterator(a) || !hasIterator(b))
- return void 0;
- if (a.constructor !== b.constructor)
- return false;
- let length = aStack.length;
- while (length--) {
- if (aStack[length] === a)
- return bStack[length] === b;
- }
- aStack.push(a);
- bStack.push(b);
- const iterableEqualityWithStack = (a2, b2) => iterableEquality(a2, b2, [...aStack], [...bStack]);
- if (a.size !== void 0) {
- 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, [iterableEqualityWithStack]);
- if (isEqual === true)
- has = true;
- }
- if (has === false) {
- allFound = false;
- break;
- }
- }
- }
- 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]), [iterableEqualityWithStack])) {
- let has = false;
- for (const bEntry of b) {
- const matchedKey = equals(aEntry[0], bEntry[0], [
- iterableEqualityWithStack
- ]);
- let matchedValue = false;
- if (matchedKey === true) {
- matchedValue = equals(aEntry[1], bEntry[1], [
- iterableEqualityWithStack
- ]);
- }
- if (matchedValue === true)
- has = true;
- }
- if (has === false) {
- allFound = false;
- break;
- }
- }
- }
- 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, [iterableEqualityWithStack]))
- return false;
- }
- if (!bIterator.next().done)
- return false;
- aStack.pop();
- bStack.pop();
- return true;
- };
- const hasPropertyInObject = (object, key) => {
- const shouldTerminate = !object || typeof object !== "object" || object === Object.prototype;
- if (shouldTerminate)
- return false;
- return Object.prototype.hasOwnProperty.call(object, key) || hasPropertyInObject(Object.getPrototypeOf(object), key);
- };
- const isObjectWithKeys = (a) => isObject(a) && !(a instanceof Error) && !Array.isArray(a) && !(a instanceof Date);
- const subsetEquality = (object, subset) => {
- const subsetEqualityWithContext = (seenReferences = /* @__PURE__ */ new WeakMap()) => (object2, subset2) => {
- if (!isObjectWithKeys(subset2))
- return void 0;
- return Object.keys(subset2).every((key) => {
- if (isObjectWithKeys(subset2[key])) {
- if (seenReferences.has(subset2[key]))
- return equals(object2[key], subset2[key], [iterableEquality]);
- seenReferences.set(subset2[key], true);
- }
- const result = object2 != null && hasPropertyInObject(object2, key) && equals(object2[key], subset2[key], [
- iterableEquality,
- subsetEqualityWithContext(seenReferences)
- ]);
- seenReferences.delete(subset2[key]);
- return result;
- });
- };
- return subsetEqualityWithContext()(object, subset);
- };
- const typeEquality = (a, b) => {
- if (a == null || b == null || a.constructor === b.constructor)
- return void 0;
- return false;
- };
- const arrayBufferEquality = (a, b) => {
- if (!(a instanceof ArrayBuffer) || !(b instanceof ArrayBuffer))
- return void 0;
- const dataViewA = new DataView(a);
- const dataViewB = new DataView(b);
- if (dataViewA.byteLength !== dataViewB.byteLength)
- return false;
- for (let i = 0; i < dataViewA.byteLength; i++) {
- if (dataViewA.getUint8(i) !== dataViewB.getUint8(i))
- return false;
- }
- return true;
- };
- const sparseArrayEquality = (a, b) => {
- if (!Array.isArray(a) || !Array.isArray(b))
- return void 0;
- const aKeys = Object.keys(a);
- const bKeys = Object.keys(b);
- return equals(a, b, [iterableEquality, typeEquality], true) && equals(aKeys, bKeys);
- };
- const generateToBeMessage = (deepEqualityName, expected = "#{this}", actual = "#{exp}") => {
- const toBeMessage = `expected ${expected} to be ${actual} // Object.is equality`;
- if (["toStrictEqual", "toEqual"].includes(deepEqualityName))
- return `${toBeMessage}
-
- If it should pass with deep equality, replace "toBe" with "${deepEqualityName}"
-
- Expected: ${expected}
- Received: serializes to the same string
- `;
- return toBeMessage;
- };
-
- class AsymmetricMatcher {
- constructor(sample, inverse = false) {
- this.sample = sample;
- this.inverse = inverse;
- this.$$typeof = Symbol.for("jest.asymmetricMatcher");
- }
- getMatcherContext(expect) {
- return {
- ...getState(expect || globalThis[GLOBAL_EXPECT]),
- equals,
- isNot: this.inverse,
- utils: {
- ...getMatcherUtils(),
- diff,
- stringify,
- iterableEquality,
- subsetEquality
- }
- };
- }
- }
- 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.prototype.hasOwnProperty.call(obj, property))
- return true;
- return this.hasProperty(this.getPrototype(obj), property);
- }
- asymmetricMatch(other) {
- if (typeof this.sample !== "object") {
- throw new TypeError(
- `You must provide an object to ${this.toString()}, not '${typeof this.sample}'.`
- );
- }
- let result = true;
- for (const property in this.sample) {
- if (!this.hasProperty(other, property) || !equals(this.sample[property], other[property])) {
- 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) {
- 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))
- );
- 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" || other instanceof 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";
- }
- }
- 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)
- );
- 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)
- };
- };
-
- const JestChaiExpect = (chai, utils) => {
- const c = () => getColors();
- function def(name, fn) {
- const addMethod = (n) => {
- utils.addMethod(chai.Assertion.prototype, n, fn);
- utils.addMethod(globalThis[JEST_MATCHERS_OBJECT].matchers, n, fn);
- };
- 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);
- };
- });
- });
- 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,
- [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,
- [
- 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,
- [
- iterableEquality,
- typeEquality,
- sparseArrayEquality,
- arrayBufferEquality
- ],
- true
- );
- if (toStrictEqualPass) {
- deepEqualityName = "toStrictEqual";
- } else {
- const toEqualPass = equals(
- actual,
- expected,
- [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;
- return this.assert(
- equals(actual, expected, [iterableEquality, subsetEquality]),
- "expected #{this} to match object #{exp}",
- "expected #{this} to not match object #{exp}",
- expected,
- actual
- );
- });
- def("toMatch", function(expected) {
- if (typeof expected === "string")
- return this.include(expected);
- else
- return this.match(expected);
- });
- def("toContain", function(item) {
- 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);
- });
- 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",
- obj
- );
- });
- def("toBeFalsy", function() {
- const obj = utils.flag(this, "object");
- this.assert(
- !obj,
- "expected #{this} to be falsy",
- "expected #{this} to not be falsy",
- 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}`,
- actual,
- expected
- );
- });
- 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}`,
- actual,
- expected
- );
- });
- 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}`,
- actual,
- expected
- );
- });
- 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}`,
- actual,
- expected
- );
- });
- def("toBeNaN", function() {
- return this.be.NaN;
- });
- def("toBeUndefined", function() {
- return this.be.undefined;
- });
- def("toBeNull", function() {
- return this.be.null;
- });
- def("toBeDefined", function() {
- const negate = utils.flag(this, "negate");
- utils.flag(this, "negate", false);
- if (negate)
- return this.be.undefined;
- return this.not.be.undefined;
- });
- 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);
- });
- 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.prototype.hasOwnProperty.call(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));
- 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}`,
- actual
- );
- });
- def("toBeCloseTo", function(received, precision = 2) {
- const expected = this._obj;
- let pass = false;
- let expectedDiff = 0;
- let receivedDiff = 0;
- if (received === Infinity && expected === Infinity) {
- pass = true;
- } else if (received === -Infinity && expected === -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
- );
- });
- const assertIsMock = (assertion) => {
- if (!isMockFunction(assertion._obj))
- throw new TypeError(`${utils.inspect(assertion._obj)} is not a spy or a call to a spy!`);
- };
- const getSpy = (assertion) => {
- assertIsMock(assertion);
- return assertion._obj;
- };
- const 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`;
- };
- const formatCalls = (spy, msg, actualCall) => {
- msg += c().gray(`
-
- Received:
- ${spy.mock.calls.map((callArg, i) => {
- let methodCall = c().bold(` ${ordinalOf(i + 1)} ${spy.getMockName()} call:
-
- `);
- if (actualCall)
- methodCall += diff(callArg, actualCall, { showLegend: false });
- else
- methodCall += stringify(callArg).split("\n").map((line) => ` ${line}`).join("\n");
- methodCall += "\n";
- return methodCall;
- }).join("\n")}`);
- msg += c().gray(`
-
- Number of calls: ${c().bold(spy.mock.calls.length)}
- `);
- return msg;
- };
- const formatReturns = (spy, msg, actualReturn) => {
- msg += c().gray(`
-
- Received:
- ${spy.mock.results.map((callReturn, i) => {
- let methodCall = c().bold(` ${ordinalOf(i + 1)} ${spy.getMockName()} call return:
-
- `);
- if (actualReturn)
- methodCall += diff(callReturn.value, actualReturn, { showLegend: false });
- else
- methodCall += stringify(callReturn).split("\n").map((line) => ` ${line}`).join("\n");
- methodCall += "\n";
- return methodCall;
- }).join("\n")}`);
- msg += c().gray(`
-
- Number of calls: ${c().bold(spy.mock.calls.length)}
- `);
- return msg;
- };
- 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`,
- `expected "${spyName}" to not be called #{exp} times`,
- number,
- callCount
- );
- });
- 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`,
- `expected "${spyName}" to not be called once`,
- 1,
- callCount
- );
- });
- def(["toHaveBeenCalled", "toBeCalled"], function() {
- const spy = getSpy(this);
- const spyName = spy.getMockName();
- const called = spy.mock.calls.length > 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`,
- true,
- called
- ]
- );
- if (called && isNot)
- msg = formatCalls(spy, msg);
- if (called && isNot || !called && !isNot) {
- const err = new Error(msg);
- err.name = "AssertionError";
- throw err;
- }
- });
- def(["toHaveBeenCalledWith", "toBeCalledWith"], function(...args) {
- const spy = getSpy(this);
- const spyName = spy.getMockName();
- const pass = spy.mock.calls.some((callArg) => equals(callArg, args, [iterableEquality]));
- const isNot = utils.flag(this, "negate");
- let 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) {
- msg = formatCalls(spy, msg, args);
- const err = new Error(msg);
- err.name = "AssertionError";
- throw err;
- }
- });
- def(["toHaveBeenNthCalledWith", "nthCalledWith"], function(times, ...args) {
- const spy = getSpy(this);
- const spyName = spy.getMockName();
- const nthCall = spy.mock.calls[times - 1];
- this.assert(
- equals(nthCall, args, [iterableEquality]),
- `expected ${ordinalOf(times)} "${spyName}" call to have been called with #{exp}`,
- `expected ${ordinalOf(times)} "${spyName}" call to not have been called with #{exp}`,
- args,
- nthCall
- );
- });
- def(["toHaveBeenLastCalledWith", "lastCalledWith"], function(...args) {
- const spy = getSpy(this);
- const spyName = spy.getMockName();
- const lastCall = spy.mock.calls[spy.calls.length - 1];
- this.assert(
- equals(lastCall, args, [iterableEquality]),
- `expected last "${spyName}" call to have been called with #{exp}`,
- `expected last "${spyName}" call to not have been called with #{exp}`,
- args,
- lastCall
- );
- });
- def(["toThrow", "toThrowError"], function(expected) {
- if (typeof expected === "string" || typeof expected === "undefined" || expected instanceof RegExp)
- return this.throws(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 {
- try {
- obj();
- } catch (err) {
- thrown = err;
- }
- }
- 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) {
- return this.assert(
- thrown && expected.message === thrown.message,
- `expected error to have message: ${expected.message}`,
- `expected error not to have message: ${expected.message}`,
- expected.message,
- thrown && thrown.message
- );
- }
- 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.toString(),
- thrown
- );
- }
- throw new Error(`"toThrow" expects string, RegExp, function, Error instance or asymmetric matcher, got "${typeof expected}"`);
- });
- def(["toHaveReturned", "toReturn"], function() {
- const spy = getSpy(this);
- const spyName = spy.getMockName();
- const calledAndNotThrew = spy.mock.calls.length > 0 && spy.mock.results.some(({ type }) => type !== "throw");
- this.assert(
- calledAndNotThrew,
- `expected "${spyName}" to be successfully called at least once`,
- `expected "${spyName}" to not be successfully called`,
- calledAndNotThrew,
- !calledAndNotThrew
- );
- });
- def(["toHaveReturnedTimes", "toReturnTimes"], function(times) {
- const spy = getSpy(this);
- const spyName = spy.getMockName();
- const successfulReturns = spy.mock.results.reduce((success, { type }) => type === "throw" ? success : ++success, 0);
- this.assert(
- successfulReturns === times,
- `expected "${spyName}" to be successfully called ${times} times`,
- `expected "${spyName}" to not be successfully called ${times} times`,
- `expected number of returns: ${times}`,
- `received number of returns: ${successfulReturns}`
- );
- });
- def(["toHaveReturnedWith", "toReturnWith"], function(value) {
- const spy = getSpy(this);
- const spyName = spy.getMockName();
- const pass = spy.mock.results.some(({ type, value: result }) => type === "return" && equals(value, result));
- const isNot = utils.flag(this, "negate");
- let msg = utils.getMessage(
- this,
- [
- pass,
- `expected "${spyName}" to return with: #{exp} at least once`,
- `expected "${spyName}" to not return with: #{exp}`,
- value
- ]
- );
- if (pass && isNot || !pass && !isNot) {
- msg = formatReturns(spy, msg, value);
- const err = new Error(msg);
- err.name = "AssertionError";
- throw err;
- }
- });
- def(["toHaveLastReturnedWith", "lastReturnedWith"], function(value) {
- const spy = getSpy(this);
- const spyName = spy.getMockName();
- const { value: lastResult } = spy.mock.results[spy.returns.length - 1];
- const pass = equals(lastResult, value);
- this.assert(
- pass,
- `expected last "${spyName}" call to return #{exp}`,
- `expected last "${spyName}" call to not return #{exp}`,
- value,
- lastResult
- );
- });
- def(["toHaveNthReturnedWith", "nthReturnedWith"], function(nthCall, value) {
- const spy = getSpy(this);
- const spyName = spy.getMockName();
- const isNot = utils.flag(this, "negate");
- const { type: callType, value: callResult } = spy.mock.results[nthCall - 1];
- const ordinalCall = `${ordinalOf(nthCall)} call`;
- if (!isNot && callType === "throw")
- chai.assert.fail(`expected ${ordinalCall} to return #{exp}, but instead it threw an error`);
- const nthCallReturn = equals(callResult, value);
- this.assert(
- nthCallReturn,
- `expected ${ordinalCall} "${spyName}" call to return #{exp}`,
- `expected ${ordinalCall} "${spyName}" call to not return #{exp}`,
- value,
- callResult
- );
- });
- def("toSatisfy", function(matcher, message) {
- return this.be.satisfy(matcher, message);
- });
- utils.addProperty(chai.Assertion.prototype, "resolves", function __VITEST_RESOLVES__() {
- utils.flag(this, "promise", "resolves");
- utils.flag(this, "error", new Error("resolves"));
- const obj = utils.flag(this, "object");
- if (typeof (obj == null ? 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 async (...args) => {
- return obj.then(
- (value) => {
- utils.flag(this, "object", value);
- return result.call(this, ...args);
- },
- (err) => {
- throw new Error(`promise rejected "${String(err)}" instead of resolving`);
- }
- );
- };
- }
- });
- return proxy;
- });
- utils.addProperty(chai.Assertion.prototype, "rejects", function __VITEST_REJECTS__() {
- utils.flag(this, "promise", "rejects");
- utils.flag(this, "error", new Error("rejects"));
- const obj = utils.flag(this, "object");
- const wrapper = typeof obj === "function" ? obj() : obj;
- if (typeof (wrapper == null ? 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 async (...args) => {
- return wrapper.then(
- (value) => {
- throw new Error(`promise resolved "${String(value)}" instead of rejecting`);
- },
- (err) => {
- utils.flag(this, "object", err);
- return result.call(this, ...args);
- }
- );
- };
- }
- });
- return proxy;
- });
- };
-
- const getMatcherState = (assertion, expect) => {
- const obj = assertion._obj;
- const isNot = util.flag(assertion, "negate");
- const promise = util.flag(assertion, "promise") || "";
- const jestUtils = {
- ...getMatcherUtils(),
- diff,
- stringify,
- iterableEquality,
- subsetEquality
- };
- const matcherState = {
- ...getState(expect),
- isNot,
- utils: jestUtils,
- promise,
- equals,
- suppressedErrors: []
- };
- return {
- state: matcherState,
- isNot,
- obj
- };
- };
- class JestExtendError extends Error {
- constructor(message, actual, expected) {
- super(message);
- this.actual = actual;
- this.expected = expected;
- }
- }
- function JestExtendPlugin(expect, matchers) {
- return (c, utils) => {
- Object.entries(matchers).forEach(([expectAssertionName, expectAssertion]) => {
- function expectWrapper(...args) {
- const { state, isNot, obj } = getMatcherState(this, expect);
- const result = expectAssertion.call(state, obj, ...args);
- if (result && typeof result === "object" && result instanceof Promise) {
- return result.then(({ pass: pass2, message: message2, actual: actual2, expected: expected2 }) => {
- if (pass2 && isNot || !pass2 && !isNot)
- throw new JestExtendError(message2(), actual2, expected2);
- });
- }
- const { pass, message, actual, expected } = result;
- if (pass && isNot || !pass && !isNot)
- throw new JestExtendError(message(), actual, expected);
- }
- utils.addMethod(globalThis[JEST_MATCHERS_OBJECT].matchers, expectAssertionName, expectWrapper);
- utils.addMethod(c.Assertion.prototype, expectAssertionName, expectWrapper);
- 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(String).join(", ")}>`;
- }
- }
- Object.defineProperty(expect, expectAssertionName, {
- configurable: true,
- enumerable: true,
- value: (...sample) => new CustomMatcher(false, ...sample),
- writable: true
- });
- Object.defineProperty(expect.not, expectAssertionName, {
- configurable: true,
- enumerable: true,
- value: (...sample) => new CustomMatcher(true, ...sample),
- writable: true
- });
- });
- };
- }
- const JestExtend = (chai, utils) => {
- utils.addMethod(chai.expect, "extend", (expect, expects) => {
- chai.use(JestExtendPlugin(expect, expects));
- });
- };
-
- export { Any, Anything, ArrayContaining, AsymmetricMatcher, GLOBAL_EXPECT, JEST_MATCHERS_OBJECT, JestAsymmetricMatchers, JestChaiExpect, JestExtend, MATCHERS_OBJECT, ObjectContaining, StringContaining, StringMatching, arrayBufferEquality, equals, fnNameFor, generateToBeMessage, getState, hasAsymmetric, hasProperty, isA, isAsymmetric, isImmutableUnorderedKeyed, isImmutableUnorderedSet, iterableEquality, setState, sparseArrayEquality, subsetEquality, typeEquality };
|