0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00
Original: 9a3eb207dc
This commit is contained in:
Kitson Kelly 2019-01-16 13:57:40 +11:00 committed by Ryan Dahl
parent 8dd76af9ab
commit 7cb7b24537
3 changed files with 273 additions and 12 deletions

View file

@ -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");
});
});
```

View file

@ -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();

View file

@ -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);
});