summaryrefslogtreecommitdiff
path: root/ext/node
diff options
context:
space:
mode:
Diffstat (limited to 'ext/node')
-rw-r--r--ext/node/lib.rs1
-rw-r--r--ext/node/polyfill.rs1
-rw-r--r--ext/node/polyfills/01_require.js2
-rw-r--r--ext/node/polyfills/testing.ts237
4 files changed, 241 insertions, 0 deletions
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index 318de77e1..ca79c3dce 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -491,6 +491,7 @@ deno_core::extension!(deno_node,
"stream/web.ts" with_specifier "node:stream/web",
"string_decoder.ts" with_specifier "node:string_decoder",
"sys.ts" with_specifier "node:sys",
+ "testing.ts" with_specifier "node:test",
"timers.ts" with_specifier "node:timers",
"timers/promises.ts" with_specifier "node:timers/promises",
"tls.ts" with_specifier "node:tls",
diff --git a/ext/node/polyfill.rs b/ext/node/polyfill.rs
index 16ffe185d..fede915a2 100644
--- a/ext/node/polyfill.rs
+++ b/ext/node/polyfill.rs
@@ -62,6 +62,7 @@ generate_builtin_node_module_lists! {
"stream/web",
"string_decoder",
"sys",
+ "test",
"timers",
"timers/promises",
"tls",
diff --git a/ext/node/polyfills/01_require.js b/ext/node/polyfills/01_require.js
index c58dad9a4..acdf8402f 100644
--- a/ext/node/polyfills/01_require.js
+++ b/ext/node/polyfills/01_require.js
@@ -117,6 +117,7 @@ import streamPromises from "node:stream/promises";
import streamWeb from "node:stream/web";
import stringDecoder from "node:string_decoder";
import sys from "node:sys";
+import test from "node:test";
import timers from "node:timers";
import timersPromises from "node:timers/promises";
import tls from "node:tls";
@@ -219,6 +220,7 @@ function setupBuiltinModules() {
"stream/web": streamWeb,
string_decoder: stringDecoder,
sys,
+ test,
timers,
"timers/promises": timersPromises,
tls,
diff --git a/ext/node/polyfills/testing.ts b/ext/node/polyfills/testing.ts
new file mode 100644
index 000000000..2c112d9fb
--- /dev/null
+++ b/ext/node/polyfills/testing.ts
@@ -0,0 +1,237 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+// TODO(petamoriken): enable prefer-primordials for node polyfills
+// deno-lint-ignore-file prefer-primordials
+
+import { notImplemented, warnNotImplemented } from "ext:deno_node/_utils.ts";
+
+export function deferred() {
+ let methods;
+ const promise = new Promise((resolve, reject) => {
+ methods = {
+ async resolve(value) {
+ await value;
+ resolve(value);
+ },
+ // deno-lint-ignore no-explicit-any
+ reject(reason?: any) {
+ reject(reason);
+ },
+ };
+ });
+ return Object.assign(promise, methods);
+}
+
+export function run() {
+ notImplemented("test.run");
+}
+
+function noop() {}
+
+class NodeTestContext {
+ #denoContext: Deno.TestContext;
+
+ constructor(t: Deno.TestContext) {
+ this.#denoContext = t;
+ }
+
+ get signal() {
+ notImplemented("test.TestContext.signal");
+ return null;
+ }
+
+ get name() {
+ notImplemented("test.TestContext.name");
+ return null;
+ }
+
+ diagnostic(message) {
+ console.log("DIAGNOSTIC:", message);
+ }
+
+ get mock() {
+ notImplemented("test.TestContext.mock");
+ return null;
+ }
+
+ runOnly() {
+ notImplemented("test.TestContext.runOnly");
+ return null;
+ }
+
+ skip() {
+ warnNotImplemented("test.TestContext.skip");
+ return null;
+ }
+
+ todo() {
+ warnNotImplemented("test.TestContext.todo");
+ return null;
+ }
+
+ test(name, options, fn) {
+ const prepared = prepareOptions(name, options, fn, {});
+ return this.#denoContext.step({
+ name: prepared.name,
+ fn: prepared.fn,
+ ignore: prepared.options.todo || prepared.options.skip,
+ }).then(() => undefined);
+ }
+
+ before(_fn, _options) {
+ notImplemented("test.TestContext.before");
+ }
+
+ after(_fn, _options) {
+ notImplemented("test.TestContext.after");
+ }
+
+ beforeEach(_fn, _options) {
+ notImplemented("test.TestContext.beforeEach");
+ }
+
+ afterEach(_fn, _options) {
+ notImplemented("test.TestContext.afterEach");
+ }
+}
+
+function prepareOptions(name, options, fn, overrides) {
+ if (typeof name === "function") {
+ fn = name;
+ } else if (name !== null && typeof name === "object") {
+ fn = options;
+ options = name;
+ } else if (typeof options === "function") {
+ fn = options;
+ }
+
+ if (options === null || typeof options !== "object") {
+ options = {};
+ }
+
+ const finalOptions = { ...options, ...overrides };
+ const { concurrency, timeout, signal } = finalOptions;
+
+ if (typeof concurrency !== "undefined") {
+ warnNotImplemented("test.options.concurrency");
+ }
+ if (typeof timeout !== "undefined") {
+ warnNotImplemented("test.options.timeout");
+ }
+ if (typeof signal !== "undefined") {
+ warnNotImplemented("test.options.signal");
+ }
+
+ if (typeof fn !== "function") {
+ fn = noop;
+ }
+
+ if (typeof name !== "string" || name === "") {
+ name = fn.name || "<anonymous>";
+ }
+
+ return { fn, options: finalOptions, name };
+}
+
+function wrapTestFn(fn, promise) {
+ return async function (t) {
+ const nodeTestContext = new NodeTestContext(t);
+ try {
+ await fn(nodeTestContext);
+ } finally {
+ promise.resolve(undefined);
+ }
+ };
+}
+
+function prepareDenoTest(name, options, fn, overrides) {
+ const prepared = prepareOptions(name, options, fn, overrides);
+
+ const promise = deferred();
+
+ const denoTestOptions = {
+ name: prepared.name,
+ fn: wrapTestFn(prepared.fn, promise),
+ only: prepared.options.only,
+ ignore: prepared.options.todo || prepared.options.skip,
+ };
+ Deno.test(denoTestOptions);
+ return promise;
+}
+
+export function test(name, options, fn) {
+ return prepareDenoTest(name, options, fn, {});
+}
+
+test.skip = function skip(name, options, fn) {
+ return prepareDenoTest(name, options, fn, { skip: true });
+};
+
+test.todo = function todo(name, options, fn) {
+ return prepareDenoTest(name, options, fn, { todo: true });
+};
+
+test.only = function only(name, options, fn) {
+ return prepareDenoTest(name, options, fn, { only: true });
+};
+
+export function describe() {
+ notImplemented("test.describe");
+}
+
+export function it() {
+ notImplemented("test.it");
+}
+
+export function before() {
+ notImplemented("test.before");
+}
+
+export function after() {
+ notImplemented("test.after");
+}
+
+export function beforeEach() {
+ notImplemented("test.beforeEach");
+}
+
+export function afterEach() {
+ notImplemented("test.afterEach");
+}
+
+export const mock = {
+ fn: () => {
+ notImplemented("test.mock.fn");
+ },
+ getter: () => {
+ notImplemented("test.mock.getter");
+ },
+ method: () => {
+ notImplemented("test.mock.method");
+ },
+ reset: () => {
+ notImplemented("test.mock.reset");
+ },
+ restoreAll: () => {
+ notImplemented("test.mock.restoreAll");
+ },
+ setter: () => {
+ notImplemented("test.mock.setter");
+ },
+ timers: {
+ enable: () => {
+ notImplemented("test.mock.timers.enable");
+ },
+ reset: () => {
+ notImplemented("test.mock.timers.reset");
+ },
+ tick: () => {
+ notImplemented("test.mock.timers.tick");
+ },
+ runAll: () => {
+ notImplemented("test.mock.timers.runAll");
+ },
+ },
+};
+
+export default test;