Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add std/expect #3814

Merged
merged 17 commits into from
Nov 21, 2023
13 changes: 13 additions & 0 deletions expect/_inspect_args.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
// deno-lint-ignore-file

export function inspectArgs(args: unknown[]): string {
return args.map(inspectArg).join(", ");
}

export function inspectArg(arg: unknown): string {
const { Deno } = globalThis as any;
return typeof Deno !== "undefined" && Deno.inspect
? Deno.inspect(arg)
: String(arg);

Check warning on line 12 in expect/_inspect_args.ts

View check run for this annotation

Codecov / codecov/patch

expect/_inspect_args.ts#L11-L12

Added lines #L11 - L12 were not covered by tests
}
22 changes: 22 additions & 0 deletions expect/_mock_util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
// deno-lint-ignore-file no-explicit-any

export const MOCK_SYMBOL = Symbol.for("@MOCK");

export type MockCall = {
args: any[];
returned?: any;
thrown?: any;
timestamp: number;
returns: boolean;
throws: boolean;
};

export function getMockCalls(f: any): MockCall[] {
const mockInfo = f[MOCK_SYMBOL];
if (!mockInfo) {
throw new Error("Received function must be a mock or spy function");
}

Check warning on line 19 in expect/_mock_util.ts

View check run for this annotation

Codecov / codecov/patch

expect/_mock_util.ts#L18-L19

Added lines #L18 - L19 were not covered by tests

return [...mockInfo.calls];
}
13 changes: 13 additions & 0 deletions expect/_to_be.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { MatcherContext, MatchResult } from "./_types.ts";
import { assertNotStrictEquals } from "../assert/assert_not_strict_equals.ts";
import { assertStrictEquals } from "../assert/assert_strict_equals.ts";

