From 147c845c95bfd55548d5b5b56d70f0a616410e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 6 Sep 2023 14:17:33 +0200 Subject: [PATCH] feat(test): Add Deno.test.ignore and Deno.test.only (#20365) Closes https://github.com/denoland/deno/issues/17106 --- cli/js/40_testing.js | 27 +- cli/lsp/testing/collectors.rs | 346 ++++++++++++++--------- cli/tests/testdata/test/ignore.ts | 10 +- cli/tests/testdata/test/only.out | 5 +- cli/tests/testdata/test/only.ts | 5 + cli/tsc/dts/lib.deno.ns.d.ts | 456 ++++++++++++++++++------------ 6 files changed, 538 insertions(+), 311 deletions(-) diff --git a/cli/js/40_testing.js b/cli/js/40_testing.js index afa9a65527..44b360a598 100644 --- a/cli/js/40_testing.js +++ b/cli/js/40_testing.js @@ -600,11 +600,11 @@ let currentBenchUserExplicitStart = null; /** @type {number | null} */ let currentBenchUserExplicitEnd = null; -// Main test function provided by Deno. -function test( +function testInner( nameOrFnOrOptions, optionsOrFn, maybeFn, + overrides = {}, ) { if (typeof ops.op_register_test != "function") { return; @@ -690,6 +690,8 @@ function test( testDesc = { ...defaults, ...nameOrFnOrOptions, fn, name }; } + testDesc = { ...testDesc, ...overrides }; + // Delete this prop in case the user passed it. It's used to detect steps. delete testDesc.parent; const jsError = core.destructureError(new Error()); @@ -721,6 +723,27 @@ function test( }); } +// Main test function provided by Deno. +function test( + nameOrFnOrOptions, + optionsOrFn, + maybeFn, +) { + return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn); +} + +test.ignore = function (nameOrFnOrOptions, optionsOrFn, maybeFn) { + return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { ignore: true }); +}; + +test.only = function ( + nameOrFnOrOptions, + optionsOrFn, + maybeFn, +) { + return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { only: true }); +}; + let registeredWarmupBench = false; // Main bench function provided by Deno. diff --git a/cli/lsp/testing/collectors.rs b/cli/lsp/testing/collectors.rs index f5f1ea0d1c..bc8eb65f10 100644 --- a/cli/lsp/testing/collectors.rs +++ b/cli/lsp/testing/collectors.rs @@ -379,54 +379,63 @@ impl Visit for TestStepCollector<'_> { fn visit_var_decl(&mut self, node: &ast::VarDecl) { if let Some(test_context) = &self.maybe_test_context { for decl in &node.decls { - if let Some(init) = &decl.init { - match init.as_ref() { - // Identify destructured assignments of `step` from test context - ast::Expr::Ident(ident) => { - if ident.sym == *test_context { - if let ast::Pat::Object(object_pat) = &decl.name { - for prop in &object_pat.props { - match prop { - ast::ObjectPatProp::Assign(prop) => { - if prop.key.sym.eq("step") { - self.vars.insert(prop.key.sym.to_string()); - } - } - ast::ObjectPatProp::KeyValue(prop) => { - if let ast::PropName::Ident(key_ident) = &prop.key { - if key_ident.sym.eq("step") { - if let ast::Pat::Ident(value_ident) = - &prop.value.as_ref() - { - self.vars.insert(value_ident.id.sym.to_string()); - } - } - } - } - _ => (), - } + let Some(init) = &decl.init else { + continue; + }; + + match init.as_ref() { + // Identify destructured assignments of `step` from test context + ast::Expr::Ident(ident) => { + if ident.sym != *test_context { + continue; + } + let ast::Pat::Object(object_pat) = &decl.name else { + continue; + }; + + for prop in &object_pat.props { + match prop { + ast::ObjectPatProp::Assign(prop) => { + if prop.key.sym.eq("step") { + self.vars.insert(prop.key.sym.to_string()); } } - } - } - // Identify variable assignments where the init is test context - // `.step` - ast::Expr::Member(member_expr) => { - if let ast::Expr::Ident(obj_ident) = member_expr.obj.as_ref() { - if obj_ident.sym == *test_context { - if let ast::MemberProp::Ident(prop_ident) = &member_expr.prop - { - if prop_ident.sym.eq("step") { - if let ast::Pat::Ident(binding_ident) = &decl.name { - self.vars.insert(binding_ident.id.sym.to_string()); + ast::ObjectPatProp::KeyValue(prop) => { + if let ast::PropName::Ident(key_ident) = &prop.key { + if key_ident.sym.eq("step") { + if let ast::Pat::Ident(value_ident) = &prop.value.as_ref() + { + self.vars.insert(value_ident.id.sym.to_string()); } } } } + _ => (), } } - _ => (), } + // Identify variable assignments where the init is test context + // `.step` + ast::Expr::Member(member_expr) => { + let ast::Expr::Ident(obj_ident) = member_expr.obj.as_ref() else { + continue; + }; + + if obj_ident.sym != *test_context { + continue; + } + + let ast::MemberProp::Ident(prop_ident) = &member_expr.prop else { + continue; + }; + + if prop_ident.sym.eq("step") { + if let ast::Pat::Ident(binding_ident) = &decl.name { + self.vars.insert(binding_ident.id.sym.to_string()); + } + } + } + _ => (), } } } @@ -463,95 +472,151 @@ impl TestCollector { impl Visit for TestCollector { fn visit_call_expr(&mut self, node: &ast::CallExpr) { - if let ast::Callee::Expr(callee_expr) = &node.callee { - match callee_expr.as_ref() { - ast::Expr::Ident(ident) => { - if self.vars.contains(&ident.sym.to_string()) { - visit_call_expr( - node, - Some(&self.fns), - source_range_to_lsp_range(&ident.range(), &self.text_info), - None, - &self.text_info, - &mut self.test_module, - ); - } + fn visit_if_deno_test( + collector: &mut TestCollector, + node: &ast::CallExpr, + range: &deno_ast::SourceRange, + ns_prop_ident: &ast::Ident, + member_expr: &ast::MemberExpr, + ) { + if ns_prop_ident.sym.to_string() == "test" { + let ast::Expr::Ident(ident) = member_expr.obj.as_ref() else { + return; + }; + + if ident.sym.to_string() != "Deno" { + return; } - ast::Expr::Member(member_expr) => { - if let ast::MemberProp::Ident(ns_prop_ident) = &member_expr.prop { - if ns_prop_ident.sym.to_string() == "test" { - if let ast::Expr::Ident(ident) = member_expr.obj.as_ref() { - if ident.sym.to_string() == "Deno" { - visit_call_expr( - node, - Some(&self.fns), - source_range_to_lsp_range( - &ns_prop_ident.range(), - &self.text_info, - ), - None, - &self.text_info, - &mut self.test_module, - ); - } - } - } - } - } - _ => (), + + visit_call_expr( + node, + Some(&collector.fns), + source_range_to_lsp_range(range, &collector.text_info), + None, + &collector.text_info, + &mut collector.test_module, + ); } } + + let ast::Callee::Expr(callee_expr) = &node.callee else { + return; + }; + + match callee_expr.as_ref() { + ast::Expr::Ident(ident) => { + if self.vars.contains(&ident.sym.to_string()) { + visit_call_expr( + node, + Some(&self.fns), + source_range_to_lsp_range(&ident.range(), &self.text_info), + None, + &self.text_info, + &mut self.test_module, + ); + } + } + ast::Expr::Member(member_expr) => { + let ast::MemberProp::Ident(ns_prop_ident) = &member_expr.prop else { + return; + }; + + let ns_prop_ident_name = ns_prop_ident.sym.to_string(); + + visit_if_deno_test( + self, + node, + &ns_prop_ident.range(), + ns_prop_ident, + member_expr, + ); + + if ns_prop_ident_name == "ignore" || ns_prop_ident_name == "only" { + let ast::Expr::Member(child_member_expr) = member_expr.obj.as_ref() + else { + return; + }; + + let ast::MemberProp::Ident(child_ns_prop_ident) = + &child_member_expr.prop + else { + return; + }; + + visit_if_deno_test( + self, + node, + &ns_prop_ident.range(), + child_ns_prop_ident, + child_member_expr, + ); + } + } + _ => (), + } } fn visit_var_decl(&mut self, node: &ast::VarDecl) { for decl in &node.decls { - if let Some(init) = &decl.init { - match init.as_ref() { - // Identify destructured assignments of `test` from `Deno` - ast::Expr::Ident(ident) => { - if ident.sym.to_string() == "Deno" { - if let ast::Pat::Object(object_pat) = &decl.name { - for prop in &object_pat.props { - match prop { - ast::ObjectPatProp::Assign(prop) => { - let name = prop.key.sym.to_string(); - if name == "test" { - self.vars.insert(name); - } - } - ast::ObjectPatProp::KeyValue(prop) => { - if let ast::PropName::Ident(key_ident) = &prop.key { - if key_ident.sym.to_string() == "test" { - if let ast::Pat::Ident(value_ident) = - &prop.value.as_ref() - { - self.vars.insert(value_ident.id.sym.to_string()); - } - } - } - } - _ => (), + let Some(init) = &decl.init else { continue }; + + match init.as_ref() { + // Identify destructured assignments of `test` from `Deno` + ast::Expr::Ident(ident) => { + if ident.sym.to_string() != "Deno" { + continue; + } + + let ast::Pat::Object(object_pat) = &decl.name else { + continue; + }; + + for prop in &object_pat.props { + match prop { + ast::ObjectPatProp::Assign(prop) => { + let name = prop.key.sym.to_string(); + if name == "test" { + self.vars.insert(name); + } + } + ast::ObjectPatProp::KeyValue(prop) => { + let ast::PropName::Ident(key_ident) = &prop.key else { + continue; + }; + + if key_ident.sym.to_string() == "test" { + if let ast::Pat::Ident(value_ident) = &prop.value.as_ref() { + self.vars.insert(value_ident.id.sym.to_string()); } } } + _ => (), } } - // Identify variable assignments where the init is `Deno.test` - ast::Expr::Member(member_expr) => { - if let ast::Expr::Ident(obj_ident) = member_expr.obj.as_ref() { - if obj_ident.sym.to_string() == "Deno" { - if let ast::MemberProp::Ident(prop_ident) = &member_expr.prop { - if prop_ident.sym.to_string() == "test" { - if let ast::Pat::Ident(binding_ident) = &decl.name { - self.vars.insert(binding_ident.id.sym.to_string()); - } - } - } - } - } - } - _ => (), } + // Identify variable assignments where the init is `Deno.test` + ast::Expr::Member(member_expr) => { + let ast::Expr::Ident(obj_ident) = member_expr.obj.as_ref() else { + continue; + }; + + if obj_ident.sym.to_string() != "Deno" { + continue; + }; + + let ast::MemberProp::Ident(prop_ident) = &member_expr.prop else { + continue; + }; + + if prop_ident.sym.to_string() != "test" { + continue; + } + + if let ast::Pat::Ident(binding_ident) = &decl.name { + self.vars.insert(binding_ident.id.sym.to_string()); + } + } + _ => (), } } } @@ -934,6 +999,8 @@ pub mod tests { let test_module = collect( r#" Deno.test(async function someFunction() {}); + Deno.test.ignore(function foo() {}); + Deno.test.only(function bar() {}); "#, ); @@ -942,20 +1009,41 @@ pub mod tests { &TestModule { specifier: test_module.specifier.clone(), script_version: test_module.script_version.clone(), - defs: vec![( - "e0f6a73647b763f82176c98a019e54200b799a32007f9859fb782aaa9e308568" - .to_string(), - TestDefinition { - id: - "e0f6a73647b763f82176c98a019e54200b799a32007f9859fb782aaa9e308568" - .to_string(), - name: "someFunction".to_string(), - range: Some(new_range(1, 11, 1, 15)), - is_dynamic: false, - parent_id: None, - step_ids: Default::default(), - } - ),] + defs: vec![ + ( + "87f28e06f5ddadd90a74a93b84df2e31b9edced8301b0ad4c8fbab8d806ec99d".to_string(), + TestDefinition { + id: "87f28e06f5ddadd90a74a93b84df2e31b9edced8301b0ad4c8fbab8d806ec99d".to_string(), + name: "foo".to_string(), + range: Some(new_range(2, 16, 2, 22)), + is_dynamic: false, + parent_id: None, + step_ids: Default::default(), + }, + ), + ( + "e0f6a73647b763f82176c98a019e54200b799a32007f9859fb782aaa9e308568".to_string(), + TestDefinition { + id: "e0f6a73647b763f82176c98a019e54200b799a32007f9859fb782aaa9e308568".to_string(), + name: "someFunction".to_string(), + range: Some(new_range(1, 11, 1, 15)), + is_dynamic: false, + parent_id: None, + step_ids: Default::default(), + } + ), + ( + "e1bd61cdaf5e64863d3d85baffe3e43bd57cdb8dc0b5d6a9e03ade18b7f68d47".to_string(), + TestDefinition { + id: "e1bd61cdaf5e64863d3d85baffe3e43bd57cdb8dc0b5d6a9e03ade18b7f68d47".to_string(), + name: "bar".to_string(), + range: Some(new_range(3, 16, 3, 20)), + is_dynamic: false, + parent_id: None, + step_ids: Default::default(), + } + ) + ] .into_iter() .collect(), } diff --git a/cli/tests/testdata/test/ignore.ts b/cli/tests/testdata/test/ignore.ts index 01113a1291..2339835db3 100644 --- a/cli/tests/testdata/test/ignore.ts +++ b/cli/tests/testdata/test/ignore.ts @@ -1,4 +1,4 @@ -for (let i = 0; i < 10; i++) { +for (let i = 0; i < 5; i++) { Deno.test({ name: `test ${i}`, ignore: true, @@ -7,3 +7,11 @@ for (let i = 0; i < 10; i++) { }, }); } +for (let i = 5; i < 10; i++) { + Deno.test.ignore({ + name: `test ${i}`, + fn() { + throw new Error("unreachable"); + }, + }); +} diff --git a/cli/tests/testdata/test/only.out b/cli/tests/testdata/test/only.out index bd5ca84e4c..2e66ed22b4 100644 --- a/cli/tests/testdata/test/only.out +++ b/cli/tests/testdata/test/only.out @@ -1,7 +1,8 @@ Check [WILDCARD]/test/only.ts -running 1 test from ./test/only.ts +running 2 tests from ./test/only.ts only ... ok ([WILDCARD]) +only2 ... ok ([WILDCARD]) -ok | 1 passed | 0 failed | 2 filtered out ([WILDCARD]) +ok | 2 passed | 0 failed | 2 filtered out ([WILDCARD]) error: Test failed because the "only" option was used diff --git a/cli/tests/testdata/test/only.ts b/cli/tests/testdata/test/only.ts index 03c4dcac33..26b4cd4257 100644 --- a/cli/tests/testdata/test/only.ts +++ b/cli/tests/testdata/test/only.ts @@ -9,6 +9,11 @@ Deno.test({ fn() {}, }); +Deno.test.only({ + name: "only2", + fn() {}, +}); + Deno.test({ name: "after", fn() {}, diff --git a/cli/tsc/dts/lib.deno.ns.d.ts b/cli/tsc/dts/lib.deno.ns.d.ts index de14c2f51c..5f1177da80 100644 --- a/cli/tsc/dts/lib.deno.ns.d.ts +++ b/cli/tsc/dts/lib.deno.ns.d.ts @@ -812,188 +812,290 @@ declare namespace Deno { permissions?: PermissionOptions; } - /** 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 { assertEquals } from "https://deno.land/std/testing/asserts.ts"; - * - * Deno.test({ - * name: "example test", - * fn() { - * assertEquals("world", "world"); - * }, - * }); - * - * Deno.test({ - * name: "example ignored test", - * ignore: Deno.build.os === "windows", - * fn() { - * // This test is ignored only on Windows machines - * }, - * }); - * - * Deno.test({ - * name: "example async test", - * async fn() { - * const decoder = new TextDecoder("utf-8"); - * const data = await Deno.readFile("hello_world.txt"); - * assertEquals(decoder.decode(data), "Hello world"); - * } - * }); - * ``` - * - * @category Testing - */ - export function test(t: TestDefinition): void; + export const test: DenoTest; - /** 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 { assertEquals } from "https://deno.land/std/testing/asserts.ts"; - * - * Deno.test("My test description", () => { - * assertEquals("hello", "hello"); - * }); - * - * Deno.test("My async test description", async () => { - * const decoder = new TextDecoder("utf-8"); - * const data = await Deno.readFile("hello_world.txt"); - * assertEquals(decoder.decode(data), "Hello world"); - * }); - * ``` - * - * @category Testing - */ - export function test( - name: string, - fn: (t: TestContext) => void | Promise, - ): void; + interface DenoTest { + /** 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 { assertEquals } from "https://deno.land/std/testing/asserts.ts"; + * + * Deno.test({ + * name: "example test", + * fn() { + * assertEquals("world", "world"); + * }, + * }); + * + * Deno.test({ + * name: "example ignored test", + * ignore: Deno.build.os === "windows", + * fn() { + * // This test is ignored only on Windows machines + * }, + * }); + * + * Deno.test({ + * name: "example async test", + * async fn() { + * const decoder = new TextDecoder("utf-8"); + * const data = await Deno.readFile("hello_world.txt"); + * assertEquals(decoder.decode(data), "Hello world"); + * } + * }); + * ``` + * + * @category Testing + */ + (t: TestDefinition): 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 { assertEquals } from "https://deno.land/std/testing/asserts.ts"; - * - * Deno.test(function myTestName() { - * assertEquals("hello", "hello"); - * }); - * - * Deno.test(async function myOtherTestName() { - * const decoder = new TextDecoder("utf-8"); - * const data = await Deno.readFile("hello_world.txt"); - * assertEquals(decoder.decode(data), "Hello world"); - * }); - * ``` - * - * @category Testing - */ - export function test(fn: (t: TestContext) => void | Promise): 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 { assertEquals } from "https://deno.land/std/testing/asserts.ts"; + * + * Deno.test("My test description", () => { + * assertEquals("hello", "hello"); + * }); + * + * Deno.test("My async test description", async () => { + * const decoder = new TextDecoder("utf-8"); + * const data = await Deno.readFile("hello_world.txt"); + * assertEquals(decoder.decode(data), "Hello world"); + * }); + * ``` + * + * @category Testing + */ + ( + name: string, + fn: (t: TestContext) => void | Promise, + ): 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 => { - * const decoder = new TextDecoder("utf-8"); - * const data = await Deno.readFile("hello_world.txt"); - * assertEquals(decoder.decode(data), "Hello world"); - * }); - * ``` - * - * @category Testing - */ - export function test( - name: string, - options: Omit, - fn: (t: TestContext) => void | Promise, - ): 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 { assertEquals } from "https://deno.land/std/testing/asserts.ts"; + * + * Deno.test(function myTestName() { + * assertEquals("hello", "hello"); + * }); + * + * Deno.test(async function myOtherTestName() { + * const decoder = new TextDecoder("utf-8"); + * const data = await Deno.readFile("hello_world.txt"); + * assertEquals(decoder.decode(data), "Hello world"); + * }); + * ``` + * + * @category Testing + */ + (fn: (t: TestContext) => void | Promise): 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 { assertEquals } from "https://deno.land/std/testing/asserts.ts"; - * - * Deno.test( - * { - * name: "My test description", - * permissions: { read: true }, - * }, - * () => { - * assertEquals("hello", "hello"); - * }, - * ); - * - * Deno.test( - * { - * name: "My async test description", - * permissions: { read: false }, - * }, - * async () => { - * const decoder = new TextDecoder("utf-8"); - * const data = await Deno.readFile("hello_world.txt"); - * assertEquals(decoder.decode(data), "Hello world"); - * }, - * ); - * ``` - * - * @category Testing - */ - export function test( - options: Omit, - fn: (t: TestContext) => void | Promise, - ): 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 => { + * const decoder = new TextDecoder("utf-8"); + * const data = await Deno.readFile("hello_world.txt"); + * assertEquals(decoder.decode(data), "Hello world"); + * }); + * ``` + * + * @category Testing + */ + ( + name: string, + options: Omit, + fn: (t: TestContext) => void | Promise, + ): 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 { assertEquals } from "https://deno.land/std/testing/asserts.ts"; - * - * Deno.test( - * { permissions: { read: true } }, - * function myTestName() { - * assertEquals("hello", "hello"); - * }, - * ); - * - * Deno.test( - * { permissions: { read: false } }, - * async function myOtherTestName() { - * const decoder = new TextDecoder("utf-8"); - * const data = await Deno.readFile("hello_world.txt"); - * assertEquals(decoder.decode(data), "Hello world"); - * }, - * ); - * ``` - * - * @category Testing - */ - export function test( - options: Omit, - fn: (t: TestContext) => void | Promise, - ): 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 { assertEquals } from "https://deno.land/std/testing/asserts.ts"; + * + * Deno.test( + * { + * name: "My test description", + * permissions: { read: true }, + * }, + * () => { + * assertEquals("hello", "hello"); + * }, + * ); + * + * Deno.test( + * { + * name: "My async test description", + * permissions: { read: false }, + * }, + * async () => { + * const decoder = new TextDecoder("utf-8"); + * const data = await Deno.readFile("hello_world.txt"); + * assertEquals(decoder.decode(data), "Hello world"); + * }, + * ); + * ``` + * + * @category Testing + */ + ( + options: Omit, + fn: (t: TestContext) => void | Promise, + ): 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 { assertEquals } from "https://deno.land/std/testing/asserts.ts"; + * + * Deno.test( + * { permissions: { read: true } }, + * function myTestName() { + * assertEquals("hello", "hello"); + * }, + * ); + * + * Deno.test( + * { permissions: { read: false } }, + * async function myOtherTestName() { + * const decoder = new TextDecoder("utf-8"); + * const data = await Deno.readFile("hello_world.txt"); + * assertEquals(decoder.decode(data), "Hello world"); + * }, + * ); + * ``` + * + * @category Testing + */ + ( + options: Omit, + fn: (t: TestContext) => void | Promise, + ): void; + + /** Shorthand property for ignoring a particular test case. + * + * @category Testing + */ + ignore(t: Omit): void; + + /** Shorthand property for ignoring a particular test case. + * + * @category Testing + */ + ignore( + name: string, + fn: (t: TestContext) => void | Promise, + ): void; + + /** Shorthand property for ignoring a particular test case. + * + * @category Testing + */ + ignore(fn: (t: TestContext) => void | Promise): void; + + /** Shorthand property for ignoring a particular test case. + * + * @category Testing + */ + ignore( + name: string, + options: Omit, + fn: (t: TestContext) => void | Promise, + ): void; + + /** Shorthand property for ignoring a particular test case. + * + * @category Testing + */ + ignore( + options: Omit, + fn: (t: TestContext) => void | Promise, + ): void; + + /** Shorthand property for ignoring a particular test case. + * + * @category Testing + */ + ignore( + options: Omit, + fn: (t: TestContext) => void | Promise, + ): void; + + /** Shorthand property for focusing a particular test case. + * + * @category Testing + */ + only(t: Omit): void; + + /** Shorthand property for focusing a particular test case. + * + * @category Testing + */ + only( + name: string, + fn: (t: TestContext) => void | Promise, + ): void; + + /** Shorthand property for focusing a particular test case. + * + * @category Testing + */ + only(fn: (t: TestContext) => void | Promise): void; + + /** Shorthand property for focusing a particular test case. + * + * @category Testing + */ + only( + name: string, + options: Omit, + fn: (t: TestContext) => void | Promise, + ): void; + + /** Shorthand property for focusing a particular test case. + * + * @category Testing + */ + only( + options: Omit, + fn: (t: TestContext) => void | Promise, + ): void; + + /** Shorthand property for focusing a particular test case. + * + * @category Testing + */ + only( + options: Omit, + fn: (t: TestContext) => void | Promise, + ): void; + } /** * Context that is passed to a benchmarked function. The instance is shared