Skip to content

Commit

Permalink
fix(expect): align toEqual to jest (denoland#4246)
Browse files Browse the repository at this point in the history
  • Loading branch information
eryue0220 authored Jan 29, 2024
1 parent aad9999 commit 67fe57c
Show file tree
Hide file tree
Showing 15 changed files with 1,666 additions and 35 deletions.
6 changes: 4 additions & 2 deletions assert/assert_not_equals.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

import { CAN_NOT_DISPLAY } from "./_constants.ts";
import { equal } from "./equal.ts";
import { AssertionError } from "./assertion_error.ts";

Expand All @@ -25,12 +27,12 @@ export function assertNotEquals<T>(actual: T, expected: T, msg?: string) {
try {
actualString = String(actual);
} catch {
actualString = "[Cannot display]";
actualString = CAN_NOT_DISPLAY;
}
try {
expectedString = String(expected);
} catch {
expectedString = "[Cannot display]";
expectedString = CAN_NOT_DISPLAY;
}
const msgSuffix = msg ? `: ${msg}` : ".";
throw new AssertionError(
Expand Down
57 changes: 57 additions & 0 deletions expect/_assert_equals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

// This file is copied from `std/assert`.

import { AssertionError } from "../assert/assertion_error.ts";
import { red } from "../fmt/colors.ts";
import { CAN_NOT_DISPLAY } from "./_constants.ts";
import { buildMessage, diff, diffstr } from "./_diff.ts";
import { equal } from "./_equal.ts";
import { format } from "./_format.ts";
import { AssertEqualsOptions } from "./_types.ts";

/**
* Make an assertion that `actual` and `expected` are equal, deeply. If not
* deeply equal, then throw.
*
* Type parameter can be specified to ensure values under comparison have the
* same type.
*
* @example
* ```ts
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
*
* assertEquals("world", "world"); // Doesn't throw
* assertEquals("hello", "world"); // Throws
* ```
*
* Note: formatter option is experimental and may be removed in the future.
*/
export function assertEquals<T>(
actual: T,
expected: T,
options: AssertEqualsOptions = {},
) {
const { formatter = format, msg, strictCheck } = options;

if (equal(actual, expected, strictCheck)) {
return;
}
const msgSuffix = msg ? `: ${msg}` : ".";
let message = `Values are not equal${msgSuffix}`;

const actualString = formatter(actual);
const expectedString = formatter(expected);
try {
const stringDiff = (typeof actual === "string") &&
(typeof expected === "string");
const diffResult = stringDiff
? diffstr(actual as string, expected as string)
: diff(actualString.split("\n"), expectedString.split("\n"));
const diffMsg = buildMessage(diffResult, { stringDiff }).join("\n");
message = `${message}\n${diffMsg}`;
} catch {
message = `${message}\n${red(CAN_NOT_DISPLAY)} + \n\n`;
}
throw new AssertionError(message);
}
223 changes: 223 additions & 0 deletions expect/_assert_equals_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

// This file is copied from `std/assert`.

import { AssertionError, assertThrows } from "../assert/mod.ts";
import {
bold,
gray,
green,
red,
stripAnsiCode,
yellow,
} from "../fmt/colors.ts";
import { assertEquals } from "./_assert_equals.ts";

const createHeader = (): string[] => [
"",
"",
` ${gray(bold("[Diff]"))} ${red(bold("Actual"))} / ${
green(
bold("Expected"),
)
}`,
"",
"",
];

const added: (s: string) => string = (s: string): string =>
green(bold(stripAnsiCode(s)));
const removed: (s: string) => string = (s: string): string =>
red(bold(stripAnsiCode(s)));

Deno.test({
name: "assertEquals() matches when values are equal",
fn() {
assertEquals({ a: 10 }, { a: 10 });
assertEquals(true, true);
assertEquals(10, 10);
assertEquals("abc", "abc");
assertEquals({ a: 10, b: { c: "1" } }, { a: 10, b: { c: "1" } });
assertEquals(new Date("invalid"), new Date("invalid"));
},
});

Deno.test({
name: "assertEquals() throws when numbers are not equal",
fn() {
assertThrows(
() => assertEquals(1, 2),
AssertionError,
[
"Values are not equal.",
...createHeader(),
removed(`- ${yellow("1")}`),
added(`+ ${yellow("2")}`),
"",
].join("\n"),
);
},
});

Deno.test({
name: "assertEquals() throws when types are not equal",
fn() {
assertThrows(
() => assertEquals<unknown>(1, "1"),
AssertionError,
[
"Values are not equal.",
...createHeader(),
removed(`- ${yellow("1")}`),
added(`+ "1"`),
].join("\n"),
);
},
});

Deno.test({
name: "assertEquals() throws when array elements are not equal",
fn() {
assertThrows(
() => assertEquals([1, "2", 3], ["1", "2", 3]),
AssertionError,
`
[
- 1,
+ "1",
"2",
3,
]`,
);
},
});

Deno.test({
name: "assertEquals() throws when object elements are not equal",
fn() {
assertThrows(
() => assertEquals({ a: 1, b: "2", c: 3 }, { a: 1, b: 2, c: [3] }),
AssertionError,
`
{
a: 1,
+ b: 2,
+ c: [
+ 3,
+ ],
- b: "2",
- c: 3,
}`,
);
},
});

Deno.test({
name: "assertEquals() throws when dates are not equal",
fn() {
assertThrows(
() =>
assertEquals(
new Date(2019, 0, 3, 4, 20, 1, 10),
new Date(2019, 0, 3, 4, 20, 1, 20),
),
AssertionError,
[
"Values are not equal.",
...createHeader(),
removed(`- ${new Date(2019, 0, 3, 4, 20, 1, 10).toISOString()}`),
added(`+ ${new Date(2019, 0, 3, 4, 20, 1, 20).toISOString()}`),
"",
].join("\n"),
);
assertThrows(
() =>
assertEquals(new Date("invalid"), new Date(2019, 0, 3, 4, 20, 1, 20)),
AssertionError,
[
"Values are not equal.",
...createHeader(),
removed(`- ${new Date("invalid")}`),
added(`+ ${new Date(2019, 0, 3, 4, 20, 1, 20).toISOString()}`),
"",
].join("\n"),
);
},
});

Deno.test({
name: "assertEquals() throws with given custom messages",
fn() {
assertThrows(
() => assertEquals(1, 2, { msg: "CUSTOM MESSAGE" }),
AssertionError,
[
"Values are not equal: CUSTOM MESSAGE",
...createHeader(),
removed(`- ${yellow("1")}`),
added(`+ ${yellow("2")}`),
"",
].join("\n"),
);
},
});

Deno.test(
"assertEquals() compares objects structurally if one object's constructor is undefined and the other is Object",
() => {
const a = Object.create(null);
a.prop = "test";
const b = {
prop: "test",
};

assertEquals(a, b);
assertEquals(b, a);
},
);

Deno.test("assertEquals() orders diff for differently ordered objects", () => {
assertThrows(
() => {
assertEquals(
{
aaaaaaaaaaaaaaaaaaaaaaaa: 0,
bbbbbbbbbbbbbbbbbbbbbbbb: 0,
ccccccccccccccccccccccc: 0,
},
{
ccccccccccccccccccccccc: 1,
aaaaaaaaaaaaaaaaaaaaaaaa: 0,
bbbbbbbbbbbbbbbbbbbbbbbb: 0,
},
);
},
AssertionError,
`
{
aaaaaaaaaaaaaaaaaaaaaaaa: 0,
bbbbbbbbbbbbbbbbbbbbbbbb: 0,
- ccccccccccccccccccccccc: 0,
+ ccccccccccccccccccccccc: 1,
}`,
);
});

Deno.test("assertEquals() matches same Set with object keys", () => {
const data = [
{
id: "_1p7ZED73OF98VbT1SzSkjn",
type: { id: "_ETGENUS" },
name: "Thuja",
friendlyId: "g-thuja",
},
{
id: "_567qzghxZmeQ9pw3q09bd3",
type: { id: "_ETGENUS" },
name: "Pinus",
friendlyId: "g-pinus",
},
];
assertEquals(data, data);
assertEquals(new Set(data), new Set(data));
});
51 changes: 51 additions & 0 deletions expect/_assert_not_equals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

// This file is copied from `std/assert`.

import { AssertionError } from "../assert/assertion_error.ts";
import { CAN_NOT_DISPLAY } from "./_constants.ts";
import { equal } from "./_equal.ts";
import { AssertEqualsOptions } from "./_types.ts";

type AssertNotEqualsOptions = Omit<AssertEqualsOptions, "formatter">;

/**
* Make an assertion that `actual` and `expected` are not equal, deeply.
* If not then throw.
*
* Type parameter can be specified to ensure values under comparison have the same type.
*
* @example
* ```ts
* import { assertNotEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_not_equals.ts";
*
* assertNotEquals(1, 2); // Doesn't throw
* assertNotEquals(1, 1); // Throws
* ```
*/
export function assertNotEquals<T>(
actual: T,
expected: T,
options: AssertNotEqualsOptions = {},
) {
const { msg, strictCheck } = options;
if (!equal(actual, expected, strictCheck)) {
return;
}
let actualString: string;
let expectedString: string;
try {
actualString = String(actual);
} catch {
actualString = CAN_NOT_DISPLAY;
}
try {
expectedString = String(expected);
} catch {
expectedString = CAN_NOT_DISPLAY;
}
const msgSuffix = msg ? `: ${msg}` : ".";
throw new AssertionError(
`Expected actual: ${actualString} not to be: ${expectedString}${msgSuffix}`,
);
}
28 changes: 28 additions & 0 deletions expect/_assert_not_equals_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

// This file is copied from `std/assert`.

import { assert, AssertionError } from "../assert/mod.ts";
import { assertEquals } from "./_assert_equals.ts";
import { assertNotEquals } from "./_assert_not_equals.ts";

Deno.test("NotEquals", function () {
const a = { foo: "bar" };
const b = { bar: "foo" };
assertNotEquals<unknown>(a, b);
assertNotEquals("Denosaurus", "Tyrannosaurus");
assertNotEquals(
new Date(2019, 0, 3, 4, 20, 1, 10),
new Date(2019, 0, 3, 4, 20, 1, 20),
);
assertNotEquals(new Date("invalid"), new Date(2019, 0, 3, 4, 20, 1, 20));
let didThrow;
try {
assertNotEquals("Raptor", "Raptor");
didThrow = false;
} catch (e) {
assert(e instanceof AssertionError);
didThrow = true;
}
assertEquals(didThrow, true);
});
4 changes: 4 additions & 0 deletions expect/_constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

// This file is copied from `std/assert`.
export const CAN_NOT_DISPLAY = "[Cannot display]";
Loading

0 comments on commit 67fe57c

Please sign in to comment.