export function toBe(context: MatcherContext, expect: unknown): MatchResult {
if (context.isNot) {
assertNotStrictEquals(context.value, expect, context.customMessage);
} else {
assertStrictEquals(context.value, expect, context.customMessage);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for splitting into so many small modules?

35 changes: 35 additions & 0 deletions expect/_to_be_close_to.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { MatcherContext, MatchResult } from "./_types.ts";
import { AssertionError } from "../assert/assertion_error.ts";

// TODO(kt3k): tolerance handling is wrong
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test that covers this tolerance?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, this has been already resolved in 357ecb3

export function toBeCloseTo(
context: MatcherContext,
expected: number,
numDigits = 2,
): MatchResult {
if (numDigits < 0) {
throw new Error(
"toBeCloseTo second argument must be a non-negative integer. Got " +
numDigits,

Check warning on line 15 in expect/_to_be_close_to.ts

View check run for this annotation

Codecov / codecov/patch

expect/_to_be_close_to.ts#L13-L15

Added lines #L13 - L15 were not covered by tests
);
}

Check warning on line 17 in expect/_to_be_close_to.ts

View check run for this annotation

Codecov / codecov/patch

expect/_to_be_close_to.ts#L17

Added line #L17 was not covered by tests
const tolerance = 0.5 * Math.pow(10, -numDigits);
const value = Number(context.value);
const pass = Math.abs(expected - value) < tolerance;

if (context.isNot) {
if (pass) {
throw new AssertionError(
`Expected the value not to be close to ${expected} (using ${numDigits} digits), but it is`,
);
}
} else {
if (!pass) {
throw new AssertionError(
`Expected the value (${value} to be close to ${expected} (using ${numDigits} digits), but it is not`,
);
}
}
}
21 changes: 21 additions & 0 deletions expect/_to_be_close_to_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { expect } from "./expect.ts";
import { AssertionError, assertThrows } from "../assert/mod.ts";

Deno.test("expect().toBeCloseTo()", () => {
expect(0.2 + 0.1).toBeCloseTo(0.3);
expect(0.2 + 0.1).toBeCloseTo(0.3, 5);
expect(0.2 + 0.1).toBeCloseTo(0.3, 15);

expect(0.2 + 0.11).not.toBeCloseTo(0.3);
expect(0.2 + 0.1).not.toBeCloseTo(0.3, 16);

assertThrows(() => {
expect(0.2 + 0.11).toBeCloseTo(0.3);
}, AssertionError);

assertThrows(() => {
expect(0.2 + 0.1).not.toBeCloseTo(0.3);
});
});
13 changes: 13 additions & 0 deletions expect/_to_be_defined.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { MatcherContext, MatchResult } from "./_types.ts";
import { assertNotStrictEquals } from "../assert/assert_not_strict_equals.ts";
import { assertStrictEquals } from "../assert/assert_strict_equals.ts";

export function toBeDefined(context: MatcherContext): MatchResult {
if (context.isNot) {
assertStrictEquals(context.value, undefined, context.customMessage);
} else {
assertNotStrictEquals(context.value, undefined, context.customMessage);
}
}
27 changes: 27 additions & 0 deletions expect/_to_be_defined_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
// deno-lint-ignore-file no-explicit-any

import { expect } from "./expect.ts";
import { AssertionError, assertThrows } from "../assert/mod.ts";

Deno.test("expect().toBeDefined()", () => {
expect(1).toBeDefined();
expect("a").toBeDefined();

expect(undefined).not.toBeDefined();
expect(({} as any).foo).not.toBeDefined();

assertThrows(() => {
expect(undefined).toBeDefined();
}, AssertionError);
assertThrows(() => {
expect(({} as any).foo).toBeDefined();
}, AssertionError);

assertThrows(() => {
expect(1).not.toBeDefined();
}, AssertionError);
assertThrows(() => {
expect("a").not.toBeDefined();
}, AssertionError);
});
23 changes: 23 additions & 0 deletions expect/_to_be_falsy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { MatcherContext, MatchResult } from "./_types.ts";
import { AssertionError } from "../assert/assertion_error.ts";

export function toBeFalsy(
context: MatcherContext,
): MatchResult {
const isFalsy = !(context.value);
if (context.isNot) {
if (isFalsy) {
throw new AssertionError(
`Expected ${context.value} to NOT be falsy`,
);
}
} else {
if (!isFalsy) {
throw new AssertionError(
`Expected ${context.value} to be falsy`,
);
}
}
}
34 changes: 34 additions & 0 deletions expect/_to_be_falsy_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { expect } from "./expect.ts";
import { AssertionError, assertThrows } from "../assert/mod.ts";

Deno.test("expect().toBeFalsy()", () => {
expect(false).toBeFalsy();
expect(0).toBeFalsy();
expect("").toBeFalsy();

expect(true).not.toBeFalsy();
expect(1).not.toBeFalsy();
expect("hello").not.toBeFalsy();

assertThrows(() => {
expect(true).toBeFalsy();
}, AssertionError);
assertThrows(() => {
expect(1).toBeFalsy();
}, AssertionError);
assertThrows(() => {
expect("hello").toBeFalsy();
}, AssertionError);

assertThrows(() => {
expect(false).not.toBeFalsy();
}, AssertionError);
assertThrows(() => {
expect(0).not.toBeFalsy();
}, AssertionError);
assertThrows(() => {
expect("").not.toBeFalsy();
}, AssertionError);
});
24 changes: 24 additions & 0 deletions expect/_to_be_greater_than.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { MatcherContext, MatchResult } from "./_types.ts";
import { AssertionError } from "../assert/assertion_error.ts";

export function toBeGreaterThan(
context: MatcherContext,
expected: number,
): MatchResult {
const isGreater = Number(context.value) > Number(expected);
if (context.isNot) {
if (isGreater) {
throw new AssertionError(
`Expected ${context.value} to NOT be greater than ${expected}`,
);
}
} else {
if (!isGreater) {
throw new AssertionError(
`Expected ${context.value} to be greater than ${expected}`,
);
}
}
}
24 changes: 24 additions & 0 deletions expect/_to_be_greater_than_or_equal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { MatcherContext, MatchResult } from "./_types.ts";
import { AssertionError } from "../assert/assertion_error.ts";

export function toBeGreaterThanOrEqual(
context: MatcherContext,
expected: number,
): MatchResult {
const isGreaterOrEqual = Number(context.value) >= Number(expected);
if (context.isNot) {
if (isGreaterOrEqual) {
throw new AssertionError(
`Expected ${context.value} to NOT be greater than or equal ${expected}`,
);
}
} else {
if (!isGreaterOrEqual) {
throw new AssertionError(
`Expected ${context.value} to be greater than or equal ${expected}`,
);
}
}
}
19 changes: 19 additions & 0 deletions expect/_to_be_greater_than_or_equal_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { expect } from "./expect.ts";
import { AssertionError, assertThrows } from "../assert/mod.ts";

Deno.test("expect().toBeGreaterThanOrEqual()", () => {
expect(10).toBeGreaterThanOrEqual(10);
expect(11).toBeGreaterThanOrEqual(10);

expect(9).not.toBeGreaterThanOrEqual(10);

assertThrows(() => {
expect(9).toBeGreaterThanOrEqual(10);
}, AssertionError);

assertThrows(() => {
expect(11).not.toBeGreaterThanOrEqual(10);
}, AssertionError);
});
22 changes: 22 additions & 0 deletions expect/_to_be_greater_than_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { expect } from "./expect.ts";
import { AssertionError, assertThrows } from "../assert/mod.ts";

Deno.test("expect().toBeGreaterThan()", () => {
expect(11).toBeGreaterThan(10);

expect(10).not.toBeGreaterThan(10);
expect(9).not.toBeGreaterThan(10);

assertThrows(() => {
expect(10).toBeGreaterThan(10);
}, AssertionError);
assertThrows(() => {
expect(9).toBeGreaterThan(10);
});

assertThrows(() => {
expect(11).not.toBeGreaterThan(10);
}, AssertionError);
});
16 changes: 16 additions & 0 deletions expect/_to_be_instance_of.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { AnyConstructor, MatcherContext, MatchResult } from "./_types.ts";
import { assertInstanceOf } from "../assert/assert_instance_of.ts";
import { assertNotInstanceOf } from "../assert/assert_not_instance_of.ts";

export function toBeInstanceOf<T extends AnyConstructor>(
context: MatcherContext,
expected: T,
): MatchResult {
if (context.isNot) {
assertNotInstanceOf(context.value, expected);
} else {
assertInstanceOf(context.value, expected);
}
}
22 changes: 22 additions & 0 deletions expect/_to_be_instance_of_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { expect } from "./expect.ts";
import { AssertionError, assertThrows } from "../assert/mod.ts";

Deno.test("expect().toBeInstanceOf", () => {
expect(new Error()).toBeInstanceOf(Error);
expect(new Error()).toBeInstanceOf(Object);

expect(new Error()).not.toBeInstanceOf(String);

assertThrows(() => {
expect(new Error()).toBeInstanceOf(String);
}, AssertionError);

assertThrows(() => {
expect(new Error()).not.toBeInstanceOf(Error);
}, AssertionError);
assertThrows(() => {
expect(new Error()).not.toBeInstanceOf(Object);
}, AssertionError);
});
24 changes: 24 additions & 0 deletions expect/_to_be_less_than.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { MatcherContext, MatchResult } from "./_types.ts";
import { AssertionError } from "../assert/assertion_error.ts";

export function toBeLessThan(
context: MatcherContext,
expected: number,
): MatchResult {
const isLower = Number(context.value) < Number(expected);
if (context.isNot) {
if (isLower) {
throw new AssertionError(
`Expected ${context.value} to NOT be lower than ${expected}`,
);
}
} else {
if (!isLower) {
throw new AssertionError(
`Expected ${context.value} to be lower than ${expected}`,
);
}
}
}
24 changes: 24 additions & 0 deletions expect/_to_be_less_than_or_equal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { MatcherContext, MatchResult } from "./_types.ts";
import { AssertionError } from "../assert/assertion_error.ts";

export function toBeLessThanOrEqual(
context: MatcherContext,
expected: number,
): MatchResult {
const isLower = Number(context.value) <= Number(expected);
if (context.isNot) {
if (isLower) {
throw new AssertionError(
`Expected ${context.value} to NOT be lower than or equal ${expected}`,
);
}
} else {
if (!isLower) {
throw new AssertionError(
`Expected ${context.value} to be lower than or equal ${expected}`,
);
}
}
}