mirror of
https://github.com/denoland/std.git
synced 2024-11-21 20:50:22 +00:00
fix(expect): support expect.objectContaining
(#6065)
Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
This commit is contained in:
parent
a541fb468c
commit
ae7048f9ca
@ -1,6 +1,8 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// deno-lint-ignore-file no-explicit-any
|
||||
|
||||
import { equal } from "./_equal.ts";
|
||||
|
||||
export abstract class AsymmetricMatcher<T> {
|
||||
constructor(
|
||||
protected value: T,
|
||||
@ -145,3 +147,31 @@ export class StringMatching extends AsymmetricMatcher<RegExp> {
|
||||
export function stringMatching(pattern: string | RegExp): StringMatching {
|
||||
return new StringMatching(pattern);
|
||||
}
|
||||
|
||||
export class ObjectContaining
|
||||
extends AsymmetricMatcher<Record<string, unknown>> {
|
||||
constructor(obj: Record<string, unknown>) {
|
||||
super(obj);
|
||||
}
|
||||
|
||||
equals(other: Record<string, unknown>): boolean {
|
||||
const keys = Object.keys(this.value);
|
||||
|
||||
for (const key of keys) {
|
||||
if (
|
||||
!Object.hasOwn(other, key) ||
|
||||
!equal(this.value[key], other[key])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export function objectContaining(
|
||||
obj: Record<string, unknown>,
|
||||
): ObjectContaining {
|
||||
return new ObjectContaining(obj);
|
||||
}
|
||||
|
50
expect/_object_containing_test.ts
Normal file
50
expect/_object_containing_test.ts
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { Buffer } from "node:buffer";
|
||||
import { Buffer as DenoBuffer } from "@std/io/buffer";
|
||||
import { expect } from "./expect.ts";
|
||||
|
||||
Deno.test("expect.objectContaining()", () => {
|
||||
expect({ bar: "baz" }).toEqual(expect.objectContaining({ bar: "baz" }));
|
||||
expect({ foo: undefined }).toEqual(
|
||||
expect.objectContaining({ foo: undefined }),
|
||||
);
|
||||
expect({ bar: "baz" }).not.toEqual(expect.objectContaining({ foo: "bar" }));
|
||||
});
|
||||
|
||||
Deno.test("expect.objectContaining() with nested objects", () => {
|
||||
expect({ foo: { bar: "baz" } }).toEqual(
|
||||
expect.objectContaining({ foo: { bar: "baz" } }),
|
||||
);
|
||||
expect({ foo: { bar: "baz" } }).not.toEqual(
|
||||
expect.objectContaining({ foo: { bar: "bar" } }),
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("expect.objectContaining() with symbols", () => {
|
||||
const foo = Symbol("foo");
|
||||
expect({ [foo]: { bar: "baz" } }).toEqual(
|
||||
expect.objectContaining({ [foo]: { bar: "baz" } }),
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("expect.objectContaining() with nested arrays", () => {
|
||||
expect({ foo: ["bar", "baz"] }).toEqual(
|
||||
expect.objectContaining({ foo: ["bar", "baz"] }),
|
||||
);
|
||||
expect({ foo: ["bar", "baz"] }).not.toEqual(
|
||||
expect.objectContaining({ foo: ["bar", "bar"] }),
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("expect.objectContaining() with Node Buffer", () => {
|
||||
expect({ foo: Buffer.from("foo") }).toEqual(
|
||||
expect.objectContaining({ foo: Buffer.from("foo") }),
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("expect.objectContaining() with Deno Buffer", () => {
|
||||
expect({ foo: new DenoBuffer([1, 2, 3]) }).toEqual(
|
||||
expect.objectContaining({ foo: new DenoBuffer([1, 2, 3]) }),
|
||||
);
|
||||
});
|
@ -509,3 +509,21 @@ expect.stringMatching = asymmetricMatchers.stringMatching as (
|
||||
* ```
|
||||
*/
|
||||
expect.hasAssertions = hasAssertions as () => void;
|
||||
/**
|
||||
* `expect.objectContaining(object)` matches any received object that recursively matches the expected properties.
|
||||
* That is, the expected object is not a subset of the received object. Therefore, it matches a received object
|
||||
* which contains properties that are not in the expected object.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { expect } from "@std/expect";
|
||||
*
|
||||
* Deno.test("example", () => {
|
||||
* expect({ bar: 'baz' }).toEqual(expect.objectContaining({ bar: 'bar'}));
|
||||
* expect({ bar: 'baz' }).not.toEqual(expect.objectContaining({ foo: 'bar'}));
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
expect.objectContaining = asymmetricMatchers.objectContaining as (
|
||||
obj: Record<string, unknown>,
|
||||
) => ReturnType<typeof asymmetricMatchers.objectContaining>;
|
||||
|
@ -54,6 +54,7 @@
|
||||
* - {@linkcode expect.anything}
|
||||
* - {@linkcode expect.any}
|
||||
* - {@linkcode expect.arrayContaining}
|
||||
* - {@linkcode expect.objectContaining}
|
||||
* - {@linkcode expect.closeTo}
|
||||
* - {@linkcode expect.stringContaining}
|
||||
* - {@linkcode expect.stringMatching}
|
||||
@ -69,7 +70,6 @@
|
||||
* - `toThrowErrorMatchingSnapshot`
|
||||
* - `toThrowErrorMatchingInlineSnapshot`
|
||||
* - Asymmetric matchers:
|
||||
* - `expect.objectContaining`
|
||||
* - `expect.not.objectContaining`
|
||||
* - Utilities:
|
||||
* - `expect.assertions`
|
||||
|
Loading…
Reference in New Issue
Block a user