mirror of
https://github.com/denoland/deno.git
synced 2025-09-28 05:04:48 +00:00
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:
parent
7d8f0ae038
commit
89424f8e4a
7 changed files with 1269 additions and 1233 deletions
|
@ -320,8 +320,16 @@ impl DenoSubcommand {
|
|||
matches!(self, Self::Run(_))
|
||||
}
|
||||
|
||||
pub fn is_test_or_jupyter(&self) -> bool {
|
||||
matches!(self, Self::Test(_) | Self::Jupyter(_))
|
||||
// Returns `true` if the subcommand depends on testing infrastructure.
|
||||
pub fn needs_test(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Test(_)
|
||||
| Self::Jupyter(_)
|
||||
| Self::Repl(_)
|
||||
| Self::Bench(_)
|
||||
| Self::Lsp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -331,7 +331,6 @@ deno_core::extension!(
|
|||
esm_entry_point = "ext:cli/99_main.js",
|
||||
esm = [
|
||||
dir "js",
|
||||
"40_testing.js",
|
||||
"99_main.js"
|
||||
],
|
||||
customizer = |ext: &mut deno_core::Extension| {
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
* }, { raw: true });
|
||||
* ```
|
||||
*/
|
||||
{
|
||||
(() => {
|
||||
const internals = Deno[Deno.internal];
|
||||
const core = internals.core;
|
||||
|
||||
|
@ -428,4 +428,4 @@
|
|||
}
|
||||
|
||||
internals.enableJupyter = enableJupyter;
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -3,36 +3,36 @@
|
|||
// Do not use primordials because we do not want to depend on the __bootstrap
|
||||
// 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 ops = core.ops;
|
||||
|
||||
const internals = globalThis.__bootstrap.internals;
|
||||
const {
|
||||
const {
|
||||
setExitHandler,
|
||||
Console,
|
||||
serializePermissions,
|
||||
} = internals;
|
||||
} = internals;
|
||||
|
||||
const opSanitizerDelayResolveQueue = [];
|
||||
let hasSetOpSanitizerDelayMacrotask = false;
|
||||
const opSanitizerDelayResolveQueue = [];
|
||||
let hasSetOpSanitizerDelayMacrotask = false;
|
||||
|
||||
// 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
|
||||
// that resolves when it's (probably) fine to run the op sanitizer.
|
||||
//
|
||||
// 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
|
||||
// callback without delaying is sufficient, because when the macrotask callback
|
||||
// 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.
|
||||
//
|
||||
// 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()`.
|
||||
// Because of this, we give extra leeway for worker ops to complete, by waiting
|
||||
// for a whole millisecond if there are pending worker ops.
|
||||
function opSanitizerDelay(hasPendingWorkerOps) {
|
||||
// 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
|
||||
// that resolves when it's (probably) fine to run the op sanitizer.
|
||||
//
|
||||
// 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
|
||||
// callback without delaying is sufficient, because when the macrotask callback
|
||||
// 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.
|
||||
//
|
||||
// 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()`.
|
||||
// Because of this, we give extra leeway for worker ops to complete, by waiting
|
||||
// for a whole millisecond if there are pending worker ops.
|
||||
function opSanitizerDelay(hasPendingWorkerOps) {
|
||||
if (!hasSetOpSanitizerDelayMacrotask) {
|
||||
core.setMacrotaskCallback(handleOpSanitizerDelayMacrotask);
|
||||
hasSetOpSanitizerDelayMacrotask = true;
|
||||
|
@ -47,21 +47,21 @@ function opSanitizerDelay(hasPendingWorkerOps) {
|
|||
}, hasPendingWorkerOps ? 1 : 0);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
function handleOpSanitizerDelayMacrotask() {
|
||||
function handleOpSanitizerDelayMacrotask() {
|
||||
const resolve = opSanitizerDelayResolveQueue.shift();
|
||||
if (resolve) {
|
||||
resolve();
|
||||
return opSanitizerDelayResolveQueue.length === 0;
|
||||
}
|
||||
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. Async operations should not complete in a test if they were not started in that test.
|
||||
// deno-fmt-ignore
|
||||
const OP_DETAILS = {
|
||||
// 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.
|
||||
// deno-fmt-ignore
|
||||
const OP_DETAILS = {
|
||||
"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_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_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`"],
|
||||
};
|
||||
};
|
||||
|
||||
let opIdHostRecvMessage = -1;
|
||||
let opIdHostRecvCtrl = -1;
|
||||
let opNames = null;
|
||||
let opIdHostRecvMessage = -1;
|
||||
let opIdHostRecvCtrl = -1;
|
||||
let opNames = null;
|
||||
|
||||
function populateOpNames() {
|
||||
function populateOpNames() {
|
||||
opNames = core.ops.op_op_names();
|
||||
opIdHostRecvMessage = opNames.indexOf("op_host_recv_message");
|
||||
opIdHostRecvCtrl = opNames.indexOf("op_host_recv_ctrl");
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap test function in additional assertion that makes sure
|
||||
// the test case does not leak async "ops" - ie. number of async
|
||||
// completed ops after the test is the same as number of dispatched
|
||||
// ops. Note that "unref" ops are ignored since in nature that are
|
||||
// optional.
|
||||
function assertOps(fn) {
|
||||
// Wrap test function in additional assertion that makes sure
|
||||
// the test case does not leak async "ops" - ie. number of async
|
||||
// completed ops after the test is the same as number of dispatched
|
||||
// ops. Note that "unref" ops are ignored since in nature that are
|
||||
// optional.
|
||||
function assertOps(fn) {
|
||||
/** @param desc {TestDescription | TestStepDescription} */
|
||||
return async function asyncOpSanitizer(desc) {
|
||||
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) {
|
||||
case "fsFile":
|
||||
return ["A file", "opened", "closed"];
|
||||
|
@ -331,9 +333,9 @@ function prettyResourceNames(name) {
|
|||
default:
|
||||
return [`A "${name}" resource`, "created", "cleaned up"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resourceCloseHint(name) {
|
||||
function resourceCloseHint(name) {
|
||||
switch (name) {
|
||||
case "fsFile":
|
||||
return "Close the file handle by calling `file.close()`.";
|
||||
|
@ -398,12 +400,12 @@ function resourceCloseHint(name) {
|
|||
default:
|
||||
return "Close the resource before the end of the test.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap test function in additional assertion that makes sure
|
||||
// the test case does not "leak" resources - ie. resource table after
|
||||
// the test has exactly the same contents as before the test.
|
||||
function assertResources(fn) {
|
||||
// Wrap test function in additional assertion that makes sure
|
||||
// the test case does not "leak" resources - ie. resource table after
|
||||
// the test has exactly the same contents as before the test.
|
||||
function assertResources(fn) {
|
||||
/** @param desc {TestDescription | TestStepDescription} */
|
||||
return async function resourceSanitizer(desc) {
|
||||
const pre = core.resources();
|
||||
|
@ -440,11 +442,11 @@ function assertResources(fn) {
|
|||
}
|
||||
return { failed: { leakedResources: details } };
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap test function in additional assertion that makes sure
|
||||
// that the test case does not accidentally exit prematurely.
|
||||
function assertExit(fn, isTest) {
|
||||
// Wrap test function in additional assertion that makes sure
|
||||
// that the test case does not accidentally exit prematurely.
|
||||
function assertExit(fn, isTest) {
|
||||
return async function exitSanitizer(...params) {
|
||||
setExitHandler((exitCode) => {
|
||||
throw new Error(
|
||||
|
@ -461,9 +463,9 @@ function assertExit(fn, isTest) {
|
|||
setExitHandler(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function wrapOuter(fn, desc) {
|
||||
function wrapOuter(fn, desc) {
|
||||
return async function outerWrapped() {
|
||||
try {
|
||||
if (desc.ignore) {
|
||||
|
@ -480,9 +482,9 @@ function wrapOuter(fn, desc) {
|
|||
state.completed = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function wrapInner(fn) {
|
||||
function wrapInner(fn) {
|
||||
/** @param desc {TestDescription | TestStepDescription} */
|
||||
return async function innerWrapped(desc) {
|
||||
function getRunningStepDescs() {
|
||||
|
@ -520,7 +522,9 @@ function wrapInner(fn) {
|
|||
|
||||
if (usesSanitizer(desc) && runningStepDescs.length > 0) {
|
||||
return {
|
||||
failed: { hasSanitizersAndOverlaps: runningStepDescs.map(getFullName) },
|
||||
failed: {
|
||||
hasSanitizersAndOverlaps: runningStepDescs.map(getFullName),
|
||||
},
|
||||
};
|
||||
}
|
||||
await fn(testStates.get(desc.id).context);
|
||||
|
@ -536,19 +540,19 @@ function wrapInner(fn) {
|
|||
}
|
||||
return failedSteps == 0 ? null : { failed: { failedSteps } };
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function pledgePermissions(permissions) {
|
||||
function pledgePermissions(permissions) {
|
||||
return ops.op_pledge_test_permissions(
|
||||
serializePermissions(permissions),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function restorePermissions(token) {
|
||||
function restorePermissions(token) {
|
||||
ops.op_restore_test_permissions(token);
|
||||
}
|
||||
}
|
||||
|
||||
function withPermissions(fn, permissions) {
|
||||
function withPermissions(fn, permissions) {
|
||||
return async function applyPermissions(...params) {
|
||||
const token = pledgePermissions(permissions);
|
||||
|
||||
|
@ -558,22 +562,22 @@ function withPermissions(fn, permissions) {
|
|||
restorePermissions(token);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const ESCAPE_ASCII_CHARS = [
|
||||
const ESCAPE_ASCII_CHARS = [
|
||||
["\b", "\\b"],
|
||||
["\f", "\\f"],
|
||||
["\t", "\\t"],
|
||||
["\n", "\\n"],
|
||||
["\r", "\\r"],
|
||||
["\v", "\\v"],
|
||||
];
|
||||
];
|
||||
|
||||
/**
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {string}
|
||||
*/
|
||||
function escapeName(name) {
|
||||
function escapeName(name) {
|
||||
// Check if we need to escape a character
|
||||
for (let i = 0; i < name.length; i++) {
|
||||
const ch = name.charCodeAt(i);
|
||||
|
@ -588,9 +592,9 @@ function escapeName(name) {
|
|||
|
||||
// We didn't need to escape anything, return original string
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @typedef {{
|
||||
* id: number,
|
||||
* name: string,
|
||||
|
@ -646,27 +650,27 @@ function escapeName(name) {
|
|||
* }} BenchDescription
|
||||
*/
|
||||
|
||||
/** @type {Map<number, TestState | TestStepState>} */
|
||||
const testStates = new Map();
|
||||
/** @type {number | null} */
|
||||
let currentBenchId = null;
|
||||
// These local variables are used to track time measurements at
|
||||
// `BenchContext::{start,end}` calls. They are global instead of using a state
|
||||
// map to minimise the overhead of assigning them.
|
||||
/** @type {number | null} */
|
||||
let currentBenchUserExplicitStart = null;
|
||||
/** @type {number | null} */
|
||||
let currentBenchUserExplicitEnd = null;
|
||||
/** @type {Map<number, TestState | TestStepState>} */
|
||||
const testStates = new Map();
|
||||
/** @type {number | null} */
|
||||
let currentBenchId = null;
|
||||
// These local variables are used to track time measurements at
|
||||
// `BenchContext::{start,end}` calls. They are global instead of using a state
|
||||
// map to minimise the overhead of assigning them.
|
||||
/** @type {number | null} */
|
||||
let currentBenchUserExplicitStart = null;
|
||||
/** @type {number | null} */
|
||||
let currentBenchUserExplicitEnd = null;
|
||||
|
||||
const registerTestIdRetBuf = new Uint32Array(1);
|
||||
const registerTestIdRetBufU8 = new Uint8Array(registerTestIdRetBuf.buffer);
|
||||
const registerTestIdRetBuf = new Uint32Array(1);
|
||||
const registerTestIdRetBufU8 = new Uint8Array(registerTestIdRetBuf.buffer);
|
||||
|
||||
function testInner(
|
||||
function testInner(
|
||||
nameOrFnOrOptions,
|
||||
optionsOrFn,
|
||||
maybeFn,
|
||||
overrides = {},
|
||||
) {
|
||||
) {
|
||||
if (typeof ops.op_register_test != "function") {
|
||||
return;
|
||||
}
|
||||
|
@ -777,37 +781,37 @@ function testInner(
|
|||
children: [],
|
||||
completed: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Main test function provided by Deno.
|
||||
function test(
|
||||
// Main test function provided by Deno.
|
||||
function test(
|
||||
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 });
|
||||
};
|
||||
};
|
||||
|
||||
test.only = function (
|
||||
test.only = function (
|
||||
nameOrFnOrOptions,
|
||||
optionsOrFn,
|
||||
maybeFn,
|
||||
) {
|
||||
) {
|
||||
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { only: true });
|
||||
};
|
||||
};
|
||||
|
||||
let registeredWarmupBench = false;
|
||||
let registeredWarmupBench = false;
|
||||
|
||||
// Main bench function provided by Deno.
|
||||
function bench(
|
||||
// Main bench function provided by Deno.
|
||||
function bench(
|
||||
nameOrFnOrOptions,
|
||||
optionsOrFn,
|
||||
maybeFn,
|
||||
) {
|
||||
) {
|
||||
if (typeof ops.op_register_bench != "function") {
|
||||
return;
|
||||
}
|
||||
|
@ -919,16 +923,24 @@ function bench(
|
|||
const { id, origin } = ops.op_register_bench(benchDesc);
|
||||
benchDesc.id = id;
|
||||
benchDesc.origin = origin;
|
||||
}
|
||||
}
|
||||
|
||||
function compareMeasurements(a, b) {
|
||||
function compareMeasurements(a, b) {
|
||||
if (a > b) return 1;
|
||||
if (a < b) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function benchStats(n, highPrecision, usedExplicitTimers, avg, min, max, all) {
|
||||
function benchStats(
|
||||
n,
|
||||
highPrecision,
|
||||
usedExplicitTimers,
|
||||
avg,
|
||||
min,
|
||||
max,
|
||||
all,
|
||||
) {
|
||||
return {
|
||||
n,
|
||||
min,
|
||||
|
@ -941,9 +953,9 @@ function benchStats(n, highPrecision, usedExplicitTimers, avg, min, max, all) {
|
|||
highPrecision,
|
||||
usedExplicitTimers,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function benchMeasure(timeBudget, fn, async, context) {
|
||||
async function benchMeasure(timeBudget, fn, async, context) {
|
||||
let n = 0;
|
||||
let avg = 0;
|
||||
let wavg = 0;
|
||||
|
@ -1103,10 +1115,10 @@ async function benchMeasure(timeBudget, fn, async, context) {
|
|||
max,
|
||||
all,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @param desc {BenchDescription} */
|
||||
function createBenchContext(desc) {
|
||||
/** @param desc {BenchDescription} */
|
||||
function createBenchContext(desc) {
|
||||
return {
|
||||
[Symbol.toStringTag]: "BenchContext",
|
||||
name: desc.name,
|
||||
|
@ -1118,7 +1130,9 @@ function createBenchContext(desc) {
|
|||
);
|
||||
}
|
||||
if (currentBenchUserExplicitStart != null) {
|
||||
throw new TypeError("BenchContext::start() has already been invoked.");
|
||||
throw new TypeError(
|
||||
"BenchContext::start() has already been invoked.",
|
||||
);
|
||||
}
|
||||
currentBenchUserExplicitStart = benchNow();
|
||||
},
|
||||
|
@ -1135,10 +1149,10 @@ function createBenchContext(desc) {
|
|||
currentBenchUserExplicitEnd = end;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** Wrap a user benchmark function in one which returns a structured result. */
|
||||
function wrapBenchmark(desc) {
|
||||
/** Wrap a user benchmark function in one which returns a structured result. */
|
||||
function wrapBenchmark(desc) {
|
||||
const fn = desc.fn;
|
||||
return async function outerWrapped() {
|
||||
let token = null;
|
||||
|
@ -1164,7 +1178,12 @@ function wrapBenchmark(desc) {
|
|||
|
||||
const benchTimeInMs = 500;
|
||||
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 };
|
||||
} catch (error) {
|
||||
|
@ -1178,24 +1197,24 @@ function wrapBenchmark(desc) {
|
|||
if (token !== null) restorePermissions(token);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function benchNow() {
|
||||
function benchNow() {
|
||||
return ops.op_bench_now();
|
||||
}
|
||||
}
|
||||
|
||||
function getFullName(desc) {
|
||||
function getFullName(desc) {
|
||||
if ("parent" in desc) {
|
||||
return `${getFullName(desc.parent)} ... ${desc.name}`;
|
||||
}
|
||||
return desc.name;
|
||||
}
|
||||
}
|
||||
|
||||
function usesSanitizer(desc) {
|
||||
function usesSanitizer(desc) {
|
||||
return desc.sanitizeResources || desc.sanitizeOps || desc.sanitizeExit;
|
||||
}
|
||||
}
|
||||
|
||||
function stepReportResult(desc, result, elapsed) {
|
||||
function stepReportResult(desc, result, elapsed) {
|
||||
const state = testStates.get(desc.id);
|
||||
for (const childDesc of state.children) {
|
||||
stepReportResult(childDesc, { failed: "incomplete" }, 0);
|
||||
|
@ -1207,10 +1226,10 @@ function stepReportResult(desc, result, elapsed) {
|
|||
} else {
|
||||
ops.op_test_event_step_result_failed(desc.id, result.failed, elapsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param desc {TestDescription | TestStepDescription} */
|
||||
function createTestContext(desc) {
|
||||
/** @param desc {TestDescription | TestStepDescription} */
|
||||
function createTestContext(desc) {
|
||||
let parent;
|
||||
let level;
|
||||
let rootId;
|
||||
|
@ -1254,7 +1273,9 @@ function createTestContext(desc) {
|
|||
|
||||
let stepDesc;
|
||||
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.");
|
||||
}
|
||||
stepDesc = {
|
||||
|
@ -1324,16 +1345,16 @@ function createTestContext(desc) {
|
|||
return result == "ok";
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Wrap a user test function in one which returns a structured result.
|
||||
* @template T {Function}
|
||||
* @param testFn {T}
|
||||
* @param desc {TestDescription | TestStepDescription}
|
||||
* @returns {T}
|
||||
*/
|
||||
function wrapTest(desc) {
|
||||
function wrapTest(desc) {
|
||||
let testFn = wrapInner(desc.fn);
|
||||
if (desc.sanitizeOps) {
|
||||
testFn = assertOps(testFn);
|
||||
|
@ -1348,8 +1369,8 @@ function wrapTest(desc) {
|
|||
testFn = withPermissions(testFn, desc.permissions);
|
||||
}
|
||||
return wrapOuter(testFn, desc);
|
||||
}
|
||||
}
|
||||
|
||||
import { denoNs } from "ext:runtime/90_deno_ns.js";
|
||||
denoNs.bench = bench;
|
||||
denoNs.test = test;
|
||||
globalThis.Deno.bench = bench;
|
||||
globalThis.Deno.test = test;
|
||||
})();
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
// 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";
|
||||
|
|
|
@ -639,9 +639,13 @@ impl CliMainWorkerFactory {
|
|||
options,
|
||||
);
|
||||
|
||||
if self.shared.subcommand.is_test_or_jupyter() {
|
||||
if self.shared.subcommand.needs_test() {
|
||||
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"),
|
||||
)?;
|
||||
}
|
||||
|
|
|
@ -448,6 +448,11 @@ const finalDenoNs = {
|
|||
resources: core.resources,
|
||||
close: core.close,
|
||||
...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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue