perf: move "cli/js/40_testing.js" out of main snapshot (#21212)

Closes https://github.com/denoland/deno/issues/21136

---------

Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
This commit is contained in:
Divy Srivastava 2023-11-24 19:46:16 -08:00 committed by GitHub
parent 7d8f0ae038
commit 89424f8e4a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 1269 additions and 1233 deletions

View file

@ -320,8 +320,16 @@ impl DenoSubcommand {
matches!(self, Self::Run(_)) matches!(self, Self::Run(_))
} }
pub fn is_test_or_jupyter(&self) -> bool { // Returns `true` if the subcommand depends on testing infrastructure.
matches!(self, Self::Test(_) | Self::Jupyter(_)) pub fn needs_test(&self) -> bool {
matches!(
self,
Self::Test(_)
| Self::Jupyter(_)
| Self::Repl(_)
| Self::Bench(_)
| Self::Lsp
)
} }
} }

View file

@ -331,7 +331,6 @@ deno_core::extension!(
esm_entry_point = "ext:cli/99_main.js", esm_entry_point = "ext:cli/99_main.js",
esm = [ esm = [
dir "js", dir "js",
"40_testing.js",
"99_main.js" "99_main.js"
], ],
customizer = |ext: &mut deno_core::Extension| { customizer = |ext: &mut deno_core::Extension| {

View file

@ -36,7 +36,7 @@
* }, { raw: true }); * }, { raw: true });
* ``` * ```
*/ */
{ (() => {
const internals = Deno[Deno.internal]; const internals = Deno[Deno.internal];
const core = internals.core; const core = internals.core;
@ -428,4 +428,4 @@
} }
internals.enableJupyter = enableJupyter; internals.enableJupyter = enableJupyter;
} })();

View file

@ -3,36 +3,36 @@
// Do not use primordials because we do not want to depend on the __bootstrap // Do not use primordials because we do not want to depend on the __bootstrap
// namespace. // namespace.
// //
// deno-lint-ignore-file prefer-primordials // deno-lint-ignore-file
(() => {
const internals = Deno[Deno.internal];
const core = internals.core;
const ops = core.ops;
const core = globalThis.Deno.core; const {
const ops = core.ops;
const internals = globalThis.__bootstrap.internals;
const {
setExitHandler, setExitHandler,
Console, Console,
serializePermissions, serializePermissions,
} = internals; } = internals;
const opSanitizerDelayResolveQueue = []; const opSanitizerDelayResolveQueue = [];
let hasSetOpSanitizerDelayMacrotask = false; let hasSetOpSanitizerDelayMacrotask = false;
// Even if every resource is closed by the end of a test, there can be a delay // Even if every resource is closed by the end of a test, there can be a delay
// until the pending ops have all finished. This function returns a promise // until the pending ops have all finished. This function returns a promise
// that resolves when it's (probably) fine to run the op sanitizer. // that resolves when it's (probably) fine to run the op sanitizer.
// //
// This is implemented by adding a macrotask callback that runs after the // This is implemented by adding a macrotask callback that runs after the
// all ready async ops resolve, and the timer macrotask. Using just a macrotask // all ready async ops resolve, and the timer macrotask. Using just a macrotask
// callback without delaying is sufficient, because when the macrotask callback // callback without delaying is sufficient, because when the macrotask callback
// runs after async op dispatch, we know that all async ops that can currently // runs after async op dispatch, we know that all async ops that can currently
// return `Poll::Ready` have done so, and have been dispatched to JS. // return `Poll::Ready` have done so, and have been dispatched to JS.
// //
// Worker ops are an exception to this, because there is no way for the user to // Worker ops are an exception to this, because there is no way for the user to
// await shutdown of the worker from the thread calling `worker.terminate()`. // await shutdown of the worker from the thread calling `worker.terminate()`.
// Because of this, we give extra leeway for worker ops to complete, by waiting // Because of this, we give extra leeway for worker ops to complete, by waiting
// for a whole millisecond if there are pending worker ops. // for a whole millisecond if there are pending worker ops.
function opSanitizerDelay(hasPendingWorkerOps) { function opSanitizerDelay(hasPendingWorkerOps) {
if (!hasSetOpSanitizerDelayMacrotask) { if (!hasSetOpSanitizerDelayMacrotask) {
core.setMacrotaskCallback(handleOpSanitizerDelayMacrotask); core.setMacrotaskCallback(handleOpSanitizerDelayMacrotask);
hasSetOpSanitizerDelayMacrotask = true; hasSetOpSanitizerDelayMacrotask = true;
@ -47,21 +47,21 @@ function opSanitizerDelay(hasPendingWorkerOps) {
}, hasPendingWorkerOps ? 1 : 0); }, hasPendingWorkerOps ? 1 : 0);
}); });
return p; return p;
} }
function handleOpSanitizerDelayMacrotask() { function handleOpSanitizerDelayMacrotask() {
const resolve = opSanitizerDelayResolveQueue.shift(); const resolve = opSanitizerDelayResolveQueue.shift();
if (resolve) { if (resolve) {
resolve(); resolve();
return opSanitizerDelayResolveQueue.length === 0; return opSanitizerDelayResolveQueue.length === 0;
} }
return undefined; // we performed no work, so can skip microtasks checkpoint return undefined; // we performed no work, so can skip microtasks checkpoint
} }
// An async operation to $0 was started in this test, but never completed. This is often caused by not $1. // An async operation to $0 was started in this test, but never completed. This is often caused by not $1.
// An async operation to $0 was started in this test, but never completed. Async operations should not complete in a test if they were not started in that test. // An async operation to $0 was started in this test, but never completed. Async operations should not complete in a test if they were not started in that test.
// deno-fmt-ignore // deno-fmt-ignore
const OP_DETAILS = { const OP_DETAILS = {
"op_blob_read_part": ["read from a Blob or File", "awaiting the result of a Blob or File read"], "op_blob_read_part": ["read from a Blob or File", "awaiting the result of a Blob or File read"],
"op_broadcast_recv": ["receive a message from a BroadcastChannel", "closing the BroadcastChannel"], "op_broadcast_recv": ["receive a message from a BroadcastChannel", "closing the BroadcastChannel"],
"op_broadcast_send": ["send a message to a BroadcastChannel", "closing the BroadcastChannel"], "op_broadcast_send": ["send a message to a BroadcastChannel", "closing the BroadcastChannel"],
@ -133,24 +133,24 @@ const OP_DETAILS = {
"op_ws_send_binary_ab": ["send a message on a WebSocket", "closing a `WebSocket` or `WebSocketStream`"], "op_ws_send_binary_ab": ["send a message on a WebSocket", "closing a `WebSocket` or `WebSocketStream`"],
"op_ws_send_ping": ["send a message on a WebSocket", "closing a `WebSocket` or `WebSocketStream`"], "op_ws_send_ping": ["send a message on a WebSocket", "closing a `WebSocket` or `WebSocketStream`"],
"op_ws_send_pong": ["send a message on a WebSocket", "closing a `WebSocket` or `WebSocketStream`"], "op_ws_send_pong": ["send a message on a WebSocket", "closing a `WebSocket` or `WebSocketStream`"],
}; };
let opIdHostRecvMessage = -1; let opIdHostRecvMessage = -1;
let opIdHostRecvCtrl = -1; let opIdHostRecvCtrl = -1;
let opNames = null; let opNames = null;
function populateOpNames() { function populateOpNames() {
opNames = core.ops.op_op_names(); opNames = core.ops.op_op_names();
opIdHostRecvMessage = opNames.indexOf("op_host_recv_message"); opIdHostRecvMessage = opNames.indexOf("op_host_recv_message");
opIdHostRecvCtrl = opNames.indexOf("op_host_recv_ctrl"); opIdHostRecvCtrl = opNames.indexOf("op_host_recv_ctrl");
} }
// Wrap test function in additional assertion that makes sure // Wrap test function in additional assertion that makes sure
// the test case does not leak async "ops" - ie. number of async // the test case does not leak async "ops" - ie. number of async
// completed ops after the test is the same as number of dispatched // completed ops after the test is the same as number of dispatched
// ops. Note that "unref" ops are ignored since in nature that are // ops. Note that "unref" ops are ignored since in nature that are
// optional. // optional.
function assertOps(fn) { function assertOps(fn) {
/** @param desc {TestDescription | TestStepDescription} */ /** @param desc {TestDescription | TestStepDescription} */
return async function asyncOpSanitizer(desc) { return async function asyncOpSanitizer(desc) {
if (opNames === null) populateOpNames(); if (opNames === null) populateOpNames();
@ -262,11 +262,13 @@ function assertOps(fn) {
} }
} }
return { failed: { leakedOps: [details, core.isOpCallTracingEnabled()] } }; return {
failed: { leakedOps: [details, core.isOpCallTracingEnabled()] },
}; };
} };
}
function prettyResourceNames(name) { function prettyResourceNames(name) {
switch (name) { switch (name) {
case "fsFile": case "fsFile":
return ["A file", "opened", "closed"]; return ["A file", "opened", "closed"];
@ -331,9 +333,9 @@ function prettyResourceNames(name) {
default: default:
return [`A "${name}" resource`, "created", "cleaned up"]; return [`A "${name}" resource`, "created", "cleaned up"];
} }
} }
function resourceCloseHint(name) { function resourceCloseHint(name) {
switch (name) { switch (name) {
case "fsFile": case "fsFile":
return "Close the file handle by calling `file.close()`."; return "Close the file handle by calling `file.close()`.";
@ -398,12 +400,12 @@ function resourceCloseHint(name) {
default: default:
return "Close the resource before the end of the test."; return "Close the resource before the end of the test.";
} }
} }
// Wrap test function in additional assertion that makes sure // Wrap test function in additional assertion that makes sure
// the test case does not "leak" resources - ie. resource table after // the test case does not "leak" resources - ie. resource table after
// the test has exactly the same contents as before the test. // the test has exactly the same contents as before the test.
function assertResources(fn) { function assertResources(fn) {
/** @param desc {TestDescription | TestStepDescription} */ /** @param desc {TestDescription | TestStepDescription} */
return async function resourceSanitizer(desc) { return async function resourceSanitizer(desc) {
const pre = core.resources(); const pre = core.resources();
@ -440,11 +442,11 @@ function assertResources(fn) {
} }
return { failed: { leakedResources: details } }; return { failed: { leakedResources: details } };
}; };
} }
// Wrap test function in additional assertion that makes sure // Wrap test function in additional assertion that makes sure
// that the test case does not accidentally exit prematurely. // that the test case does not accidentally exit prematurely.
function assertExit(fn, isTest) { function assertExit(fn, isTest) {
return async function exitSanitizer(...params) { return async function exitSanitizer(...params) {
setExitHandler((exitCode) => { setExitHandler((exitCode) => {
throw new Error( throw new Error(
@ -461,9 +463,9 @@ function assertExit(fn, isTest) {
setExitHandler(null); setExitHandler(null);
} }
}; };
} }
function wrapOuter(fn, desc) { function wrapOuter(fn, desc) {
return async function outerWrapped() { return async function outerWrapped() {
try { try {
if (desc.ignore) { if (desc.ignore) {
@ -480,9 +482,9 @@ function wrapOuter(fn, desc) {
state.completed = true; state.completed = true;
} }
}; };
} }
function wrapInner(fn) { function wrapInner(fn) {
/** @param desc {TestDescription | TestStepDescription} */ /** @param desc {TestDescription | TestStepDescription} */
return async function innerWrapped(desc) { return async function innerWrapped(desc) {
function getRunningStepDescs() { function getRunningStepDescs() {
@ -520,7 +522,9 @@ function wrapInner(fn) {
if (usesSanitizer(desc) && runningStepDescs.length > 0) { if (usesSanitizer(desc) && runningStepDescs.length > 0) {
return { return {
failed: { hasSanitizersAndOverlaps: runningStepDescs.map(getFullName) }, failed: {
hasSanitizersAndOverlaps: runningStepDescs.map(getFullName),
},
}; };
} }
await fn(testStates.get(desc.id).context); await fn(testStates.get(desc.id).context);
@ -536,19 +540,19 @@ function wrapInner(fn) {
} }
return failedSteps == 0 ? null : { failed: { failedSteps } }; return failedSteps == 0 ? null : { failed: { failedSteps } };
}; };
} }
function pledgePermissions(permissions) { function pledgePermissions(permissions) {
return ops.op_pledge_test_permissions( return ops.op_pledge_test_permissions(
serializePermissions(permissions), serializePermissions(permissions),
); );
} }
function restorePermissions(token) { function restorePermissions(token) {
ops.op_restore_test_permissions(token); ops.op_restore_test_permissions(token);
} }
function withPermissions(fn, permissions) { function withPermissions(fn, permissions) {
return async function applyPermissions(...params) { return async function applyPermissions(...params) {
const token = pledgePermissions(permissions); const token = pledgePermissions(permissions);
@ -558,22 +562,22 @@ function withPermissions(fn, permissions) {
restorePermissions(token); restorePermissions(token);
} }
}; };
} }
const ESCAPE_ASCII_CHARS = [ const ESCAPE_ASCII_CHARS = [
["\b", "\\b"], ["\b", "\\b"],
["\f", "\\f"], ["\f", "\\f"],
["\t", "\\t"], ["\t", "\\t"],
["\n", "\\n"], ["\n", "\\n"],
["\r", "\\r"], ["\r", "\\r"],
["\v", "\\v"], ["\v", "\\v"],
]; ];
/** /**
* @param {string} name * @param {string} name
* @returns {string} * @returns {string}
*/ */
function escapeName(name) { function escapeName(name) {
// Check if we need to escape a character // Check if we need to escape a character
for (let i = 0; i < name.length; i++) { for (let i = 0; i < name.length; i++) {
const ch = name.charCodeAt(i); const ch = name.charCodeAt(i);
@ -588,9 +592,9 @@ function escapeName(name) {
// We didn't need to escape anything, return original string // We didn't need to escape anything, return original string
return name; return name;
} }
/** /**
* @typedef {{ * @typedef {{
* id: number, * id: number,
* name: string, * name: string,
@ -646,27 +650,27 @@ function escapeName(name) {
* }} BenchDescription * }} BenchDescription
*/ */
/** @type {Map<number, TestState | TestStepState>} */ /** @type {Map<number, TestState | TestStepState>} */
const testStates = new Map(); const testStates = new Map();
/** @type {number | null} */ /** @type {number | null} */
let currentBenchId = null; let currentBenchId = null;
// These local variables are used to track time measurements at // These local variables are used to track time measurements at
// `BenchContext::{start,end}` calls. They are global instead of using a state // `BenchContext::{start,end}` calls. They are global instead of using a state
// map to minimise the overhead of assigning them. // map to minimise the overhead of assigning them.
/** @type {number | null} */ /** @type {number | null} */
let currentBenchUserExplicitStart = null; let currentBenchUserExplicitStart = null;
/** @type {number | null} */ /** @type {number | null} */
let currentBenchUserExplicitEnd = null; let currentBenchUserExplicitEnd = null;
const registerTestIdRetBuf = new Uint32Array(1); const registerTestIdRetBuf = new Uint32Array(1);
const registerTestIdRetBufU8 = new Uint8Array(registerTestIdRetBuf.buffer); const registerTestIdRetBufU8 = new Uint8Array(registerTestIdRetBuf.buffer);
function testInner( function testInner(
nameOrFnOrOptions, nameOrFnOrOptions,
optionsOrFn, optionsOrFn,
maybeFn, maybeFn,
overrides = {}, overrides = {},
) { ) {
if (typeof ops.op_register_test != "function") { if (typeof ops.op_register_test != "function") {
return; return;
} }
@ -777,37 +781,37 @@ function testInner(
children: [], children: [],
completed: false, completed: false,
}); });
} }
// Main test function provided by Deno. // Main test function provided by Deno.
function test( function test(
nameOrFnOrOptions, nameOrFnOrOptions,
optionsOrFn, optionsOrFn,
maybeFn, maybeFn,
) { ) {
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn); return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn);
} }
test.ignore = function (nameOrFnOrOptions, optionsOrFn, maybeFn) { test.ignore = function (nameOrFnOrOptions, optionsOrFn, maybeFn) {
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { ignore: true }); return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { ignore: true });
}; };
test.only = function ( test.only = function (
nameOrFnOrOptions, nameOrFnOrOptions,
optionsOrFn, optionsOrFn,
maybeFn, maybeFn,
) { ) {
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { only: true }); return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { only: true });
}; };
let registeredWarmupBench = false; let registeredWarmupBench = false;
// Main bench function provided by Deno. // Main bench function provided by Deno.
function bench( function bench(
nameOrFnOrOptions, nameOrFnOrOptions,
optionsOrFn, optionsOrFn,
maybeFn, maybeFn,
) { ) {
if (typeof ops.op_register_bench != "function") { if (typeof ops.op_register_bench != "function") {
return; return;
} }
@ -919,16 +923,24 @@ function bench(
const { id, origin } = ops.op_register_bench(benchDesc); const { id, origin } = ops.op_register_bench(benchDesc);
benchDesc.id = id; benchDesc.id = id;
benchDesc.origin = origin; benchDesc.origin = origin;
} }
function compareMeasurements(a, b) { function compareMeasurements(a, b) {
if (a > b) return 1; if (a > b) return 1;
if (a < b) return -1; if (a < b) return -1;
return 0; return 0;
} }
function benchStats(n, highPrecision, usedExplicitTimers, avg, min, max, all) { function benchStats(
n,
highPrecision,
usedExplicitTimers,
avg,
min,
max,
all,
) {
return { return {
n, n,
min, min,
@ -941,9 +953,9 @@ function benchStats(n, highPrecision, usedExplicitTimers, avg, min, max, all) {
highPrecision, highPrecision,
usedExplicitTimers, usedExplicitTimers,
}; };
} }
async function benchMeasure(timeBudget, fn, async, context) { async function benchMeasure(timeBudget, fn, async, context) {
let n = 0; let n = 0;
let avg = 0; let avg = 0;
let wavg = 0; let wavg = 0;
@ -1103,10 +1115,10 @@ async function benchMeasure(timeBudget, fn, async, context) {
max, max,
all, all,
); );
} }
/** @param desc {BenchDescription} */ /** @param desc {BenchDescription} */
function createBenchContext(desc) { function createBenchContext(desc) {
return { return {
[Symbol.toStringTag]: "BenchContext", [Symbol.toStringTag]: "BenchContext",
name: desc.name, name: desc.name,
@ -1118,7 +1130,9 @@ function createBenchContext(desc) {
); );
} }
if (currentBenchUserExplicitStart != null) { if (currentBenchUserExplicitStart != null) {
throw new TypeError("BenchContext::start() has already been invoked."); throw new TypeError(
"BenchContext::start() has already been invoked.",
);
} }
currentBenchUserExplicitStart = benchNow(); currentBenchUserExplicitStart = benchNow();
}, },
@ -1135,10 +1149,10 @@ function createBenchContext(desc) {
currentBenchUserExplicitEnd = end; currentBenchUserExplicitEnd = end;
}, },
}; };
} }
/** Wrap a user benchmark function in one which returns a structured result. */ /** Wrap a user benchmark function in one which returns a structured result. */
function wrapBenchmark(desc) { function wrapBenchmark(desc) {
const fn = desc.fn; const fn = desc.fn;
return async function outerWrapped() { return async function outerWrapped() {
let token = null; let token = null;
@ -1164,7 +1178,12 @@ function wrapBenchmark(desc) {
const benchTimeInMs = 500; const benchTimeInMs = 500;
const context = createBenchContext(desc); const context = createBenchContext(desc);
const stats = await benchMeasure(benchTimeInMs, fn, desc.async, context); const stats = await benchMeasure(
benchTimeInMs,
fn,
desc.async,
context,
);
return { ok: stats }; return { ok: stats };
} catch (error) { } catch (error) {
@ -1178,24 +1197,24 @@ function wrapBenchmark(desc) {
if (token !== null) restorePermissions(token); if (token !== null) restorePermissions(token);
} }
}; };
} }
function benchNow() { function benchNow() {
return ops.op_bench_now(); return ops.op_bench_now();
} }
function getFullName(desc) { function getFullName(desc) {
if ("parent" in desc) { if ("parent" in desc) {
return `${getFullName(desc.parent)} ... ${desc.name}`; return `${getFullName(desc.parent)} ... ${desc.name}`;
} }
return desc.name; return desc.name;
} }
function usesSanitizer(desc) { function usesSanitizer(desc) {
return desc.sanitizeResources || desc.sanitizeOps || desc.sanitizeExit; return desc.sanitizeResources || desc.sanitizeOps || desc.sanitizeExit;
} }
function stepReportResult(desc, result, elapsed) { function stepReportResult(desc, result, elapsed) {
const state = testStates.get(desc.id); const state = testStates.get(desc.id);
for (const childDesc of state.children) { for (const childDesc of state.children) {
stepReportResult(childDesc, { failed: "incomplete" }, 0); stepReportResult(childDesc, { failed: "incomplete" }, 0);
@ -1207,10 +1226,10 @@ function stepReportResult(desc, result, elapsed) {
} else { } else {
ops.op_test_event_step_result_failed(desc.id, result.failed, elapsed); ops.op_test_event_step_result_failed(desc.id, result.failed, elapsed);
} }
} }
/** @param desc {TestDescription | TestStepDescription} */ /** @param desc {TestDescription | TestStepDescription} */
function createTestContext(desc) { function createTestContext(desc) {
let parent; let parent;
let level; let level;
let rootId; let rootId;
@ -1254,7 +1273,9 @@ function createTestContext(desc) {
let stepDesc; let stepDesc;
if (typeof nameOrFnOrOptions === "string") { if (typeof nameOrFnOrOptions === "string") {
if (!Object.prototype.isPrototypeOf.call(Function.prototype, maybeFn)) { if (
!Object.prototype.isPrototypeOf.call(Function.prototype, maybeFn)
) {
throw new TypeError("Expected function for second argument."); throw new TypeError("Expected function for second argument.");
} }
stepDesc = { stepDesc = {
@ -1324,16 +1345,16 @@ function createTestContext(desc) {
return result == "ok"; return result == "ok";
}, },
}; };
} }
/** /**
* Wrap a user test function in one which returns a structured result. * Wrap a user test function in one which returns a structured result.
* @template T {Function} * @template T {Function}
* @param testFn {T} * @param testFn {T}
* @param desc {TestDescription | TestStepDescription} * @param desc {TestDescription | TestStepDescription}
* @returns {T} * @returns {T}
*/ */
function wrapTest(desc) { function wrapTest(desc) {
let testFn = wrapInner(desc.fn); let testFn = wrapInner(desc.fn);
if (desc.sanitizeOps) { if (desc.sanitizeOps) {
testFn = assertOps(testFn); testFn = assertOps(testFn);
@ -1348,8 +1369,8 @@ function wrapTest(desc) {
testFn = withPermissions(testFn, desc.permissions); testFn = withPermissions(testFn, desc.permissions);
} }
return wrapOuter(testFn, desc); return wrapOuter(testFn, desc);
} }
import { denoNs } from "ext:runtime/90_deno_ns.js"; globalThis.Deno.bench = bench;
denoNs.bench = bench; globalThis.Deno.test = test;
denoNs.test = test; })();

View file

@ -1,3 +1,2 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import "ext:cli/40_testing.js";
import "ext:cli/runtime/js/99_main.js"; import "ext:cli/runtime/js/99_main.js";

View file

@ -639,9 +639,13 @@ impl CliMainWorkerFactory {
options, options,
); );
if self.shared.subcommand.is_test_or_jupyter() { if self.shared.subcommand.needs_test() {
worker.js_runtime.execute_script_static( worker.js_runtime.execute_script_static(
"40_jupyter.js", "ext:cli/40_testing.js",
include_str!("js/40_testing.js"),
)?;
worker.js_runtime.execute_script_static(
"ext:cli/40_jupyter.js",
include_str!("js/40_jupyter.js"), include_str!("js/40_jupyter.js"),
)?; )?;
} }

View file

@ -448,6 +448,11 @@ const finalDenoNs = {
resources: core.resources, resources: core.resources,
close: core.close, close: core.close,
...denoNs, ...denoNs,
// Deno.test and Deno.bench are noops here, but kept for compatibility; so
// that they don't cause errors when used outside of `deno test`/`deno bench`
// contexts.
test: () => {},
bench: () => {},
}; };
const { const {