mirror of
https://github.com/denoland/std.git
synced 2024-11-22 04:59:05 +00:00
feat(expect): add asymmetric matchers (any, anything, arrayContaining) (#4366)
This commit is contained in:
parent
1e0764dc23
commit
5d15ab7596
15
expect/_any_test.ts
Normal file
15
expect/_any_test.ts
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { expect } from "./expect.ts";
|
||||
|
||||
class Cat {}
|
||||
Deno.test("expect.any()", () => {
|
||||
expect(new Cat()).toEqual(expect.any(Cat));
|
||||
expect(new Cat()).toEqual(expect.any(Object));
|
||||
expect("Hello").toEqual(expect.any(String));
|
||||
expect(1).toEqual(expect.any(Number));
|
||||
expect(() => {}).toEqual(expect.any(Function));
|
||||
expect(false).toEqual(expect.any(Boolean));
|
||||
expect(BigInt(1)).toEqual(expect.any(BigInt));
|
||||
expect(Symbol("sym")).toEqual(expect.any(Symbol));
|
||||
});
|
27
expect/_anything_test.ts
Normal file
27
expect/_anything_test.ts
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { expect } from "./expect.ts";
|
||||
import { AssertionError, assertThrows } from "../assert/mod.ts";
|
||||
import { fn } from "./fn.ts";
|
||||
|
||||
Deno.test("expect.anything() as a parameter of toEqual()", () => {
|
||||
expect(null).not.toEqual(expect.anything());
|
||||
expect(undefined).not.toEqual(expect.anything());
|
||||
expect(1).toEqual(expect.anything());
|
||||
|
||||
assertThrows(() => {
|
||||
expect(null).toEqual(expect.anything());
|
||||
}, AssertionError);
|
||||
assertThrows(() => {
|
||||
expect(undefined).toEqual(expect.anything());
|
||||
}, AssertionError);
|
||||
assertThrows(() => {
|
||||
expect(1).not.toEqual(expect.anything());
|
||||
}, AssertionError);
|
||||
});
|
||||
|
||||
Deno.test("expect.anything() as a parameter of toHaveBeenCalled()", () => {
|
||||
const mockFn = fn();
|
||||
mockFn(3);
|
||||
expect(mockFn).toHaveBeenCalledWith(expect.anything());
|
||||
});
|
16
expect/_array_containing_test.ts
Normal file
16
expect/_array_containing_test.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { expect } from "./expect.ts";
|
||||
|
||||
Deno.test("expect.arrayContaining() with array of numbers", () => {
|
||||
const arr = [1, 2, 3];
|
||||
expect([1, 2, 3, 4]).toEqual(expect.arrayContaining(arr));
|
||||
expect([4, 5, 6]).not.toEqual(expect.arrayContaining(arr));
|
||||
expect([1, 2, 3]).toEqual(expect.arrayContaining(arr));
|
||||
});
|
||||
|
||||
Deno.test("expect.arrayContaining() with array of mixed types", () => {
|
||||
const arr = [1, 2, "hello"];
|
||||
expect([1, 2, 3, "hello", "bye"]).toEqual(expect.arrayContaining(arr));
|
||||
expect([4, "bye"]).not.toEqual(expect.arrayContaining(arr));
|
||||
});
|
79
expect/_asymmetric_matchers.ts
Normal file
79
expect/_asymmetric_matchers.ts
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// deno-lint-ignore-file no-explicit-any
|
||||
|
||||
abstract class AsymmetricMatcher<T> {
|
||||
constructor(
|
||||
protected value: T,
|
||||
) {}
|
||||
abstract equals(other: unknown): boolean;
|
||||
}
|
||||
|
||||
export class Anything extends AsymmetricMatcher<void> {
|
||||
equals(other: unknown): boolean {
|
||||
return other !== null && other !== undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function anything(): Anything {
|
||||
return new Anything();
|
||||
}
|
||||
|
||||
export class Any extends AsymmetricMatcher<any> {
|
||||
constructor(value: unknown) {
|
||||
if (value === undefined) {
|
||||
throw TypeError("Expected a constructor function");
|
||||
}
|
||||
super(value);
|
||||
}
|
||||
equals(other: unknown): boolean {
|
||||
if (typeof other === "object") {
|
||||
return other instanceof this.value;
|
||||
} else {
|
||||
if (this.value == Number) {
|
||||
return typeof other === "number";
|
||||
}
|
||||
|
||||
if (this.value == String) {
|
||||
return typeof other == "string";
|
||||
}
|
||||
|
||||
if (this.value == Number) {
|
||||
return typeof other == "number";
|
||||
}
|
||||
|
||||
if (this.value == Function) {
|
||||
return typeof other == "function";
|
||||
}
|
||||
|
||||
if (this.value == Boolean) {
|
||||
return typeof other == "boolean";
|
||||
}
|
||||
|
||||
if (this.value == BigInt) {
|
||||
return typeof other == "bigint";
|
||||
}
|
||||
|
||||
if (this.value == Symbol) {
|
||||
return typeof other == "symbol";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function any(c: unknown): Any {
|
||||
return new Any(c);
|
||||
}
|
||||
|
||||
export class ArrayContaining extends AsymmetricMatcher<any[]> {
|
||||
constructor(arr: any[]) {
|
||||
super(arr);
|
||||
}
|
||||
equals(other: any[]): boolean {
|
||||
return this.value.every((e) => other.includes(e));
|
||||
}
|
||||
}
|
||||
|
||||
export function arrayContaining(c: any[]): ArrayContaining {
|
||||
return new ArrayContaining(c);
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
// This file is copied from `std/assert`.
|
||||
|
||||
import type { EqualOptions } from "./_types.ts";
|
||||
import { Any, Anything, ArrayContaining } from "./_asymmetric_matchers.ts";
|
||||
|
||||
function isKeyedCollection(x: unknown): x is Set<unknown> {
|
||||
return [Symbol.iterator, "size"].every((k) => k in (x as Set<unknown>));
|
||||
@ -52,6 +53,15 @@ export function equal(c: unknown, d: unknown, options?: EqualOptions): boolean {
|
||||
) {
|
||||
return String(a) === String(b);
|
||||
}
|
||||
if (b instanceof Anything) {
|
||||
return b.equals(a);
|
||||
}
|
||||
if (b instanceof Any) {
|
||||
return b.equals(a);
|
||||
}
|
||||
if (b instanceof ArrayContaining && a instanceof Array) {
|
||||
return b.equals(a);
|
||||
}
|
||||
if (a instanceof Date && b instanceof Date) {
|
||||
const aTime = a.getTime();
|
||||
const bTime = b.getTime();
|
||||
@ -95,7 +105,7 @@ export function equal(c: unknown, d: unknown, options?: EqualOptions): boolean {
|
||||
if (!strictCheck) {
|
||||
if (aLen > 0) {
|
||||
for (let i = 0; i < aKeys.length; i += 1) {
|
||||
const key = aKeys[i];
|
||||
const key = aKeys[i]!;
|
||||
if (
|
||||
(key in a) && (a[key as keyof typeof a] === undefined) &&
|
||||
!(key in b)
|
||||
@ -107,7 +117,7 @@ export function equal(c: unknown, d: unknown, options?: EqualOptions): boolean {
|
||||
|
||||
if (bLen > 0) {
|
||||
for (let i = 0; i < bKeys.length; i += 1) {
|
||||
const key = bKeys[i];
|
||||
const key = bKeys[i]!;
|
||||
if (
|
||||
(key in b) && (b[key as keyof typeof b] === undefined) &&
|
||||
!(key in a)
|
||||
|
@ -47,6 +47,7 @@ import {
|
||||
toThrow,
|
||||
} from "./_matchers.ts";
|
||||
import { isPromiseLike } from "./_utils.ts";
|
||||
import { any, anything, arrayContaining } from "./_asymmetric_matchers.ts";
|
||||
|
||||
const matchers: Record<MatcherKey, Matcher> = {
|
||||
lastCalledWith: toHaveBeenLastCalledWith,
|
||||
@ -168,3 +169,6 @@ export function expect(value: unknown, customMessage?: string): Expected {
|
||||
}
|
||||
|
||||
expect.addEqualityTesters = addCustomEqualityTesters;
|
||||
expect.anything = anything;
|
||||
expect.any = any;
|
||||
expect.arrayContaining = arrayContaining;
|
||||
|
Loading…
Reference in New Issue
Block a user