mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 09:31:22 -05:00
parent
8dd76af9ab
commit
7cb7b24537
3 changed files with 273 additions and 12 deletions
|
@ -1,14 +1,41 @@
|
|||
# Testing
|
||||
|
||||
This module provides a few basic utilities to make testing easier and
|
||||
consistent in Deno.
|
||||
|
||||
## Usage
|
||||
|
||||
The module exports a `test` function which is the test harness in Deno. It
|
||||
accepts either a function (including async functions) or an object which
|
||||
contains a `name` property and a `fn` property. When running tests and
|
||||
outputting the results, the name of the past function is used, or if the
|
||||
object is passed, the `name` property is used to identify the test.
|
||||
|
||||
The module also exports `assert`, `assertEqual`, and `equal`.
|
||||
|
||||
`equal` is a deep comparision function, where `actual` and `expected` are
|
||||
compared deeply, and if they vary, `equal` returns `false`.
|
||||
|
||||
The export `assert` is a function, but it is also decorated with other useful
|
||||
functions:
|
||||
|
||||
- `assert()` - Expects a boolean value, throws if the value is `false`.
|
||||
- `assert.equal()` - Uses the `equal` comparison and throws if the `actual` and
|
||||
`expected` are not equal.
|
||||
- `assert.strictEqual()` - Compares `actual` and `expected` strictly, therefore
|
||||
for non-primitives the values must reference the same instance.
|
||||
- `assert.throws()` - Expects the passed `fn` to throw. If `fn` does not throw,
|
||||
this function does. Also compares any errors thrown to an optional expected
|
||||
`Error` class and checks that the error `.message` includes an optional
|
||||
string.
|
||||
|
||||
`assertEqual()` is the same as `assert.equal()` but maintained for backwards
|
||||
compatibility.
|
||||
|
||||
Basic usage:
|
||||
|
||||
```ts
|
||||
import {
|
||||
test,
|
||||
assert,
|
||||
equal,
|
||||
assertEqual
|
||||
} from "https://deno.land/x/testing/mod.ts";
|
||||
import { test, assert, equal } from "https://deno.land/x/testing/mod.ts";
|
||||
|
||||
test({
|
||||
name: "testing example",
|
||||
|
@ -17,8 +44,8 @@ test({
|
|||
assert(!equal("hello", "world"));
|
||||
assert(equal({ hello: "world" }, { hello: "world" }));
|
||||
assert(!equal({ world: "hello" }, { hello: "world" }));
|
||||
assertEqual("world", "world");
|
||||
assertEqual({ hello: "world" }, { hello: "world" });
|
||||
assert.equal("world", "world");
|
||||
assert.equal({ hello: "world" }, { hello: "world" });
|
||||
}
|
||||
});
|
||||
```
|
||||
|
@ -31,7 +58,51 @@ test(function example() {
|
|||
assert(!equal("hello", "world"));
|
||||
assert(equal({ hello: "world" }, { hello: "world" }));
|
||||
assert(!equal({ world: "hello" }, { hello: "world" }));
|
||||
assertEqual("world", "world");
|
||||
assertEqual({ hello: "world" }, { hello: "world" });
|
||||
assert.equal("world", "world");
|
||||
assert.equal({ hello: "world" }, { hello: "world" });
|
||||
});
|
||||
```
|
||||
|
||||
Using `assert.strictEqual()`:
|
||||
|
||||
```ts
|
||||
test(function isStrictlyEqual() {
|
||||
const a = {};
|
||||
const b = a;
|
||||
assert.strictEqual(a, b);
|
||||
});
|
||||
|
||||
// This test fails
|
||||
test(function isNotStrictlyEqual() {
|
||||
const a = {};
|
||||
const b = {};
|
||||
assert.strictEqual(a, b);
|
||||
});
|
||||
```
|
||||
|
||||
Using `assert.throws()`:
|
||||
|
||||
```ts
|
||||
test(function doesThrow() {
|
||||
assert.throws(() => {
|
||||
throw new TypeError("hello world!");
|
||||
});
|
||||
assert.throws(() => {
|
||||
throw new TypeError("hello world!");
|
||||
}, TypeError);
|
||||
assert.throws(
|
||||
() => {
|
||||
throw new TypeError("hello world!");
|
||||
},
|
||||
TypeError,
|
||||
"hello"
|
||||
);
|
||||
});
|
||||
|
||||
// This test will not pass
|
||||
test(function fails() {
|
||||
assert.throws(() => {
|
||||
console.log("Hello world");
|
||||
});
|
||||
});
|
||||
```
|
||||
|
|
|
@ -29,11 +29,95 @@ export function assertEqual(actual: unknown, expected: unknown, msg?: string) {
|
|||
}
|
||||
}
|
||||
|
||||
export function assert(expr: boolean, msg = "") {
|
||||
interface Constructor {
|
||||
new (...args: any[]): any;
|
||||
}
|
||||
|
||||
interface Assert {
|
||||
/** Make an assertion, if not true, then throw. */
|
||||
(expr: boolean, msg?: string): void;
|
||||
|
||||
/** Make an assertion that `actual` and `expected` are equal, deeply. If not
|
||||
* deeply equal, then throw.
|
||||
*/
|
||||
equal(actual: unknown, expected: unknown, msg?: string): void;
|
||||
|
||||
/** Make an assertion that `actual` and `expected` are strictly equal. If
|
||||
* not then throw.
|
||||
*/
|
||||
strictEqual(actual: unknown, expected: unknown, msg?: string): void;
|
||||
|
||||
/** Executes a function, expecting it to throw. If it does not, then it
|
||||
* throws. An error class and a string that should be included in the
|
||||
* error message can also be asserted.
|
||||
*/
|
||||
throws(fn: () => void, errorClass?: Constructor, msgIncludes?: string): void;
|
||||
}
|
||||
|
||||
export const assert = function assert(expr: boolean, msg = "") {
|
||||
if (!expr) {
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
} as Assert;
|
||||
|
||||
assert.equal = assertEqual;
|
||||
assert.strictEqual = function strictEqual(actual, expected, msg = "") {
|
||||
if (actual !== expected) {
|
||||
let actualString: string;
|
||||
let expectedString: string;
|
||||
try {
|
||||
actualString = String(actual);
|
||||
} catch (e) {
|
||||
actualString = "[Cannot display]";
|
||||
}
|
||||
try {
|
||||
expectedString = String(expected);
|
||||
} catch (e) {
|
||||
expectedString = "[Cannot display]";
|
||||
}
|
||||
console.error(
|
||||
"strictEqual failed. actual =",
|
||||
actualString,
|
||||
"expected =",
|
||||
expectedString
|
||||
);
|
||||
if (!msg) {
|
||||
msg = `actual: ${actualString} expected: ${expectedString}`;
|
||||
}
|
||||
throw new Error(msg);
|
||||
}
|
||||
};
|
||||
assert.throws = function throws(
|
||||
fn,
|
||||
ErrorClass: Constructor,
|
||||
msgIncludes = "",
|
||||
msg = ""
|
||||
) {
|
||||
let doesThrow = false;
|
||||
try {
|
||||
fn();
|
||||
} catch (e) {
|
||||
if (ErrorClass && !(Object.getPrototypeOf(e) === ErrorClass.prototype)) {
|
||||
msg = `Expected error to be instance of "${ErrorClass.name}"${
|
||||
msg ? `: ${msg}` : "."
|
||||
}`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
if (msgIncludes) {
|
||||
if (!e.message.includes(msgIncludes)) {
|
||||
msg = `Expected error message to include "${msgIncludes}", but got "${
|
||||
e.message
|
||||
}"${msg ? `: ${msg}` : "."}`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
doesThrow = true;
|
||||
}
|
||||
if (!doesThrow) {
|
||||
msg = `Expected function to throw${msg ? `: ${msg}` : "."}`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
};
|
||||
|
||||
export function equal(c: unknown, d: unknown): boolean {
|
||||
const seen = new Map();
|
||||
|
|
106
testing/test.ts
106
testing/test.ts
|
@ -28,6 +28,7 @@ test(function testingAssertEqual() {
|
|||
const a = Object.create(null);
|
||||
a.b = "foo";
|
||||
assertEqual(a, a);
|
||||
assert(assert.equal === assertEqual);
|
||||
});
|
||||
|
||||
test(function testingAssertEqualActualUncoercable() {
|
||||
|
@ -55,3 +56,108 @@ test(function testingAssertEqualExpectedUncoercable() {
|
|||
}
|
||||
assert(didThrow);
|
||||
});
|
||||
|
||||
test(function testingAssertStrictEqual() {
|
||||
const a = {};
|
||||
const b = a;
|
||||
assert.strictEqual(a, b);
|
||||
});
|
||||
|
||||
test(function testingAssertNotStrictEqual() {
|
||||
let didThrow = false;
|
||||
const a = {};
|
||||
const b = {};
|
||||
try {
|
||||
assert.strictEqual(a, b);
|
||||
} catch (e) {
|
||||
assert(e.message === "actual: [object Object] expected: [object Object]");
|
||||
didThrow = true;
|
||||
}
|
||||
assert(didThrow);
|
||||
});
|
||||
|
||||
test(function testingDoesThrow() {
|
||||
let count = 0;
|
||||
assert.throws(() => {
|
||||
count++;
|
||||
throw new Error();
|
||||
});
|
||||
assert(count === 1);
|
||||
});
|
||||
|
||||
test(function testingDoesNotThrow() {
|
||||
let count = 0;
|
||||
let didThrow = false;
|
||||
try {
|
||||
assert.throws(() => {
|
||||
count++;
|
||||
console.log("Hello world");
|
||||
});
|
||||
} catch (e) {
|
||||
assert(e.message === "Expected function to throw.");
|
||||
didThrow = true;
|
||||
}
|
||||
assert(count === 1);
|
||||
assert(didThrow);
|
||||
});
|
||||
|
||||
test(function testingThrowsErrorType() {
|
||||
let count = 0;
|
||||
assert.throws(() => {
|
||||
count++;
|
||||
throw new TypeError();
|
||||
}, TypeError);
|
||||
assert(count === 1);
|
||||
});
|
||||
|
||||
test(function testingThrowsNotErrorType() {
|
||||
let count = 0;
|
||||
let didThrow = false;
|
||||
try {
|
||||
assert.throws(() => {
|
||||
count++;
|
||||
throw new TypeError();
|
||||
}, RangeError);
|
||||
} catch (e) {
|
||||
assert(e.message === `Expected error to be instance of "RangeError".`);
|
||||
didThrow = true;
|
||||
}
|
||||
assert(count === 1);
|
||||
assert(didThrow);
|
||||
});
|
||||
|
||||
test(function testingThrowsMsgIncludes() {
|
||||
let count = 0;
|
||||
assert.throws(
|
||||
() => {
|
||||
count++;
|
||||
throw new TypeError("Hello world!");
|
||||
},
|
||||
TypeError,
|
||||
"world"
|
||||
);
|
||||
assert(count === 1);
|
||||
});
|
||||
|
||||
test(function testingThrowsMsgNotIncludes() {
|
||||
let count = 0;
|
||||
let didThrow = false;
|
||||
try {
|
||||
assert.throws(
|
||||
() => {
|
||||
count++;
|
||||
throw new TypeError("Hello world!");
|
||||
},
|
||||
TypeError,
|
||||
"foobar"
|
||||
);
|
||||
} catch (e) {
|
||||
assert(
|
||||
e.message ===
|
||||
`Expected error message to include "foobar", but got "Hello world!".`
|
||||
);
|
||||
didThrow = true;
|
||||
}
|
||||
assert(count === 1);
|
||||
assert(didThrow);
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue