mirror of
https://github.com/denoland/deno.git
synced 2024-12-26 00:59:24 -05:00
feat(test): Add more overloads for "Deno.test" (#12749)
This commit adds 4 more overloads to "Deno.test()" API. ``` // Deno.test(function testName() { }); export function test(fn: (t: TestContext) => void | Promise<void>): void; // Deno.test("test name", { only: true }, function() { }); export function test( name: string, options: Omit<TestDefinition, "name">, fn: (t: TestContext) => void | Promise<void>, ): void; // Deno.test({ name: "test name" }, function() { }); export function test( options: Omit<TestDefinition, "fn">, fn: (t: TestContext) => void | Promise<void>, ): void; // Deno.test({ only: true }, function testName() { }); export function test( options: Omit<TestDefinition, "fn" | "name">, fn: (t: TestContext) => void | Promise<void>, ): void; ```
This commit is contained in:
parent
ae34f8fa10
commit
d8afd56838
7 changed files with 246 additions and 27 deletions
93
cli/dts/lib.deno.ns.d.ts
vendored
93
cli/dts/lib.deno.ns.d.ts
vendored
|
@ -315,11 +315,11 @@ declare namespace Deno {
|
||||||
* ```ts
|
* ```ts
|
||||||
* import {assert, fail, assertEquals} from "https://deno.land/std/testing/asserts.ts";
|
* import {assert, fail, assertEquals} from "https://deno.land/std/testing/asserts.ts";
|
||||||
*
|
*
|
||||||
* Deno.test("My test description", ():void => {
|
* Deno.test("My test description", (): void => {
|
||||||
* assertEquals("hello", "hello");
|
* assertEquals("hello", "hello");
|
||||||
* });
|
* });
|
||||||
*
|
*
|
||||||
* Deno.test("My async test description", async ():Promise<void> => {
|
* Deno.test("My async test description", async (): Promise<void> => {
|
||||||
* const decoder = new TextDecoder("utf-8");
|
* const decoder = new TextDecoder("utf-8");
|
||||||
* const data = await Deno.readFile("hello_world.txt");
|
* const data = await Deno.readFile("hello_world.txt");
|
||||||
* assertEquals(decoder.decode(data), "Hello world");
|
* assertEquals(decoder.decode(data), "Hello world");
|
||||||
|
@ -331,6 +331,95 @@ declare namespace Deno {
|
||||||
fn: (t: TestContext) => void | Promise<void>,
|
fn: (t: TestContext) => void | Promise<void>,
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
|
/** Register a test which will be run when `deno test` is used on the command
|
||||||
|
* line and the containing module looks like a test module.
|
||||||
|
* `fn` can be async if required. Declared function must have a name.
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* import {assert, fail, assertEquals} from "https://deno.land/std/testing/asserts.ts";
|
||||||
|
*
|
||||||
|
* Deno.test(function myTestName(): void {
|
||||||
|
* assertEquals("hello", "hello");
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* Deno.test(async function myOtherTestName(): Promise<void> {
|
||||||
|
* const decoder = new TextDecoder("utf-8");
|
||||||
|
* const data = await Deno.readFile("hello_world.txt");
|
||||||
|
* assertEquals(decoder.decode(data), "Hello world");
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function test(fn: (t: TestContext) => void | Promise<void>): void;
|
||||||
|
|
||||||
|
/** Register a test which will be run when `deno test` is used on the command
|
||||||
|
* line and the containing module looks like a test module.
|
||||||
|
* `fn` can be async if required.
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* import {assert, fail, assertEquals} from "https://deno.land/std/testing/asserts.ts";
|
||||||
|
*
|
||||||
|
* Deno.test("My test description", { permissions: { read: true } }, (): void => {
|
||||||
|
* assertEquals("hello", "hello");
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* Deno.test("My async test description", { permissions: { read: false } }, async (): Promise<void> => {
|
||||||
|
* const decoder = new TextDecoder("utf-8");
|
||||||
|
* const data = await Deno.readFile("hello_world.txt");
|
||||||
|
* assertEquals(decoder.decode(data), "Hello world");
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function test(
|
||||||
|
name: string,
|
||||||
|
options: Omit<TestDefinition, "fn" | "name">,
|
||||||
|
fn: (t: TestContext) => void | Promise<void>,
|
||||||
|
): void;
|
||||||
|
|
||||||
|
/** Register a test which will be run when `deno test` is used on the command
|
||||||
|
* line and the containing module looks like a test module.
|
||||||
|
* `fn` can be async if required.
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* import {assert, fail, assertEquals} from "https://deno.land/std/testing/asserts.ts";
|
||||||
|
*
|
||||||
|
* Deno.test({ name: "My test description", permissions: { read: true } }, (): void => {
|
||||||
|
* assertEquals("hello", "hello");
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* Deno.test({ name: "My async test description", permissions: { read: false } }, async (): Promise<void> => {
|
||||||
|
* const decoder = new TextDecoder("utf-8");
|
||||||
|
* const data = await Deno.readFile("hello_world.txt");
|
||||||
|
* assertEquals(decoder.decode(data), "Hello world");
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function test(
|
||||||
|
options: Omit<TestDefinition, "fn">,
|
||||||
|
fn: (t: TestContext) => void | Promise<void>,
|
||||||
|
): void;
|
||||||
|
|
||||||
|
/** Register a test which will be run when `deno test` is used on the command
|
||||||
|
* line and the containing module looks like a test module.
|
||||||
|
* `fn` can be async if required. Declared function must have a name.
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* import {assert, fail, assertEquals} from "https://deno.land/std/testing/asserts.ts";
|
||||||
|
*
|
||||||
|
* Deno.test({ permissions: { read: true } }, function myTestName(): void {
|
||||||
|
* assertEquals("hello", "hello");
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* Deno.test({ permissions: { read: false } }, async function myOtherTestName(): Promise<void> {
|
||||||
|
* const decoder = new TextDecoder("utf-8");
|
||||||
|
* const data = await Deno.readFile("hello_world.txt");
|
||||||
|
* assertEquals(decoder.decode(data), "Hello world");
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function test(
|
||||||
|
options: Omit<TestDefinition, "fn" | "name">,
|
||||||
|
fn: (t: TestContext) => void | Promise<void>,
|
||||||
|
): void;
|
||||||
/** Exit the Deno process with optional exit code. If no exit code is supplied
|
/** Exit the Deno process with optional exit code. If no exit code is supplied
|
||||||
* then Deno will exit with return code of 0.
|
* then Deno will exit with return code of 0.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1016,29 +1016,29 @@ async fn test_resolve_dns() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn typecheck_declarations_ns() {
|
fn typecheck_declarations_ns() {
|
||||||
let status = util::deno_cmd()
|
let output = util::deno_cmd()
|
||||||
.arg("test")
|
.arg("test")
|
||||||
.arg("--doc")
|
.arg("--doc")
|
||||||
.arg(util::root_path().join("cli/dts/lib.deno.ns.d.ts"))
|
.arg(util::root_path().join("cli/dts/lib.deno.ns.d.ts"))
|
||||||
.spawn()
|
.output()
|
||||||
.unwrap()
|
|
||||||
.wait()
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(status.success());
|
println!("stdout: {}", String::from_utf8(output.stdout).unwrap());
|
||||||
|
println!("stderr: {}", String::from_utf8(output.stderr).unwrap());
|
||||||
|
assert!(output.status.success());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn typecheck_declarations_unstable() {
|
fn typecheck_declarations_unstable() {
|
||||||
let status = util::deno_cmd()
|
let output = util::deno_cmd()
|
||||||
.arg("test")
|
.arg("test")
|
||||||
.arg("--doc")
|
.arg("--doc")
|
||||||
.arg("--unstable")
|
.arg("--unstable")
|
||||||
.arg(util::root_path().join("cli/dts/lib.deno.unstable.d.ts"))
|
.arg(util::root_path().join("cli/dts/lib.deno.unstable.d.ts"))
|
||||||
.spawn()
|
.output()
|
||||||
.unwrap()
|
|
||||||
.wait()
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(status.success());
|
println!("stdout: {}", String::from_utf8(output.stdout).unwrap());
|
||||||
|
println!("stderr: {}", String::from_utf8(output.stderr).unwrap());
|
||||||
|
assert!(output.status.success());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -19,6 +19,12 @@ fn no_color() {
|
||||||
assert!(out.contains("test result: FAILED. 1 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out"));
|
assert!(out.contains("test result: FAILED. 1 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itest!(overloads {
|
||||||
|
args: "test test/overloads.ts",
|
||||||
|
exit_code: 0,
|
||||||
|
output: "test/overloads.out",
|
||||||
|
});
|
||||||
|
|
||||||
itest!(meta {
|
itest!(meta {
|
||||||
args: "test test/meta.ts",
|
args: "test test/meta.ts",
|
||||||
exit_code: 0,
|
exit_code: 0,
|
||||||
|
|
11
cli/tests/testdata/test/overloads.out
vendored
Normal file
11
cli/tests/testdata/test/overloads.out
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
Check [WILDCARD]/test/overloads.ts
|
||||||
|
running 6 tests from [WILDCARD]/test/overloads.ts
|
||||||
|
test test0 ... ok ([WILDCARD])
|
||||||
|
test test1 ... ok ([WILDCARD])
|
||||||
|
test test2 ... ok ([WILDCARD])
|
||||||
|
test test3 ... ok ([WILDCARD])
|
||||||
|
test test4 ... ok ([WILDCARD])
|
||||||
|
test test5 ... ignored ([WILDCARD])
|
||||||
|
|
||||||
|
test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out ([WILDCARD])
|
||||||
|
|
6
cli/tests/testdata/test/overloads.ts
vendored
Normal file
6
cli/tests/testdata/test/overloads.ts
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Deno.test("test0", () => {});
|
||||||
|
Deno.test(function test1() {});
|
||||||
|
Deno.test({ name: "test2", fn: () => {} });
|
||||||
|
Deno.test("test3", { permissions: "none" }, () => {});
|
||||||
|
Deno.test({ name: "test4" }, () => {});
|
||||||
|
Deno.test({ ignore: true }, function test5() {});
|
|
@ -1,9 +1,63 @@
|
||||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
import { assertRejects, assertThrows, unitTest } from "./test_util.ts";
|
import { assertRejects, assertThrows, unitTest } from "./test_util.ts";
|
||||||
|
|
||||||
unitTest(function testFnOverloading() {
|
unitTest(function testWrongOverloads() {
|
||||||
// just verifying that you can use this test definition syntax
|
assertThrows(
|
||||||
Deno.test("test fn overloading", () => {});
|
() => {
|
||||||
|
// @ts-ignore Testing invalid overloads
|
||||||
|
Deno.test("some name", { fn: () => {} }, () => {});
|
||||||
|
},
|
||||||
|
TypeError,
|
||||||
|
"Unexpected 'fn' field in options, test function is already provided as the third argument.",
|
||||||
|
);
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
|
// @ts-ignore Testing invalid overloads
|
||||||
|
Deno.test("some name", { name: "some name2" }, () => {});
|
||||||
|
},
|
||||||
|
TypeError,
|
||||||
|
"Unexpected 'name' field in options, test name is already provided as the first argument.",
|
||||||
|
);
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
|
// @ts-ignore Testing invalid overloads
|
||||||
|
Deno.test(() => {});
|
||||||
|
},
|
||||||
|
TypeError,
|
||||||
|
"The test function must have a name",
|
||||||
|
);
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
|
// @ts-ignore Testing invalid overloads
|
||||||
|
Deno.test(function foo() {}, {});
|
||||||
|
},
|
||||||
|
TypeError,
|
||||||
|
"Unexpected second argument to Deno.test()",
|
||||||
|
);
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
|
// @ts-ignore Testing invalid overloads
|
||||||
|
Deno.test({ fn: () => {} }, function foo() {});
|
||||||
|
},
|
||||||
|
TypeError,
|
||||||
|
"Unexpected 'fn' field in options, test function is already provided as the second argument.",
|
||||||
|
);
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
|
// @ts-ignore Testing invalid overloads
|
||||||
|
Deno.test({});
|
||||||
|
},
|
||||||
|
TypeError,
|
||||||
|
"Expected 'fn' field in the first argument to be a test function.",
|
||||||
|
);
|
||||||
|
assertThrows(
|
||||||
|
() => {
|
||||||
|
// @ts-ignore Testing invalid overloads
|
||||||
|
Deno.test({ fn: "boo!" });
|
||||||
|
},
|
||||||
|
TypeError,
|
||||||
|
"Expected 'fn' field in the first argument to be a test function.",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest(function nameOfTestCaseCantBeEmpty() {
|
unitTest(function nameOfTestCaseCantBeEmpty() {
|
||||||
|
|
|
@ -254,8 +254,9 @@ finishing test case.`;
|
||||||
|
|
||||||
// Main test function provided by Deno.
|
// Main test function provided by Deno.
|
||||||
function test(
|
function test(
|
||||||
t,
|
nameOrFnOrOptions,
|
||||||
fn,
|
optionsOrFn,
|
||||||
|
maybeFn,
|
||||||
) {
|
) {
|
||||||
let testDef;
|
let testDef;
|
||||||
const defaults = {
|
const defaults = {
|
||||||
|
@ -267,22 +268,74 @@ finishing test case.`;
|
||||||
permissions: null,
|
permissions: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof t === "string") {
|
if (typeof nameOrFnOrOptions === "string") {
|
||||||
if (!fn || typeof fn != "function") {
|
if (!nameOrFnOrOptions) {
|
||||||
throw new TypeError("Missing test function");
|
|
||||||
}
|
|
||||||
if (!t) {
|
|
||||||
throw new TypeError("The test name can't be empty");
|
throw new TypeError("The test name can't be empty");
|
||||||
}
|
}
|
||||||
testDef = { fn: fn, name: t, ...defaults };
|
if (typeof optionsOrFn === "function") {
|
||||||
|
testDef = { fn: optionsOrFn, name: nameOrFnOrOptions, ...defaults };
|
||||||
|
} else {
|
||||||
|
if (!maybeFn || typeof maybeFn !== "function") {
|
||||||
|
throw new TypeError("Missing test function");
|
||||||
|
}
|
||||||
|
if (optionsOrFn.fn != undefined) {
|
||||||
|
throw new TypeError(
|
||||||
|
"Unexpected 'fn' field in options, test function is already provided as the third argument.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (optionsOrFn.name != undefined) {
|
||||||
|
throw new TypeError(
|
||||||
|
"Unexpected 'name' field in options, test name is already provided as the first argument.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
testDef = {
|
||||||
|
...defaults,
|
||||||
|
...optionsOrFn,
|
||||||
|
fn: maybeFn,
|
||||||
|
name: nameOrFnOrOptions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else if (typeof nameOrFnOrOptions === "function") {
|
||||||
|
if (!nameOrFnOrOptions.name) {
|
||||||
|
throw new TypeError("The test function must have a name");
|
||||||
|
}
|
||||||
|
if (optionsOrFn != undefined) {
|
||||||
|
throw new TypeError("Unexpected second argument to Deno.test()");
|
||||||
|
}
|
||||||
|
if (maybeFn != undefined) {
|
||||||
|
throw new TypeError("Unexpected third argument to Deno.test()");
|
||||||
|
}
|
||||||
|
testDef = {
|
||||||
|
...defaults,
|
||||||
|
fn: nameOrFnOrOptions,
|
||||||
|
name: nameOrFnOrOptions.name,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
if (!t.fn) {
|
let fn;
|
||||||
throw new TypeError("Missing test function");
|
let name;
|
||||||
|
if (typeof optionsOrFn === "function") {
|
||||||
|
fn = optionsOrFn;
|
||||||
|
if (nameOrFnOrOptions.fn != undefined) {
|
||||||
|
throw new TypeError(
|
||||||
|
"Unexpected 'fn' field in options, test function is already provided as the second argument.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
name = nameOrFnOrOptions.name ?? fn.name;
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
!nameOrFnOrOptions.fn || typeof nameOrFnOrOptions.fn !== "function"
|
||||||
|
) {
|
||||||
|
throw new TypeError(
|
||||||
|
"Expected 'fn' field in the first argument to be a test function.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
fn = nameOrFnOrOptions.fn;
|
||||||
|
name = nameOrFnOrOptions.name ?? fn.name;
|
||||||
}
|
}
|
||||||
if (!t.name) {
|
if (!name) {
|
||||||
throw new TypeError("The test name can't be empty");
|
throw new TypeError("The test name can't be empty");
|
||||||
}
|
}
|
||||||
testDef = { ...defaults, ...t };
|
testDef = { ...defaults, ...nameOrFnOrOptions, fn, name };
|
||||||
}
|
}
|
||||||
|
|
||||||
testDef.fn = wrapTestFnWithSanitizers(testDef.fn, testDef);
|
testDef.fn = wrapTestFnWithSanitizers(testDef.fn, testDef);
|
||||||
|
|
Loading…
Reference in a new issue