@logtape/testing-node 2.3.0-dev.0 → 2.3.0-dev.840

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -38,11 +38,11 @@ import { test } from "@logtape/testing-node/autoload";
38
38
  import { getLogger } from "@logtape/logtape";
39
39
 
40
40
  test("case", async () => {
41
- getLogger(["my-lib"]).debug("Fixture state: {state}.", {
41
+ getLogger(["my-lib"]).info("Fixture state: {state}.", {
42
42
  state: "ready",
43
43
  });
44
44
 
45
- // Logs emitted here are printed only if this callback fails.
45
+ // The info log is printed only if this callback fails.
46
46
  });
47
47
  ~~~~
48
48
 
@@ -52,6 +52,10 @@ when LogTape has not been configured yet. If your suite already configures
52
52
  LogTape, that configuration must include `contextLocalStorage`; otherwise, use
53
53
  `@logtape/testing-node` and manage setup explicitly.
54
54
 
55
+ Set `LOGTAPE_TEST_MODE` to `on-failure`, `always`, or `never`, and
56
+ `LOGTAPE_TEST_LOWEST_LEVEL` to a LogTape level such as `debug` or `info` to
57
+ configure the default reporter used by the autoload `test` and `it` exports.
58
+
55
59
  Use `createTest()` when a suite needs custom reporter options:
56
60
 
57
61
  ~~~~ typescript
package/dist/autoload.cjs CHANGED
@@ -24,8 +24,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  //#endregion
25
25
  const node_async_hooks = __toESM(require("node:async_hooks"));
26
26
  const __logtape_logtape = __toESM(require("@logtape/logtape"));
27
- const node_test = __toESM(require("node:test"));
28
27
  const __logtape_testing_reporter = __toESM(require("@logtape/testing/reporter"));
28
+ const node_test = __toESM(require("node:test"));
29
29
 
30
30
  //#region src/mod.ts
31
31
  /**
@@ -60,52 +60,51 @@ function createIt(options = {}) {
60
60
  *
61
61
  * @since 2.3.0
62
62
  */
63
- const test = createTest();
63
+ const test$1 = createTest();
64
64
  /**
65
65
  * A `node:test` `it()` alias that reports LogTape records from failed test
66
66
  * callbacks using the default reporter options.
67
67
  *
68
68
  * @since 2.3.0
69
69
  */
70
- const it = createIt();
70
+ const it$1 = createIt();
71
71
  /**
72
72
  * Shorthand for marking a test as `only`.
73
73
  *
74
74
  * @since 2.3.0
75
75
  */
76
- const only = test.only;
76
+ const only$1 = test$1.only;
77
77
  /**
78
78
  * Shorthand for skipping a test.
79
79
  *
80
80
  * @since 2.3.0
81
81
  */
82
- const skip = test.skip;
82
+ const skip$1 = test$1.skip;
83
83
  /**
84
84
  * Shorthand for marking a test as TODO.
85
85
  *
86
86
  * @since 2.3.0
87
87
  */
88
- const todo = test.todo;
88
+ const todo$1 = test$1.todo;
89
89
  /**
90
90
  * Shorthand for expecting a test to fail when supported by the active Node.js
91
91
  * runtime.
92
92
  *
93
93
  * @since 2.3.0
94
94
  */
95
- const expectFailure = test.expectFailure;
95
+ const expectFailure$1 = test$1.expectFailure;
96
96
  /**
97
97
  * Node.js' test assertion tracker when supported by the active runtime.
98
98
  *
99
99
  * @since 2.3.0
100
100
  */
101
- const assert = test.assert;
101
+ const assert = test$1.assert;
102
102
  /**
103
103
  * Node.js' snapshot helper when supported by the active runtime.
104
104
  *
105
105
  * @since 2.3.0
106
106
  */
107
- const snapshot = test.snapshot;
108
- var src_default = test;
107
+ const snapshot = test$1.snapshot;
109
108
  function createNodeTestFunction(baseTest, options, includeExtendedProperties = true) {
110
109
  const register = (...args) => Reflect.apply(baseTest, void 0, wrapCallbackArgument(args, options));
111
110
  const baseExpectFailure = baseTest.expectFailure;
@@ -142,27 +141,48 @@ function wrapNodeCallback(wrap, callback) {
142
141
  if (callback.length >= 2) return function(context, done) {
143
142
  const runCallback = (...args) => Reflect.apply(callback, this, args);
144
143
  wrap(() => new Promise((resolve, reject) => {
144
+ let callbackReturned = false;
145
+ let doneCalled = false;
146
+ let pendingDone = false;
147
+ let pendingDoneError;
145
148
  let settled = false;
146
- const wrappedDone = (error) => {
149
+ const settle = (error) => {
147
150
  if (settled) return;
148
151
  settled = true;
149
152
  if (error == null) resolve();
150
153
  else reject(error);
151
154
  };
155
+ const wrappedDone = (error) => {
156
+ if (doneCalled) return;
157
+ doneCalled = true;
158
+ if (!callbackReturned) {
159
+ pendingDone = true;
160
+ pendingDoneError = error;
161
+ return;
162
+ }
163
+ settle(error);
164
+ };
152
165
  try {
153
- runCallback(context, wrappedDone);
166
+ const result = runCallback(context, wrappedDone);
167
+ callbackReturned = true;
168
+ if (isPromiseLike(result)) {
169
+ reject(new TypeError("Callback-style node:test functions must not return a Promise."));
170
+ return;
171
+ }
172
+ if (pendingDone) settle(pendingDoneError);
154
173
  } catch (error) {
174
+ callbackReturned = true;
155
175
  reject(error);
156
176
  }
157
177
  }))().then(() => done(), (error) => done(error));
158
178
  };
159
- if (callback.length === 0) return function() {
160
- return wrap(() => Reflect.apply(callback, this, []))();
161
- };
162
179
  return function(context) {
163
180
  return wrap(() => Reflect.apply(callback, this, [context]))();
164
181
  };
165
182
  }
183
+ function isPromiseLike(value) {
184
+ return typeof value === "object" && value != null && "then" in value && typeof value.then === "function";
185
+ }
166
186
 
167
187
  //#endregion
168
188
  //#region src/autoload.ts
@@ -176,7 +196,21 @@ if (config == null) (0, __logtape_logtape.configureSync)({
176
196
  }]
177
197
  });
178
198
  else if (config.contextLocalStorage == null) throw new __logtape_logtape.ConfigError("@logtape/testing-node/autoload requires the existing LogTape configuration to provide contextLocalStorage.");
179
- var autoload_default = src_default;
199
+ const reporterOptions = (0, __logtape_testing_reporter.getFailureLogReporterOptionsFromEnv)({ getEnv });
200
+ const test = createTest(reporterOptions);
201
+ const it = createIt(reporterOptions);
202
+ const only = test.only;
203
+ const skip = test.skip;
204
+ const todo = test.todo;
205
+ const expectFailure = test.expectFailure;
206
+ function getEnv(name) {
207
+ try {
208
+ return process.env[name];
209
+ } catch {
210
+ return void 0;
211
+ }
212
+ }
213
+ var autoload_default = test;
180
214
 
181
215
  //#endregion
182
216
  Object.defineProperty(exports, 'after', {
@@ -236,5 +270,5 @@ Object.defineProperty(exports, 'suite', {
236
270
  return node_test.suite;
237
271
  }
238
272
  });
239
- exports.test = src_default;
273
+ exports.test = test;
240
274
  exports.todo = todo;
@@ -75,39 +75,7 @@ declare function createIt(options?: FailureLogReporterOptions$1): NodeTestFuncti
75
75
  *
76
76
  * @since 2.3.0
77
77
  */
78
- declare const test: NodeTestFunction;
79
- /**
80
- * A `node:test` `it()` alias that reports LogTape records from failed test
81
- * callbacks using the default reporter options.
82
- *
83
- * @since 2.3.0
84
- */
85
- declare const it: NodeTestFunction;
86
- /**
87
- * Shorthand for marking a test as `only`.
88
- *
89
- * @since 2.3.0
90
- */
91
- declare const only: NodeTestFunction;
92
- /**
93
- * Shorthand for skipping a test.
94
- *
95
- * @since 2.3.0
96
- */
97
- declare const skip: NodeTestFunction;
98
- /**
99
- * Shorthand for marking a test as TODO.
100
- *
101
- * @since 2.3.0
102
- */
103
- declare const todo: NodeTestFunction;
104
- /**
105
- * Shorthand for expecting a test to fail when supported by the active Node.js
106
- * runtime.
107
- *
108
- * @since 2.3.0
109
- */
110
- declare const expectFailure: NodeTestFunction | undefined;
78
+
111
79
  /**
112
80
  * Node.js' test assertion tracker when supported by the active runtime.
113
81
  *
@@ -121,5 +89,13 @@ declare const assert: unknown;
121
89
  */
122
90
  declare const snapshot: unknown;
123
91
  //#endregion
92
+ //#region src/autoload.d.ts
93
+ declare const test: NodeTestFunction;
94
+ declare const it: NodeTestFunction;
95
+ declare const only: NodeTestFunction["only"];
96
+ declare const skip: NodeTestFunction["skip"];
97
+ declare const todo: NodeTestFunction["todo"];
98
+ declare const expectFailure: NodeTestFunction["expectFailure"];
99
+ //#endregion
124
100
  export { FailureLogReportMode, FailureLogReporterOptions, NodeTestCallback, NodeTestFunction, NodeTestOptions, TestContext, after, afterEach, assert, before, beforeEach, createIt, createTest, test as default, test, describe, expectFailure, it, mock, only, run, skip, snapshot, suite, todo };
125
101
  //# sourceMappingURL=autoload.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"autoload.d.cts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AAgCA;;;;;AAU+B;AAa/B;;;AAES,UAzBQ,eAAA,CAyBR;EAAgB,SAAA,WAAA,CAAA,EAAA,MAAA,GAAA,OAAA;EAQR,SAAA,aAAgB,CAAA,EAAA,OAAA,GAAA,MAAA,GA5B3B,MA4B2B,GAAA,CAAA,CAAA,KAAA,EAAA,OAAA,EAAA,GAAA,OAAA,CAAA,GAAA,MAAA,GAzB3B,KAyB2B;EAAA,SAAA,IAAA,CAAA,EAAA,OAAA;EAAA,SACL,MAAA,CAAA,EAxBR,WAwBQ;EAAe,SAAO,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,IAAA,CAAA,EAAA,SAAA,MAAA,EAAA;EAAO,SAGrD,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,OAAA,CAAA,EAAA,MAAA;EAAO,SACpC,IAAA,CAAA,EAAA,MAAA;;;;;;;AAII,KAnBL,gBAAA,GAmBK,CAAA,OAAA,EAlBN,WAkBM,EAAA,IAAA,CAAA,EAjBR,gBAiBQ,EAAA,GAAA,OAAA;;;;AAGiB;AACjC;AAyBe,UAtCC,gBAAA,CAsCS;EAAA,CAAA,IAAA,CAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EArCE,eAqCF,EAAA,EAAA,CAAA,EArCwB,gBAqCxB,CAAA,EArC2C,OAqC3C,CAAA,IAAA,CAAA;EAAA,CAAA,IACf,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,EAnCY,gBAmCZ,CAAA,EAnC+B,OAmC/B,CAAA,IAAA,CAAA;EAA8B,CAAA,OACtC,CAAA,EAnCU,eAmCV,EAAA,EAAA,CAAA,EAnCgC,gBAmChC,CAAA,EAnCmD,OAmCnD,CAAA,IAAA,CAAA;EAAgB,CAAA,EAAA,CAAA,EAlCX,gBAkCW,CAAA,EAlCQ,OAkCR,CAAA,IAAA,CAAA;EAeH,SAAA,IAAQ,EAhDP,gBAgDO;EAAA,SAAA,IAAA,EA/CP,gBA+CO;EAAA,SACb,IAAA,EA/CM,gBA+CN;EAA8B,SACtC,aAAA,CAAA,EA/CwB,gBA+CxB;EAAgB,SAAA,EAAA,CAAA,EA9CH,gBA8CG;EAaN,SAAqC,IAAA,CAAA,EA1DhC,gBA0DC;AAQnB;AAOA,KAtEK,gBAAA,GAsEc,CAAA,KAA4B,CAA5B,EAAA,OAA4B,EAAA,GAAA,IAAA;AAO/C;AAOA;AAQA;AAOA;AAOA;;;;;;;;iBAnFgB,UAAA,WACL,8BACR;;;;;;;;;iBAea,QAAA,WACL,8BACR;;;;;;;cAaU,MAAM;;;;;;;cAQN,IAAI;;;;;;cAOJ,MAAM;;;;;;cAON,MAAM;;;;;;cAON,MAAM;;;;;;;cAQN,eAAe;;;;;;cAOf;;;;;;cAOA"}
1
+ {"version":3,"file":"autoload.d.cts","names":[],"sources":["../src/mod.ts","../src/autoload.ts"],"sourcesContent":[],"mappings":";;;;;AAmCA;;;;;AAU+B;AAa/B;;;AAES,UAzBQ,eAAA,CAyBR;EAAgB,SAAA,WAAA,CAAA,EAAA,MAAA,GAAA,OAAA;EAQR,SAAA,aAAgB,CAAA,EAAA,OAAA,GAAA,MAAA,GA5B3B,MA4B2B,GAAA,CAAA,CAAA,KAAA,EAAA,OAAA,EAAA,GAAA,OAAA,CAAA,GAAA,MAAA,GAzB3B,KAyB2B;EAAA,SAAA,IAAA,CAAA,EAAA,OAAA;EAAA,SACL,MAAA,CAAA,EAxBR,WAwBQ;EAAe,SAAO,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,IAAA,CAAA,EAAA,SAAA,MAAA,EAAA;EAAO,SAGrD,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,OAAA,CAAA,EAAA,MAAA;EAAO,SACpC,IAAA,CAAA,EAAA,MAAA;;;;;;;AAII,KAnBL,gBAAA,GAmBK,CAAA,OAAA,EAlBN,WAkBM,EAAA,IAAA,CAAA,EAjBR,gBAiBQ,EAAA,GAAA,OAAA;;;;AAGiB;AACjC;AAyBe,UAtCC,gBAAA,CAsCS;EAAA,CAAA,IAAA,CAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EArCE,eAqCF,EAAA,EAAA,CAAA,EArCwB,gBAqCxB,CAAA,EArC2C,OAqC3C,CAAA,IAAA,CAAA;EAAA,CAAA,IACf,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,EAnCY,gBAmCZ,CAAA,EAnC+B,OAmC/B,CAAA,IAAA,CAAA;EAA8B,CAAA,OACtC,CAAA,EAnCU,eAmCV,EAAA,EAAA,CAAA,EAnCgC,gBAmChC,CAAA,EAnCmD,OAmCnD,CAAA,IAAA,CAAA;EAAgB,CAAA,EAAA,CAAA,EAlCX,gBAkCW,CAAA,EAlCQ,OAkCR,CAAA,IAAA,CAAA;EAeH,SAAA,IAAQ,EAhDP,gBAgDO;EAAA,SAAA,IAAA,EA/CP,gBA+CO;EAAA,SACb,IAAA,EA/CM,gBA+CN;EAA8B,SACtC,aAAA,CAAA,EA/CwB,gBA+CxB;EAAgB,SAAA,EAAA,CAAA,EA9CH,gBA8CG;EAyDN,SAAgE,IAAA,CAAA,EAtG3D,gBAsG2D;AAO7E;KA1GK,gBAAA;;;AC/Ca;AAyBwC;AACJ;AAC1B;AACA;AACA;;;;;iBDyCZ,UAAA,WACL,8BACR;;;;;;;;;iBAea,QAAA,WACL,8BACR;;;;;;;;;;;;;cAyDU;;;;;;cAOA;;;cChIP,MAAM;cACN,IAAI;AD3BV,cC4BM,ID5BW,EC4BL,gBD5BoB,CAAA,MAAA,CAAA;cC6B1B,ID7B0B,EC6BpB,gBD7BoB,CAAA,MAAA,CAAA;cC8B1B,IDzBA,ECyBM,gBDzBN,CAAA,MAAA,CAAA;cC0BA,aDvBA,ECuBe,gBDvBf,CAAA,eAAA,CAAA"}
@@ -1,5 +1,5 @@
1
- import { TestContext, after, afterEach, before, beforeEach, describe, mock, run, suite } from "node:test";
2
1
  import { FailureLogReportMode, FailureLogReporterOptions, FailureLogReporterOptions as FailureLogReporterOptions$1 } from "@logtape/testing/reporter";
2
+ import { TestContext, after, afterEach, before, beforeEach, describe, mock, run, suite } from "node:test";
3
3
 
4
4
  //#region src/mod.d.ts
5
5
 
@@ -75,39 +75,7 @@ declare function createIt(options?: FailureLogReporterOptions$1): NodeTestFuncti
75
75
  *
76
76
  * @since 2.3.0
77
77
  */
78
- declare const test: NodeTestFunction;
79
- /**
80
- * A `node:test` `it()` alias that reports LogTape records from failed test
81
- * callbacks using the default reporter options.
82
- *
83
- * @since 2.3.0
84
- */
85
- declare const it: NodeTestFunction;
86
- /**
87
- * Shorthand for marking a test as `only`.
88
- *
89
- * @since 2.3.0
90
- */
91
- declare const only: NodeTestFunction;
92
- /**
93
- * Shorthand for skipping a test.
94
- *
95
- * @since 2.3.0
96
- */
97
- declare const skip: NodeTestFunction;
98
- /**
99
- * Shorthand for marking a test as TODO.
100
- *
101
- * @since 2.3.0
102
- */
103
- declare const todo: NodeTestFunction;
104
- /**
105
- * Shorthand for expecting a test to fail when supported by the active Node.js
106
- * runtime.
107
- *
108
- * @since 2.3.0
109
- */
110
- declare const expectFailure: NodeTestFunction | undefined;
78
+
111
79
  /**
112
80
  * Node.js' test assertion tracker when supported by the active runtime.
113
81
  *
@@ -121,5 +89,13 @@ declare const assert: unknown;
121
89
  */
122
90
  declare const snapshot: unknown;
123
91
  //#endregion
92
+ //#region src/autoload.d.ts
93
+ declare const test: NodeTestFunction;
94
+ declare const it: NodeTestFunction;
95
+ declare const only: NodeTestFunction["only"];
96
+ declare const skip: NodeTestFunction["skip"];
97
+ declare const todo: NodeTestFunction["todo"];
98
+ declare const expectFailure: NodeTestFunction["expectFailure"];
99
+ //#endregion
124
100
  export { FailureLogReportMode, FailureLogReporterOptions, NodeTestCallback, NodeTestFunction, NodeTestOptions, TestContext, after, afterEach, assert, before, beforeEach, createIt, createTest, test as default, test, describe, expectFailure, it, mock, only, run, skip, snapshot, suite, todo };
125
101
  //# sourceMappingURL=autoload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"autoload.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AAgCA;;;;;AAU+B;AAa/B;;;AAES,UAzBQ,eAAA,CAyBR;EAAgB,SAAA,WAAA,CAAA,EAAA,MAAA,GAAA,OAAA;EAQR,SAAA,aAAgB,CAAA,EAAA,OAAA,GAAA,MAAA,GA5B3B,MA4B2B,GAAA,CAAA,CAAA,KAAA,EAAA,OAAA,EAAA,GAAA,OAAA,CAAA,GAAA,MAAA,GAzB3B,KAyB2B;EAAA,SAAA,IAAA,CAAA,EAAA,OAAA;EAAA,SACL,MAAA,CAAA,EAxBR,WAwBQ;EAAe,SAAO,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,IAAA,CAAA,EAAA,SAAA,MAAA,EAAA;EAAO,SAGrD,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,OAAA,CAAA,EAAA,MAAA;EAAO,SACpC,IAAA,CAAA,EAAA,MAAA;;;;;;;AAII,KAnBL,gBAAA,GAmBK,CAAA,OAAA,EAlBN,WAkBM,EAAA,IAAA,CAAA,EAjBR,gBAiBQ,EAAA,GAAA,OAAA;;;;AAGiB;AACjC;AAyBe,UAtCC,gBAAA,CAsCS;EAAA,CAAA,IAAA,CAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EArCE,eAqCF,EAAA,EAAA,CAAA,EArCwB,gBAqCxB,CAAA,EArC2C,OAqC3C,CAAA,IAAA,CAAA;EAAA,CAAA,IACf,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,EAnCY,gBAmCZ,CAAA,EAnC+B,OAmC/B,CAAA,IAAA,CAAA;EAA8B,CAAA,OACtC,CAAA,EAnCU,eAmCV,EAAA,EAAA,CAAA,EAnCgC,gBAmChC,CAAA,EAnCmD,OAmCnD,CAAA,IAAA,CAAA;EAAgB,CAAA,EAAA,CAAA,EAlCX,gBAkCW,CAAA,EAlCQ,OAkCR,CAAA,IAAA,CAAA;EAeH,SAAA,IAAQ,EAhDP,gBAgDO;EAAA,SAAA,IAAA,EA/CP,gBA+CO;EAAA,SACb,IAAA,EA/CM,gBA+CN;EAA8B,SACtC,aAAA,CAAA,EA/CwB,gBA+CxB;EAAgB,SAAA,EAAA,CAAA,EA9CH,gBA8CG;EAaN,SAAqC,IAAA,CAAA,EA1DhC,gBA0DC;AAQnB;AAOA,KAtEK,gBAAA,GAsEc,CAAA,KAA4B,CAA5B,EAAA,OAA4B,EAAA,GAAA,IAAA;AAO/C;AAOA;AAQA;AAOA;AAOA;;;;;;;;iBAnFgB,UAAA,WACL,8BACR;;;;;;;;;iBAea,QAAA,WACL,8BACR;;;;;;;cAaU,MAAM;;;;;;;cAQN,IAAI;;;;;;cAOJ,MAAM;;;;;;cAON,MAAM;;;;;;cAON,MAAM;;;;;;;cAQN,eAAe;;;;;;cAOf;;;;;;cAOA"}
1
+ {"version":3,"file":"autoload.d.ts","names":[],"sources":["../src/mod.ts","../src/autoload.ts"],"sourcesContent":[],"mappings":";;;;;AAmCA;;;;;AAU+B;AAa/B;;;AAES,UAzBQ,eAAA,CAyBR;EAAgB,SAAA,WAAA,CAAA,EAAA,MAAA,GAAA,OAAA;EAQR,SAAA,aAAgB,CAAA,EAAA,OAAA,GAAA,MAAA,GA5B3B,MA4B2B,GAAA,CAAA,CAAA,KAAA,EAAA,OAAA,EAAA,GAAA,OAAA,CAAA,GAAA,MAAA,GAzB3B,KAyB2B;EAAA,SAAA,IAAA,CAAA,EAAA,OAAA;EAAA,SACL,MAAA,CAAA,EAxBR,WAwBQ;EAAe,SAAO,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,IAAA,CAAA,EAAA,SAAA,MAAA,EAAA;EAAO,SAGrD,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,OAAA,CAAA,EAAA,MAAA;EAAO,SACpC,IAAA,CAAA,EAAA,MAAA;;;;;;;AAII,KAnBL,gBAAA,GAmBK,CAAA,OAAA,EAlBN,WAkBM,EAAA,IAAA,CAAA,EAjBR,gBAiBQ,EAAA,GAAA,OAAA;;;;AAGiB;AACjC;AAyBe,UAtCC,gBAAA,CAsCS;EAAA,CAAA,IAAA,CAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EArCE,eAqCF,EAAA,EAAA,CAAA,EArCwB,gBAqCxB,CAAA,EArC2C,OAqC3C,CAAA,IAAA,CAAA;EAAA,CAAA,IACf,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,EAnCY,gBAmCZ,CAAA,EAnC+B,OAmC/B,CAAA,IAAA,CAAA;EAA8B,CAAA,OACtC,CAAA,EAnCU,eAmCV,EAAA,EAAA,CAAA,EAnCgC,gBAmChC,CAAA,EAnCmD,OAmCnD,CAAA,IAAA,CAAA;EAAgB,CAAA,EAAA,CAAA,EAlCX,gBAkCW,CAAA,EAlCQ,OAkCR,CAAA,IAAA,CAAA;EAeH,SAAA,IAAQ,EAhDP,gBAgDO;EAAA,SAAA,IAAA,EA/CP,gBA+CO;EAAA,SACb,IAAA,EA/CM,gBA+CN;EAA8B,SACtC,aAAA,CAAA,EA/CwB,gBA+CxB;EAAgB,SAAA,EAAA,CAAA,EA9CH,gBA8CG;EAyDN,SAAgE,IAAA,CAAA,EAtG3D,gBAsG2D;AAO7E;KA1GK,gBAAA;;;AC/Ca;AAyBwC;AACJ;AAC1B;AACA;AACA;;;;;iBDyCZ,UAAA,WACL,8BACR;;;;;;;;;iBAea,QAAA,WACL,8BACR;;;;;;;;;;;;;cAyDU;;;;;;cAOA;;;cChIP,MAAM;cACN,IAAI;AD3BV,cC4BM,ID5BW,EC4BL,gBD5BoB,CAAA,MAAA,CAAA;cC6B1B,ID7B0B,EC6BpB,gBD7BoB,CAAA,MAAA,CAAA;cC8B1B,IDzBA,ECyBM,gBDzBN,CAAA,MAAA,CAAA;cC0BA,aDvBA,ECuBe,gBDvBf,CAAA,eAAA,CAAA"}
package/dist/autoload.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { ConfigError, configureSync, getConfig } from "@logtape/logtape";
3
+ import { createFailureLogReporter, getFailureLogReporterOptionsFromEnv } from "@logtape/testing/reporter";
3
4
  import nodeTest, { after, afterEach, before, beforeEach, describe, it as it$1, mock, run, suite } from "node:test";
4
- import { createFailureLogReporter } from "@logtape/testing/reporter";
5
5
 
6
6
  //#region src/mod.ts
7
7
  /**
@@ -36,52 +36,51 @@ function createIt(options = {}) {
36
36
  *
37
37
  * @since 2.3.0
38
38
  */
39
- const test = createTest();
39
+ const test$1 = createTest();
40
40
  /**
41
41
  * A `node:test` `it()` alias that reports LogTape records from failed test
42
42
  * callbacks using the default reporter options.
43
43
  *
44
44
  * @since 2.3.0
45
45
  */
46
- const it = createIt();
46
+ const it$2 = createIt();
47
47
  /**
48
48
  * Shorthand for marking a test as `only`.
49
49
  *
50
50
  * @since 2.3.0
51
51
  */
52
- const only = test.only;
52
+ const only$1 = test$1.only;
53
53
  /**
54
54
  * Shorthand for skipping a test.
55
55
  *
56
56
  * @since 2.3.0
57
57
  */
58
- const skip = test.skip;
58
+ const skip$1 = test$1.skip;
59
59
  /**
60
60
  * Shorthand for marking a test as TODO.
61
61
  *
62
62
  * @since 2.3.0
63
63
  */
64
- const todo = test.todo;
64
+ const todo$1 = test$1.todo;
65
65
  /**
66
66
  * Shorthand for expecting a test to fail when supported by the active Node.js
67
67
  * runtime.
68
68
  *
69
69
  * @since 2.3.0
70
70
  */
71
- const expectFailure = test.expectFailure;
71
+ const expectFailure$1 = test$1.expectFailure;
72
72
  /**
73
73
  * Node.js' test assertion tracker when supported by the active runtime.
74
74
  *
75
75
  * @since 2.3.0
76
76
  */
77
- const assert = test.assert;
77
+ const assert = test$1.assert;
78
78
  /**
79
79
  * Node.js' snapshot helper when supported by the active runtime.
80
80
  *
81
81
  * @since 2.3.0
82
82
  */
83
- const snapshot = test.snapshot;
84
- var src_default = test;
83
+ const snapshot = test$1.snapshot;
85
84
  function createNodeTestFunction(baseTest, options, includeExtendedProperties = true) {
86
85
  const register = (...args) => Reflect.apply(baseTest, void 0, wrapCallbackArgument(args, options));
87
86
  const baseExpectFailure = baseTest.expectFailure;
@@ -118,27 +117,48 @@ function wrapNodeCallback(wrap, callback) {
118
117
  if (callback.length >= 2) return function(context, done) {
119
118
  const runCallback = (...args) => Reflect.apply(callback, this, args);
120
119
  wrap(() => new Promise((resolve, reject) => {
120
+ let callbackReturned = false;
121
+ let doneCalled = false;
122
+ let pendingDone = false;
123
+ let pendingDoneError;
121
124
  let settled = false;
122
- const wrappedDone = (error) => {
125
+ const settle = (error) => {
123
126
  if (settled) return;
124
127
  settled = true;
125
128
  if (error == null) resolve();
126
129
  else reject(error);
127
130
  };
131
+ const wrappedDone = (error) => {
132
+ if (doneCalled) return;
133
+ doneCalled = true;
134
+ if (!callbackReturned) {
135
+ pendingDone = true;
136
+ pendingDoneError = error;
137
+ return;
138
+ }
139
+ settle(error);
140
+ };
128
141
  try {
129
- runCallback(context, wrappedDone);
142
+ const result = runCallback(context, wrappedDone);
143
+ callbackReturned = true;
144
+ if (isPromiseLike(result)) {
145
+ reject(new TypeError("Callback-style node:test functions must not return a Promise."));
146
+ return;
147
+ }
148
+ if (pendingDone) settle(pendingDoneError);
130
149
  } catch (error) {
150
+ callbackReturned = true;
131
151
  reject(error);
132
152
  }
133
153
  }))().then(() => done(), (error) => done(error));
134
154
  };
135
- if (callback.length === 0) return function() {
136
- return wrap(() => Reflect.apply(callback, this, []))();
137
- };
138
155
  return function(context) {
139
156
  return wrap(() => Reflect.apply(callback, this, [context]))();
140
157
  };
141
158
  }
159
+ function isPromiseLike(value) {
160
+ return typeof value === "object" && value != null && "then" in value && typeof value.then === "function";
161
+ }
142
162
 
143
163
  //#endregion
144
164
  //#region src/autoload.ts
@@ -152,8 +172,22 @@ if (config == null) configureSync({
152
172
  }]
153
173
  });
154
174
  else if (config.contextLocalStorage == null) throw new ConfigError("@logtape/testing-node/autoload requires the existing LogTape configuration to provide contextLocalStorage.");
155
- var autoload_default = src_default;
175
+ const reporterOptions = getFailureLogReporterOptionsFromEnv({ getEnv });
176
+ const test = createTest(reporterOptions);
177
+ const it = createIt(reporterOptions);
178
+ const only = test.only;
179
+ const skip = test.skip;
180
+ const todo = test.todo;
181
+ const expectFailure = test.expectFailure;
182
+ function getEnv(name) {
183
+ try {
184
+ return process.env[name];
185
+ } catch {
186
+ return void 0;
187
+ }
188
+ }
189
+ var autoload_default = test;
156
190
 
157
191
  //#endregion
158
- export { after, afterEach, assert, before, beforeEach, createIt, createTest, autoload_default as default, describe, expectFailure, it, mock, only, run, skip, snapshot, suite, src_default as test, todo };
192
+ export { after, afterEach, assert, before, beforeEach, createIt, createTest, autoload_default as default, describe, expectFailure, it, mock, only, run, skip, snapshot, suite, test, todo };
159
193
  //# sourceMappingURL=autoload.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"autoload.js","names":["options: FailureLogReporterOptions","nodeIt","test: NodeTestFunction","it: NodeTestFunction","only: NodeTestFunction","skip: NodeTestFunction","todo: NodeTestFunction","expectFailure: NodeTestFunction | undefined","assert: unknown","snapshot: unknown","baseTest: BaseNodeTestFunction","args: readonly unknown[]","wrap: ReturnType<typeof createFailureLogReporter>[\"wrap\"]","callback: AnyFunction","context: TestContext","done: NodeDoneCallback","wrappedDone: NodeDoneCallback","error?: unknown","error: unknown","test"],"sources":["../src/mod.ts","../src/autoload.ts"],"sourcesContent":["import nodeTest, { it as nodeIt } from \"node:test\";\nimport type { TestContext } from \"node:test\";\n\nimport {\n createFailureLogReporter,\n type FailureLogReporterOptions,\n} from \"@logtape/testing/reporter\";\n\nexport type {\n FailureLogReporterOptions,\n FailureLogReportMode,\n} from \"@logtape/testing/reporter\";\nexport {\n after,\n afterEach,\n before,\n beforeEach,\n describe,\n mock,\n run,\n suite,\n} from \"node:test\";\n\n/**\n * Options accepted by Node.js `test()` and `it()` functions.\n *\n * The shape intentionally mirrors Node's documented option bag while allowing\n * newer Node.js options to pass through even when a runtime's bundled TypeScript\n * declarations lag behind the current documentation.\n *\n * @since 2.3.0\n */\nexport interface NodeTestOptions {\n readonly concurrency?: number | boolean;\n readonly expectFailure?:\n | boolean\n | string\n | RegExp\n | ((error: unknown) => boolean)\n | object\n | Error;\n readonly only?: boolean;\n readonly signal?: AbortSignal;\n readonly skip?: boolean | string;\n readonly tags?: readonly string[];\n readonly todo?: boolean | string;\n readonly timeout?: number;\n readonly plan?: number;\n}\n\n/**\n * A callback passed to Node.js `test()` or `it()`.\n *\n * @since 2.3.0\n */\nexport type NodeTestCallback = (\n context: TestContext,\n done?: NodeDoneCallback,\n) => unknown;\n\n/**\n * A Node.js `test()`-compatible function.\n *\n * @since 2.3.0\n */\nexport interface NodeTestFunction {\n (name?: string, options?: NodeTestOptions, fn?: NodeTestCallback): Promise<\n void\n >;\n (name?: string, fn?: NodeTestCallback): Promise<void>;\n (options?: NodeTestOptions, fn?: NodeTestCallback): Promise<void>;\n (fn?: NodeTestCallback): Promise<void>;\n readonly only: NodeTestFunction;\n readonly skip: NodeTestFunction;\n readonly todo: NodeTestFunction;\n readonly expectFailure?: NodeTestFunction;\n readonly it?: NodeTestFunction;\n readonly test?: NodeTestFunction;\n}\n\ntype NodeDoneCallback = (error?: unknown) => void;\ntype AnyFunction = (...args: never[]) => unknown;\ntype BaseNodeTestFunction = AnyFunction & {\n readonly only: AnyFunction;\n readonly skip: AnyFunction;\n readonly todo: AnyFunction;\n readonly expectFailure?: AnyFunction;\n readonly it?: AnyFunction;\n readonly test?: AnyFunction;\n};\n\n/**\n * Creates a `node:test` test function that reports LogTape records from failed\n * test callbacks.\n *\n * The returned function preserves Node.js test options and shorthand helpers\n * such as `test.only()`, `test.skip()`, and `test.todo()`. Only callback\n * arguments are adapted; options are passed through to `node:test`.\n *\n * @param options Failure log reporter options.\n * @returns A configured `node:test`-compatible test function.\n * @since 2.3.0\n */\nexport function createTest(\n options: FailureLogReporterOptions = {},\n): NodeTestFunction {\n return createNodeTestFunction(\n nodeTest as unknown as BaseNodeTestFunction,\n options,\n );\n}\n\n/**\n * Creates an `it()` alias that reports LogTape records from failed test\n * callbacks.\n *\n * @param options Failure log reporter options.\n * @returns A configured `node:test`-compatible `it()` function.\n * @since 2.3.0\n */\nexport function createIt(\n options: FailureLogReporterOptions = {},\n): NodeTestFunction {\n return createNodeTestFunction(\n nodeIt as unknown as BaseNodeTestFunction,\n options,\n );\n}\n\n/**\n * A `node:test` test function that reports LogTape records from failed test\n * callbacks using the default reporter options.\n *\n * @since 2.3.0\n */\nexport const test: NodeTestFunction = createTest();\n\n/**\n * A `node:test` `it()` alias that reports LogTape records from failed test\n * callbacks using the default reporter options.\n *\n * @since 2.3.0\n */\nexport const it: NodeTestFunction = createIt();\n\n/**\n * Shorthand for marking a test as `only`.\n *\n * @since 2.3.0\n */\nexport const only: NodeTestFunction = test.only;\n\n/**\n * Shorthand for skipping a test.\n *\n * @since 2.3.0\n */\nexport const skip: NodeTestFunction = test.skip;\n\n/**\n * Shorthand for marking a test as TODO.\n *\n * @since 2.3.0\n */\nexport const todo: NodeTestFunction = test.todo;\n\n/**\n * Shorthand for expecting a test to fail when supported by the active Node.js\n * runtime.\n *\n * @since 2.3.0\n */\nexport const expectFailure: NodeTestFunction | undefined = test.expectFailure;\n\n/**\n * Node.js' test assertion tracker when supported by the active runtime.\n *\n * @since 2.3.0\n */\nexport const assert: unknown = (test as { readonly assert?: unknown }).assert;\n\n/**\n * Node.js' snapshot helper when supported by the active runtime.\n *\n * @since 2.3.0\n */\nexport const snapshot: unknown = (test as { readonly snapshot?: unknown })\n .snapshot;\n\nexport default test;\n\nfunction createNodeTestFunction(\n baseTest: BaseNodeTestFunction,\n options: FailureLogReporterOptions,\n includeExtendedProperties = true,\n): NodeTestFunction {\n const register = ((...args: unknown[]) =>\n Reflect.apply(\n baseTest,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction;\n\n const baseExpectFailure = baseTest.expectFailure;\n const wrapped = Object.assign(register, baseTest, {\n only: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.only,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"only\"],\n skip: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.skip,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"skip\"],\n todo: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.todo,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"todo\"],\n expectFailure: typeof baseExpectFailure === \"function\"\n ? ((...args: unknown[]) =>\n Reflect.apply(\n baseExpectFailure,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"expectFailure\"]\n : undefined,\n });\n\n if (includeExtendedProperties) {\n if (typeof baseTest.it === \"function\") {\n Object.defineProperty(wrapped, \"it\", {\n configurable: true,\n enumerable: true,\n value: createNodeTestFunction(\n baseTest.it as BaseNodeTestFunction,\n options,\n false,\n ),\n writable: true,\n });\n }\n if (typeof baseTest.test === \"function\") {\n Object.defineProperty(wrapped, \"test\", {\n configurable: true,\n enumerable: true,\n value: wrapped,\n writable: true,\n });\n }\n }\n\n return wrapped;\n}\n\nfunction wrapCallbackArgument(\n args: readonly unknown[],\n options: FailureLogReporterOptions,\n): unknown[] {\n const callback = args.at(-1);\n if (typeof callback !== \"function\") return [...args];\n\n const reporter = createFailureLogReporter(options);\n const wrapped = wrapNodeCallback(\n reporter.wrap.bind(reporter),\n callback as unknown as AnyFunction,\n );\n return [...args.slice(0, -1), wrapped];\n}\n\nfunction wrapNodeCallback(\n wrap: ReturnType<typeof createFailureLogReporter>[\"wrap\"],\n callback: AnyFunction,\n): AnyFunction {\n if (callback.length >= 2) {\n return function (\n this: unknown,\n context: TestContext,\n done: NodeDoneCallback,\n ): void {\n const runCallback = (...args: readonly unknown[]): unknown =>\n Reflect.apply(callback, this, args);\n void wrap(() =>\n new Promise<void>((resolve, reject) => {\n let settled = false;\n const wrappedDone: NodeDoneCallback = ((error?: unknown) => {\n if (settled) return;\n settled = true;\n if (error == null) resolve();\n else reject(error);\n }) as NodeDoneCallback;\n\n try {\n runCallback(context, wrappedDone);\n } catch (error) {\n reject(error);\n }\n })\n )().then(\n () => done(),\n (error: unknown) => done(error),\n );\n };\n }\n\n if (callback.length === 0) {\n return function (this: unknown): Promise<unknown> {\n return wrap(() => Reflect.apply(callback, this, []))();\n };\n }\n\n return function (this: unknown, context: TestContext): Promise<unknown> {\n return wrap(() => Reflect.apply(callback, this, [context]))();\n };\n}\n\nexport type { TestContext };\n","import { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport {\n ConfigError,\n configureSync,\n type ContextLocalStorage,\n getConfig,\n} from \"@logtape/logtape\";\n\nimport {\n after,\n afterEach,\n assert,\n before,\n beforeEach,\n createIt,\n createTest,\n default as test,\n describe,\n expectFailure,\n it,\n mock,\n only,\n run,\n skip,\n snapshot,\n suite,\n todo,\n} from \"./mod.ts\";\n\nexport type {\n FailureLogReporterOptions,\n FailureLogReportMode,\n NodeTestCallback,\n NodeTestFunction,\n NodeTestOptions,\n TestContext,\n} from \"./mod.ts\";\n\nconst config = getConfig();\n\nif (config == null) {\n configureSync({\n contextLocalStorage: new AsyncLocalStorage() as ContextLocalStorage<\n Record<string, unknown>\n >,\n sinks: {},\n loggers: [\n { category: [\"logtape\", \"meta\"], sinks: [] },\n ],\n });\n} else if (config.contextLocalStorage == null) {\n throw new ConfigError(\n \"@logtape/testing-node/autoload requires the existing LogTape \" +\n \"configuration to provide contextLocalStorage.\",\n );\n}\n\nexport {\n after,\n afterEach,\n assert,\n before,\n beforeEach,\n createIt,\n createTest,\n describe,\n expectFailure,\n it,\n mock,\n only,\n run,\n skip,\n snapshot,\n suite,\n test,\n todo,\n};\nexport default test;\n"],"mappings":"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"}
1
+ {"version":3,"file":"autoload.js","names":["options: FailureLogReporterOptions","nodeIt","test: NodeTestFunction","it: NodeTestFunction","only: NodeTestFunction","test","skip: NodeTestFunction","todo: NodeTestFunction","expectFailure: NodeTestFunction | undefined","assert: unknown","snapshot: unknown","baseTest: BaseNodeTestFunction","register: NodeTestFunction","args: readonly unknown[]","wrap: ReturnType<typeof createFailureLogReporter>[\"wrap\"]","callback: AnyFunction","context: TestContext","done: NodeDoneCallback","pendingDoneError: unknown","error?: unknown","wrappedDone: NodeDoneCallback","error: unknown","value: unknown","reporterOptions: FailureLogReporterOptions","test: NodeTestFunction","it: NodeTestFunction","only: NodeTestFunction[\"only\"]","skip: NodeTestFunction[\"skip\"]","todo: NodeTestFunction[\"todo\"]","expectFailure: NodeTestFunction[\"expectFailure\"]","name: string"],"sources":["../src/mod.ts","../src/autoload.ts"],"sourcesContent":["// deno-coverage-ignore-file -- This package targets node:test. Deno's\n// node:test shim rejects the nested registrations needed by the integration\n// tests, so coverage for this module comes from the Node.js and Bun jobs.\nimport nodeTest, { it as nodeIt } from \"node:test\";\nimport type { TestContext } from \"node:test\";\n\nimport {\n createFailureLogReporter,\n type FailureLogReporterOptions,\n} from \"@logtape/testing/reporter\";\n\nexport type {\n FailureLogReporterOptions,\n FailureLogReportMode,\n} from \"@logtape/testing/reporter\";\nexport {\n after,\n afterEach,\n before,\n beforeEach,\n describe,\n mock,\n run,\n suite,\n} from \"node:test\";\n\n/**\n * Options accepted by Node.js `test()` and `it()` functions.\n *\n * The shape intentionally mirrors Node's documented option bag while allowing\n * newer Node.js options to pass through even when a runtime's bundled TypeScript\n * declarations lag behind the current documentation.\n *\n * @since 2.3.0\n */\nexport interface NodeTestOptions {\n readonly concurrency?: number | boolean;\n readonly expectFailure?:\n | boolean\n | string\n | RegExp\n | ((error: unknown) => boolean)\n | object\n | Error;\n readonly only?: boolean;\n readonly signal?: AbortSignal;\n readonly skip?: boolean | string;\n readonly tags?: readonly string[];\n readonly todo?: boolean | string;\n readonly timeout?: number;\n readonly plan?: number;\n}\n\n/**\n * A callback passed to Node.js `test()` or `it()`.\n *\n * @since 2.3.0\n */\nexport type NodeTestCallback = (\n context: TestContext,\n done?: NodeDoneCallback,\n) => unknown;\n\n/**\n * A Node.js `test()`-compatible function.\n *\n * @since 2.3.0\n */\nexport interface NodeTestFunction {\n (name?: string, options?: NodeTestOptions, fn?: NodeTestCallback): Promise<\n void\n >;\n (name?: string, fn?: NodeTestCallback): Promise<void>;\n (options?: NodeTestOptions, fn?: NodeTestCallback): Promise<void>;\n (fn?: NodeTestCallback): Promise<void>;\n readonly only: NodeTestFunction;\n readonly skip: NodeTestFunction;\n readonly todo: NodeTestFunction;\n readonly expectFailure?: NodeTestFunction;\n readonly it?: NodeTestFunction;\n readonly test?: NodeTestFunction;\n}\n\ntype NodeDoneCallback = (error?: unknown) => void;\ntype AnyFunction = (...args: never[]) => unknown;\ntype BaseNodeTestFunction = AnyFunction & {\n readonly only: AnyFunction;\n readonly skip: AnyFunction;\n readonly todo: AnyFunction;\n readonly expectFailure?: AnyFunction;\n readonly it?: AnyFunction;\n readonly test?: AnyFunction;\n};\n\n/**\n * Creates a `node:test` test function that reports LogTape records from failed\n * test callbacks.\n *\n * The returned function preserves Node.js test options and shorthand helpers\n * such as `test.only()`, `test.skip()`, and `test.todo()`. Only callback\n * arguments are adapted; options are passed through to `node:test`.\n *\n * @param options Failure log reporter options.\n * @returns A configured `node:test`-compatible test function.\n * @since 2.3.0\n */\nexport function createTest(\n options: FailureLogReporterOptions = {},\n): NodeTestFunction {\n return createNodeTestFunction(\n nodeTest as unknown as BaseNodeTestFunction,\n options,\n );\n}\n\n/**\n * Creates an `it()` alias that reports LogTape records from failed test\n * callbacks.\n *\n * @param options Failure log reporter options.\n * @returns A configured `node:test`-compatible `it()` function.\n * @since 2.3.0\n */\nexport function createIt(\n options: FailureLogReporterOptions = {},\n): NodeTestFunction {\n return createNodeTestFunction(\n nodeIt as unknown as BaseNodeTestFunction,\n options,\n );\n}\n\n/**\n * A `node:test` test function that reports LogTape records from failed test\n * callbacks using the default reporter options.\n *\n * @since 2.3.0\n */\nexport const test: NodeTestFunction = createTest();\n\n/**\n * A `node:test` `it()` alias that reports LogTape records from failed test\n * callbacks using the default reporter options.\n *\n * @since 2.3.0\n */\nexport const it: NodeTestFunction = createIt();\n\n/**\n * Shorthand for marking a test as `only`.\n *\n * @since 2.3.0\n */\nexport const only: NodeTestFunction = test.only;\n\n/**\n * Shorthand for skipping a test.\n *\n * @since 2.3.0\n */\nexport const skip: NodeTestFunction = test.skip;\n\n/**\n * Shorthand for marking a test as TODO.\n *\n * @since 2.3.0\n */\nexport const todo: NodeTestFunction = test.todo;\n\n/**\n * Shorthand for expecting a test to fail when supported by the active Node.js\n * runtime.\n *\n * @since 2.3.0\n */\nexport const expectFailure: NodeTestFunction | undefined = test.expectFailure;\n\n/**\n * Node.js' test assertion tracker when supported by the active runtime.\n *\n * @since 2.3.0\n */\nexport const assert: unknown = (test as { readonly assert?: unknown }).assert;\n\n/**\n * Node.js' snapshot helper when supported by the active runtime.\n *\n * @since 2.3.0\n */\nexport const snapshot: unknown = (test as { readonly snapshot?: unknown })\n .snapshot;\n\nexport default test;\n\nfunction createNodeTestFunction(\n baseTest: BaseNodeTestFunction,\n options: FailureLogReporterOptions,\n includeExtendedProperties = true,\n): NodeTestFunction {\n const register: NodeTestFunction = ((...args: unknown[]) =>\n Reflect.apply(\n baseTest,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction;\n\n const baseExpectFailure = baseTest.expectFailure;\n const wrapped = Object.assign(register, baseTest, {\n only: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.only,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"only\"],\n skip: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.skip,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"skip\"],\n todo: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.todo,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"todo\"],\n expectFailure: typeof baseExpectFailure === \"function\"\n ? ((...args: unknown[]) =>\n Reflect.apply(\n baseExpectFailure,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"expectFailure\"]\n : undefined,\n });\n\n if (includeExtendedProperties) {\n if (typeof baseTest.it === \"function\") {\n Object.defineProperty(wrapped, \"it\", {\n configurable: true,\n enumerable: true,\n value: createNodeTestFunction(\n baseTest.it as BaseNodeTestFunction,\n options,\n false,\n ),\n writable: true,\n });\n }\n if (typeof baseTest.test === \"function\") {\n Object.defineProperty(wrapped, \"test\", {\n configurable: true,\n enumerable: true,\n value: wrapped,\n writable: true,\n });\n }\n }\n\n return wrapped;\n}\n\nfunction wrapCallbackArgument(\n args: readonly unknown[],\n options: FailureLogReporterOptions,\n): unknown[] {\n const callback = args.at(-1);\n if (typeof callback !== \"function\") return [...args];\n\n const reporter = createFailureLogReporter(options);\n const wrapped = wrapNodeCallback(\n reporter.wrap.bind(reporter),\n callback as unknown as AnyFunction,\n );\n return [...args.slice(0, -1), wrapped];\n}\n\nfunction wrapNodeCallback(\n wrap: ReturnType<typeof createFailureLogReporter>[\"wrap\"],\n callback: AnyFunction,\n): AnyFunction {\n if (callback.length >= 2) {\n return function (\n this: unknown,\n context: TestContext,\n done: NodeDoneCallback,\n ): void {\n const runCallback = (...args: readonly unknown[]): unknown =>\n Reflect.apply(callback, this, args);\n void wrap(() =>\n new Promise<void>((resolve, reject) => {\n let callbackReturned = false;\n let doneCalled = false;\n let pendingDone = false;\n let pendingDoneError: unknown;\n let settled = false;\n const settle = (error?: unknown): void => {\n if (settled) return;\n settled = true;\n if (error == null) resolve();\n else reject(error);\n };\n const wrappedDone: NodeDoneCallback = ((error?: unknown) => {\n if (doneCalled) return;\n doneCalled = true;\n if (!callbackReturned) {\n pendingDone = true;\n pendingDoneError = error;\n return;\n }\n settle(error);\n }) as NodeDoneCallback;\n\n try {\n const result = runCallback(context, wrappedDone);\n callbackReturned = true;\n if (isPromiseLike(result)) {\n reject(\n new TypeError(\n \"Callback-style node:test functions must not return a Promise.\",\n ),\n );\n return;\n }\n if (pendingDone) settle(pendingDoneError);\n } catch (error) {\n callbackReturned = true;\n reject(error);\n }\n })\n )().then(\n () => done(),\n (error: unknown) => done(error),\n );\n };\n }\n\n return function (this: unknown, context: TestContext): unknown {\n return wrap(() => Reflect.apply(callback, this, [context]))();\n };\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return typeof value === \"object\" && value != null &&\n \"then\" in value &&\n typeof value.then === \"function\";\n}\n\nexport type { TestContext };\n","import { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport {\n ConfigError,\n configureSync,\n type ContextLocalStorage,\n getConfig,\n} from \"@logtape/logtape\";\nimport {\n type FailureLogReporterOptions,\n getFailureLogReporterOptionsFromEnv,\n} from \"@logtape/testing/reporter\";\n\nimport {\n after,\n afterEach,\n assert,\n before,\n beforeEach,\n createIt,\n createTest,\n describe,\n mock,\n type NodeTestFunction,\n run,\n snapshot,\n suite,\n} from \"./mod.ts\";\n\nexport type {\n FailureLogReporterOptions,\n FailureLogReportMode,\n NodeTestCallback,\n NodeTestFunction,\n NodeTestOptions,\n TestContext,\n} from \"./mod.ts\";\n\nconst config = getConfig();\n\nif (config == null) {\n configureSync({\n contextLocalStorage: new AsyncLocalStorage() as ContextLocalStorage<\n Record<string, unknown>\n >,\n sinks: {},\n loggers: [\n { category: [\"logtape\", \"meta\"], sinks: [] },\n ],\n });\n} else if (config.contextLocalStorage == null) {\n throw new ConfigError(\n \"@logtape/testing-node/autoload requires the existing LogTape \" +\n \"configuration to provide contextLocalStorage.\",\n );\n}\n\nconst reporterOptions: FailureLogReporterOptions =\n getFailureLogReporterOptionsFromEnv({\n getEnv,\n });\nconst test: NodeTestFunction = createTest(reporterOptions);\nconst it: NodeTestFunction = createIt(reporterOptions);\nconst only: NodeTestFunction[\"only\"] = test.only;\nconst skip: NodeTestFunction[\"skip\"] = test.skip;\nconst todo: NodeTestFunction[\"todo\"] = test.todo;\nconst expectFailure: NodeTestFunction[\"expectFailure\"] = test.expectFailure;\n\nfunction getEnv(name: string): string | undefined {\n try {\n return process.env[name];\n } catch {\n return undefined;\n }\n}\n\nexport {\n after,\n afterEach,\n assert,\n before,\n beforeEach,\n createIt,\n createTest,\n describe,\n expectFailure,\n it,\n mock,\n only,\n run,\n skip,\n snapshot,\n suite,\n test,\n todo,\n};\nexport default test;\n"],"mappings":"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"}
package/dist/mod.cjs CHANGED
@@ -118,27 +118,48 @@ function wrapNodeCallback(wrap, callback) {
118
118
  if (callback.length >= 2) return function(context, done) {
119
119
  const runCallback = (...args) => Reflect.apply(callback, this, args);
120
120
  wrap(() => new Promise((resolve, reject) => {
121
+ let callbackReturned = false;
122
+ let doneCalled = false;
123
+ let pendingDone = false;
124
+ let pendingDoneError;
121
125
  let settled = false;
122
- const wrappedDone = (error) => {
126
+ const settle = (error) => {
123
127
  if (settled) return;
124
128
  settled = true;
125
129
  if (error == null) resolve();
126
130
  else reject(error);
127
131
  };
132
+ const wrappedDone = (error) => {
133
+ if (doneCalled) return;
134
+ doneCalled = true;
135
+ if (!callbackReturned) {
136
+ pendingDone = true;
137
+ pendingDoneError = error;
138
+ return;
139
+ }
140
+ settle(error);
141
+ };
128
142
  try {
129
- runCallback(context, wrappedDone);
143
+ const result = runCallback(context, wrappedDone);
144
+ callbackReturned = true;
145
+ if (isPromiseLike(result)) {
146
+ reject(new TypeError("Callback-style node:test functions must not return a Promise."));
147
+ return;
148
+ }
149
+ if (pendingDone) settle(pendingDoneError);
130
150
  } catch (error) {
151
+ callbackReturned = true;
131
152
  reject(error);
132
153
  }
133
154
  }))().then(() => done(), (error) => done(error));
134
155
  };
135
- if (callback.length === 0) return function() {
136
- return wrap(() => Reflect.apply(callback, this, []))();
137
- };
138
156
  return function(context) {
139
157
  return wrap(() => Reflect.apply(callback, this, [context]))();
140
158
  };
141
159
  }
160
+ function isPromiseLike(value) {
161
+ return typeof value === "object" && value != null && "then" in value && typeof value.then === "function";
162
+ }
142
163
 
143
164
  //#endregion
144
165
  Object.defineProperty(exports, 'after', {
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.cts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AAgCA;;;;;AAU+B;AAa/B;;;AAES,UAzBQ,eAAA,CAyBR;EAAgB,SAAA,WAAA,CAAA,EAAA,MAAA,GAAA,OAAA;EAQR,SAAA,aAAgB,CAAA,EAAA,OAAA,GAAA,MAAA,GA5B3B,MA4B2B,GAAA,CAAA,CAAA,KAAA,EAAA,OAAA,EAAA,GAAA,OAAA,CAAA,GAAA,MAAA,GAzB3B,KAyB2B;EAAA,SAAA,IAAA,CAAA,EAAA,OAAA;EAAA,SACL,MAAA,CAAA,EAxBR,WAwBQ;EAAe,SAAO,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,IAAA,CAAA,EAAA,SAAA,MAAA,EAAA;EAAO,SAGrD,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,OAAA,CAAA,EAAA,MAAA;EAAO,SACpC,IAAA,CAAA,EAAA,MAAA;;;;;;;AAII,KAnBL,gBAAA,GAmBK,CAAA,OAAA,EAlBN,WAkBM,EAAA,IAAA,CAAA,EAjBR,gBAiBQ,EAAA,GAAA,OAAA;;;;AAGiB;AACjC;AAyBe,UAtCC,gBAAA,CAsCS;EAAA,CAAA,IAAA,CAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EArCE,eAqCF,EAAA,EAAA,CAAA,EArCwB,gBAqCxB,CAAA,EArC2C,OAqC3C,CAAA,IAAA,CAAA;EAAA,CAAA,IACf,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,EAnCY,gBAmCZ,CAAA,EAnC+B,OAmC/B,CAAA,IAAA,CAAA;EAA8B,CAAA,OACtC,CAAA,EAnCU,eAmCV,EAAA,EAAA,CAAA,EAnCgC,gBAmChC,CAAA,EAnCmD,OAmCnD,CAAA,IAAA,CAAA;EAAgB,CAAA,EAAA,CAAA,EAlCX,gBAkCW,CAAA,EAlCQ,OAkCR,CAAA,IAAA,CAAA;EAeH,SAAA,IAAQ,EAhDP,gBAgDO;EAAA,SAAA,IAAA,EA/CP,gBA+CO;EAAA,SACb,IAAA,EA/CM,gBA+CN;EAA8B,SACtC,aAAA,CAAA,EA/CwB,gBA+CxB;EAAgB,SAAA,EAAA,CAAA,EA9CH,gBA8CG;EAaN,SAAqC,IAAA,CAAA,EA1DhC,gBA0DC;AAQnB;AAOA,KAtEK,gBAAA,GAsEc,CAAA,KAA4B,CAA5B,EAAA,OAA4B,EAAA,GAAA,IAAA;AAO/C;AAOA;AAQA;AAOA;AAOA;;;;;;;;iBAnFgB,UAAA,WACL,8BACR;;;;;;;;;iBAea,QAAA,WACL,8BACR;;;;;;;cAaU,MAAM;;;;;;;cAQN,IAAI;;;;;;cAOJ,MAAM;;;;;;cAON,MAAM;;;;;;cAON,MAAM;;;;;;;cAQN,eAAe;;;;;;cAOf;;;;;;cAOA"}
1
+ {"version":3,"file":"mod.d.cts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AAmCA;;;;;AAU+B;AAa/B;;;AAES,UAzBQ,eAAA,CAyBR;EAAgB,SAAA,WAAA,CAAA,EAAA,MAAA,GAAA,OAAA;EAQR,SAAA,aAAgB,CAAA,EAAA,OAAA,GAAA,MAAA,GA5B3B,MA4B2B,GAAA,CAAA,CAAA,KAAA,EAAA,OAAA,EAAA,GAAA,OAAA,CAAA,GAAA,MAAA,GAzB3B,KAyB2B;EAAA,SAAA,IAAA,CAAA,EAAA,OAAA;EAAA,SACL,MAAA,CAAA,EAxBR,WAwBQ;EAAe,SAAO,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,IAAA,CAAA,EAAA,SAAA,MAAA,EAAA;EAAO,SAGrD,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,OAAA,CAAA,EAAA,MAAA;EAAO,SACpC,IAAA,CAAA,EAAA,MAAA;;;;;;;AAII,KAnBL,gBAAA,GAmBK,CAAA,OAAA,EAlBN,WAkBM,EAAA,IAAA,CAAA,EAjBR,gBAiBQ,EAAA,GAAA,OAAA;;;;AAGiB;AACjC;AAyBe,UAtCC,gBAAA,CAsCS;EAAA,CAAA,IAAA,CAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EArCE,eAqCF,EAAA,EAAA,CAAA,EArCwB,gBAqCxB,CAAA,EArC2C,OAqC3C,CAAA,IAAA,CAAA;EAAA,CAAA,IACf,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,EAnCY,gBAmCZ,CAAA,EAnC+B,OAmC/B,CAAA,IAAA,CAAA;EAA8B,CAAA,OACtC,CAAA,EAnCU,eAmCV,EAAA,EAAA,CAAA,EAnCgC,gBAmChC,CAAA,EAnCmD,OAmCnD,CAAA,IAAA,CAAA;EAAgB,CAAA,EAAA,CAAA,EAlCX,gBAkCW,CAAA,EAlCQ,OAkCR,CAAA,IAAA,CAAA;EAeH,SAAA,IAAQ,EAhDP,gBAgDO;EAAA,SAAA,IAAA,EA/CP,gBA+CO;EAAA,SACb,IAAA,EA/CM,gBA+CN;EAA8B,SACtC,aAAA,CAAA,EA/CwB,gBA+CxB;EAAgB,SAAA,EAAA,CAAA,EA9CH,gBA8CG;EAaN,SAAqC,IAAA,CAAA,EA1DhC,gBA0DC;AAQnB;AAOA,KAtEK,gBAAA,GAsEc,CAAA,KAA4B,CAA5B,EAAA,OAA4B,EAAA,GAAA,IAAA;AAO/C;AAOA;AAQA;AAOA;AAOA;;;;;;;;iBAnFgB,UAAA,WACL,8BACR;;;;;;;;;iBAea,QAAA,WACL,8BACR;;;;;;;cAaU,MAAM;;;;;;;cAQN,IAAI;;;;;;cAOJ,MAAM;;;;;;cAON,MAAM;;;;;;cAON,MAAM;;;;;;;cAQN,eAAe;;;;;;cAOf;;;;;;cAOA"}
package/dist/mod.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AAgCA;;;;;AAU+B;AAa/B;;;AAES,UAzBQ,eAAA,CAyBR;EAAgB,SAAA,WAAA,CAAA,EAAA,MAAA,GAAA,OAAA;EAQR,SAAA,aAAgB,CAAA,EAAA,OAAA,GAAA,MAAA,GA5B3B,MA4B2B,GAAA,CAAA,CAAA,KAAA,EAAA,OAAA,EAAA,GAAA,OAAA,CAAA,GAAA,MAAA,GAzB3B,KAyB2B;EAAA,SAAA,IAAA,CAAA,EAAA,OAAA;EAAA,SACL,MAAA,CAAA,EAxBR,WAwBQ;EAAe,SAAO,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,IAAA,CAAA,EAAA,SAAA,MAAA,EAAA;EAAO,SAGrD,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,OAAA,CAAA,EAAA,MAAA;EAAO,SACpC,IAAA,CAAA,EAAA,MAAA;;;;;;;AAII,KAnBL,gBAAA,GAmBK,CAAA,OAAA,EAlBN,WAkBM,EAAA,IAAA,CAAA,EAjBR,gBAiBQ,EAAA,GAAA,OAAA;;;;AAGiB;AACjC;AAyBe,UAtCC,gBAAA,CAsCS;EAAA,CAAA,IAAA,CAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EArCE,eAqCF,EAAA,EAAA,CAAA,EArCwB,gBAqCxB,CAAA,EArC2C,OAqC3C,CAAA,IAAA,CAAA;EAAA,CAAA,IACf,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,EAnCY,gBAmCZ,CAAA,EAnC+B,OAmC/B,CAAA,IAAA,CAAA;EAA8B,CAAA,OACtC,CAAA,EAnCU,eAmCV,EAAA,EAAA,CAAA,EAnCgC,gBAmChC,CAAA,EAnCmD,OAmCnD,CAAA,IAAA,CAAA;EAAgB,CAAA,EAAA,CAAA,EAlCX,gBAkCW,CAAA,EAlCQ,OAkCR,CAAA,IAAA,CAAA;EAeH,SAAA,IAAQ,EAhDP,gBAgDO;EAAA,SAAA,IAAA,EA/CP,gBA+CO;EAAA,SACb,IAAA,EA/CM,gBA+CN;EAA8B,SACtC,aAAA,CAAA,EA/CwB,gBA+CxB;EAAgB,SAAA,EAAA,CAAA,EA9CH,gBA8CG;EAaN,SAAqC,IAAA,CAAA,EA1DhC,gBA0DC;AAQnB;AAOA,KAtEK,gBAAA,GAsEc,CAAA,KAA4B,CAA5B,EAAA,OAA4B,EAAA,GAAA,IAAA;AAO/C;AAOA;AAQA;AAOA;AAOA;;;;;;;;iBAnFgB,UAAA,WACL,8BACR;;;;;;;;;iBAea,QAAA,WACL,8BACR;;;;;;;cAaU,MAAM;;;;;;;cAQN,IAAI;;;;;;cAOJ,MAAM;;;;;;cAON,MAAM;;;;;;cAON,MAAM;;;;;;;cAQN,eAAe;;;;;;cAOf;;;;;;cAOA"}
1
+ {"version":3,"file":"mod.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AAmCA;;;;;AAU+B;AAa/B;;;AAES,UAzBQ,eAAA,CAyBR;EAAgB,SAAA,WAAA,CAAA,EAAA,MAAA,GAAA,OAAA;EAQR,SAAA,aAAgB,CAAA,EAAA,OAAA,GAAA,MAAA,GA5B3B,MA4B2B,GAAA,CAAA,CAAA,KAAA,EAAA,OAAA,EAAA,GAAA,OAAA,CAAA,GAAA,MAAA,GAzB3B,KAyB2B;EAAA,SAAA,IAAA,CAAA,EAAA,OAAA;EAAA,SACL,MAAA,CAAA,EAxBR,WAwBQ;EAAe,SAAO,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,IAAA,CAAA,EAAA,SAAA,MAAA,EAAA;EAAO,SAGrD,IAAA,CAAA,EAAA,OAAA,GAAA,MAAA;EAAgB,SAAG,OAAA,CAAA,EAAA,MAAA;EAAO,SACpC,IAAA,CAAA,EAAA,MAAA;;;;;;;AAII,KAnBL,gBAAA,GAmBK,CAAA,OAAA,EAlBN,WAkBM,EAAA,IAAA,CAAA,EAjBR,gBAiBQ,EAAA,GAAA,OAAA;;;;AAGiB;AACjC;AAyBe,UAtCC,gBAAA,CAsCS;EAAA,CAAA,IAAA,CAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EArCE,eAqCF,EAAA,EAAA,CAAA,EArCwB,gBAqCxB,CAAA,EArC2C,OAqC3C,CAAA,IAAA,CAAA;EAAA,CAAA,IACf,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,EAnCY,gBAmCZ,CAAA,EAnC+B,OAmC/B,CAAA,IAAA,CAAA;EAA8B,CAAA,OACtC,CAAA,EAnCU,eAmCV,EAAA,EAAA,CAAA,EAnCgC,gBAmChC,CAAA,EAnCmD,OAmCnD,CAAA,IAAA,CAAA;EAAgB,CAAA,EAAA,CAAA,EAlCX,gBAkCW,CAAA,EAlCQ,OAkCR,CAAA,IAAA,CAAA;EAeH,SAAA,IAAQ,EAhDP,gBAgDO;EAAA,SAAA,IAAA,EA/CP,gBA+CO;EAAA,SACb,IAAA,EA/CM,gBA+CN;EAA8B,SACtC,aAAA,CAAA,EA/CwB,gBA+CxB;EAAgB,SAAA,EAAA,CAAA,EA9CH,gBA8CG;EAaN,SAAqC,IAAA,CAAA,EA1DhC,gBA0DC;AAQnB;AAOA,KAtEK,gBAAA,GAsEc,CAAA,KAA4B,CAA5B,EAAA,OAA4B,EAAA,GAAA,IAAA;AAO/C;AAOA;AAQA;AAOA;AAOA;;;;;;;;iBAnFgB,UAAA,WACL,8BACR;;;;;;;;;iBAea,QAAA,WACL,8BACR;;;;;;;cAaU,MAAM;;;;;;;cAQN,IAAI;;;;;;cAOJ,MAAM;;;;;;cAON,MAAM;;;;;;cAON,MAAM;;;;;;;cAQN,eAAe;;;;;;cAOf;;;;;;cAOA"}
package/dist/mod.js CHANGED
@@ -116,27 +116,48 @@ function wrapNodeCallback(wrap, callback) {
116
116
  if (callback.length >= 2) return function(context, done) {
117
117
  const runCallback = (...args) => Reflect.apply(callback, this, args);
118
118
  wrap(() => new Promise((resolve, reject) => {
119
+ let callbackReturned = false;
120
+ let doneCalled = false;
121
+ let pendingDone = false;
122
+ let pendingDoneError;
119
123
  let settled = false;
120
- const wrappedDone = (error) => {
124
+ const settle = (error) => {
121
125
  if (settled) return;
122
126
  settled = true;
123
127
  if (error == null) resolve();
124
128
  else reject(error);
125
129
  };
130
+ const wrappedDone = (error) => {
131
+ if (doneCalled) return;
132
+ doneCalled = true;
133
+ if (!callbackReturned) {
134
+ pendingDone = true;
135
+ pendingDoneError = error;
136
+ return;
137
+ }
138
+ settle(error);
139
+ };
126
140
  try {
127
- runCallback(context, wrappedDone);
141
+ const result = runCallback(context, wrappedDone);
142
+ callbackReturned = true;
143
+ if (isPromiseLike(result)) {
144
+ reject(new TypeError("Callback-style node:test functions must not return a Promise."));
145
+ return;
146
+ }
147
+ if (pendingDone) settle(pendingDoneError);
128
148
  } catch (error) {
149
+ callbackReturned = true;
129
150
  reject(error);
130
151
  }
131
152
  }))().then(() => done(), (error) => done(error));
132
153
  };
133
- if (callback.length === 0) return function() {
134
- return wrap(() => Reflect.apply(callback, this, []))();
135
- };
136
154
  return function(context) {
137
155
  return wrap(() => Reflect.apply(callback, this, [context]))();
138
156
  };
139
157
  }
158
+ function isPromiseLike(value) {
159
+ return typeof value === "object" && value != null && "then" in value && typeof value.then === "function";
160
+ }
140
161
 
141
162
  //#endregion
142
163
  export { after, afterEach, assert, before, beforeEach, createIt, createTest, src_default as default, describe, expectFailure, it, mock, only, run, skip, snapshot, suite, test, todo };
package/dist/mod.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.js","names":["options: FailureLogReporterOptions","nodeIt","test: NodeTestFunction","it: NodeTestFunction","only: NodeTestFunction","skip: NodeTestFunction","todo: NodeTestFunction","expectFailure: NodeTestFunction | undefined","assert: unknown","snapshot: unknown","baseTest: BaseNodeTestFunction","args: readonly unknown[]","wrap: ReturnType<typeof createFailureLogReporter>[\"wrap\"]","callback: AnyFunction","context: TestContext","done: NodeDoneCallback","wrappedDone: NodeDoneCallback","error?: unknown","error: unknown"],"sources":["../src/mod.ts"],"sourcesContent":["import nodeTest, { it as nodeIt } from \"node:test\";\nimport type { TestContext } from \"node:test\";\n\nimport {\n createFailureLogReporter,\n type FailureLogReporterOptions,\n} from \"@logtape/testing/reporter\";\n\nexport type {\n FailureLogReporterOptions,\n FailureLogReportMode,\n} from \"@logtape/testing/reporter\";\nexport {\n after,\n afterEach,\n before,\n beforeEach,\n describe,\n mock,\n run,\n suite,\n} from \"node:test\";\n\n/**\n * Options accepted by Node.js `test()` and `it()` functions.\n *\n * The shape intentionally mirrors Node's documented option bag while allowing\n * newer Node.js options to pass through even when a runtime's bundled TypeScript\n * declarations lag behind the current documentation.\n *\n * @since 2.3.0\n */\nexport interface NodeTestOptions {\n readonly concurrency?: number | boolean;\n readonly expectFailure?:\n | boolean\n | string\n | RegExp\n | ((error: unknown) => boolean)\n | object\n | Error;\n readonly only?: boolean;\n readonly signal?: AbortSignal;\n readonly skip?: boolean | string;\n readonly tags?: readonly string[];\n readonly todo?: boolean | string;\n readonly timeout?: number;\n readonly plan?: number;\n}\n\n/**\n * A callback passed to Node.js `test()` or `it()`.\n *\n * @since 2.3.0\n */\nexport type NodeTestCallback = (\n context: TestContext,\n done?: NodeDoneCallback,\n) => unknown;\n\n/**\n * A Node.js `test()`-compatible function.\n *\n * @since 2.3.0\n */\nexport interface NodeTestFunction {\n (name?: string, options?: NodeTestOptions, fn?: NodeTestCallback): Promise<\n void\n >;\n (name?: string, fn?: NodeTestCallback): Promise<void>;\n (options?: NodeTestOptions, fn?: NodeTestCallback): Promise<void>;\n (fn?: NodeTestCallback): Promise<void>;\n readonly only: NodeTestFunction;\n readonly skip: NodeTestFunction;\n readonly todo: NodeTestFunction;\n readonly expectFailure?: NodeTestFunction;\n readonly it?: NodeTestFunction;\n readonly test?: NodeTestFunction;\n}\n\ntype NodeDoneCallback = (error?: unknown) => void;\ntype AnyFunction = (...args: never[]) => unknown;\ntype BaseNodeTestFunction = AnyFunction & {\n readonly only: AnyFunction;\n readonly skip: AnyFunction;\n readonly todo: AnyFunction;\n readonly expectFailure?: AnyFunction;\n readonly it?: AnyFunction;\n readonly test?: AnyFunction;\n};\n\n/**\n * Creates a `node:test` test function that reports LogTape records from failed\n * test callbacks.\n *\n * The returned function preserves Node.js test options and shorthand helpers\n * such as `test.only()`, `test.skip()`, and `test.todo()`. Only callback\n * arguments are adapted; options are passed through to `node:test`.\n *\n * @param options Failure log reporter options.\n * @returns A configured `node:test`-compatible test function.\n * @since 2.3.0\n */\nexport function createTest(\n options: FailureLogReporterOptions = {},\n): NodeTestFunction {\n return createNodeTestFunction(\n nodeTest as unknown as BaseNodeTestFunction,\n options,\n );\n}\n\n/**\n * Creates an `it()` alias that reports LogTape records from failed test\n * callbacks.\n *\n * @param options Failure log reporter options.\n * @returns A configured `node:test`-compatible `it()` function.\n * @since 2.3.0\n */\nexport function createIt(\n options: FailureLogReporterOptions = {},\n): NodeTestFunction {\n return createNodeTestFunction(\n nodeIt as unknown as BaseNodeTestFunction,\n options,\n );\n}\n\n/**\n * A `node:test` test function that reports LogTape records from failed test\n * callbacks using the default reporter options.\n *\n * @since 2.3.0\n */\nexport const test: NodeTestFunction = createTest();\n\n/**\n * A `node:test` `it()` alias that reports LogTape records from failed test\n * callbacks using the default reporter options.\n *\n * @since 2.3.0\n */\nexport const it: NodeTestFunction = createIt();\n\n/**\n * Shorthand for marking a test as `only`.\n *\n * @since 2.3.0\n */\nexport const only: NodeTestFunction = test.only;\n\n/**\n * Shorthand for skipping a test.\n *\n * @since 2.3.0\n */\nexport const skip: NodeTestFunction = test.skip;\n\n/**\n * Shorthand for marking a test as TODO.\n *\n * @since 2.3.0\n */\nexport const todo: NodeTestFunction = test.todo;\n\n/**\n * Shorthand for expecting a test to fail when supported by the active Node.js\n * runtime.\n *\n * @since 2.3.0\n */\nexport const expectFailure: NodeTestFunction | undefined = test.expectFailure;\n\n/**\n * Node.js' test assertion tracker when supported by the active runtime.\n *\n * @since 2.3.0\n */\nexport const assert: unknown = (test as { readonly assert?: unknown }).assert;\n\n/**\n * Node.js' snapshot helper when supported by the active runtime.\n *\n * @since 2.3.0\n */\nexport const snapshot: unknown = (test as { readonly snapshot?: unknown })\n .snapshot;\n\nexport default test;\n\nfunction createNodeTestFunction(\n baseTest: BaseNodeTestFunction,\n options: FailureLogReporterOptions,\n includeExtendedProperties = true,\n): NodeTestFunction {\n const register = ((...args: unknown[]) =>\n Reflect.apply(\n baseTest,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction;\n\n const baseExpectFailure = baseTest.expectFailure;\n const wrapped = Object.assign(register, baseTest, {\n only: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.only,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"only\"],\n skip: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.skip,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"skip\"],\n todo: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.todo,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"todo\"],\n expectFailure: typeof baseExpectFailure === \"function\"\n ? ((...args: unknown[]) =>\n Reflect.apply(\n baseExpectFailure,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"expectFailure\"]\n : undefined,\n });\n\n if (includeExtendedProperties) {\n if (typeof baseTest.it === \"function\") {\n Object.defineProperty(wrapped, \"it\", {\n configurable: true,\n enumerable: true,\n value: createNodeTestFunction(\n baseTest.it as BaseNodeTestFunction,\n options,\n false,\n ),\n writable: true,\n });\n }\n if (typeof baseTest.test === \"function\") {\n Object.defineProperty(wrapped, \"test\", {\n configurable: true,\n enumerable: true,\n value: wrapped,\n writable: true,\n });\n }\n }\n\n return wrapped;\n}\n\nfunction wrapCallbackArgument(\n args: readonly unknown[],\n options: FailureLogReporterOptions,\n): unknown[] {\n const callback = args.at(-1);\n if (typeof callback !== \"function\") return [...args];\n\n const reporter = createFailureLogReporter(options);\n const wrapped = wrapNodeCallback(\n reporter.wrap.bind(reporter),\n callback as unknown as AnyFunction,\n );\n return [...args.slice(0, -1), wrapped];\n}\n\nfunction wrapNodeCallback(\n wrap: ReturnType<typeof createFailureLogReporter>[\"wrap\"],\n callback: AnyFunction,\n): AnyFunction {\n if (callback.length >= 2) {\n return function (\n this: unknown,\n context: TestContext,\n done: NodeDoneCallback,\n ): void {\n const runCallback = (...args: readonly unknown[]): unknown =>\n Reflect.apply(callback, this, args);\n void wrap(() =>\n new Promise<void>((resolve, reject) => {\n let settled = false;\n const wrappedDone: NodeDoneCallback = ((error?: unknown) => {\n if (settled) return;\n settled = true;\n if (error == null) resolve();\n else reject(error);\n }) as NodeDoneCallback;\n\n try {\n runCallback(context, wrappedDone);\n } catch (error) {\n reject(error);\n }\n })\n )().then(\n () => done(),\n (error: unknown) => done(error),\n );\n };\n }\n\n if (callback.length === 0) {\n return function (this: unknown): Promise<unknown> {\n return wrap(() => Reflect.apply(callback, this, []))();\n };\n }\n\n return function (this: unknown, context: TestContext): Promise<unknown> {\n return wrap(() => Reflect.apply(callback, this, [context]))();\n };\n}\n\nexport type { TestContext };\n"],"mappings":";;;;;;;;;;;;;;;;AAuGA,SAAgB,WACdA,UAAqC,CAAE,GACrB;AAClB,QAAO,uBACL,UACA,QACD;AACF;;;;;;;;;AAUD,SAAgB,SACdA,UAAqC,CAAE,GACrB;AAClB,QAAO,uBACLC,MACA,QACD;AACF;;;;;;;AAQD,MAAaC,OAAyB,YAAY;;;;;;;AAQlD,MAAaC,KAAuB,UAAU;;;;;;AAO9C,MAAaC,OAAyB,KAAK;;;;;;AAO3C,MAAaC,OAAyB,KAAK;;;;;;AAO3C,MAAaC,OAAyB,KAAK;;;;;;;AAQ3C,MAAaC,gBAA8C,KAAK;;;;;;AAOhE,MAAaC,SAAmB,KAAuC;;;;;;AAOvE,MAAaC,WAAqB,KAC/B;AAEH,kBAAe;AAEf,SAAS,uBACPC,UACAV,SACA,4BAA4B,MACV;CAClB,MAAM,WAAY,CAAC,GAAG,SACpB,QAAQ,MACN,kBAEA,qBAAqB,MAAM,QAAQ,CACpC;CAEH,MAAM,oBAAoB,SAAS;CACnC,MAAM,UAAU,OAAO,OAAO,UAAU,UAAU;EAChD,MAAO,CAAC,GAAG,SACT,QAAQ,MACN,SAAS,cAET,qBAAqB,MAAM,QAAQ,CACpC;EACH,MAAO,CAAC,GAAG,SACT,QAAQ,MACN,SAAS,cAET,qBAAqB,MAAM,QAAQ,CACpC;EACH,MAAO,CAAC,GAAG,SACT,QAAQ,MACN,SAAS,cAET,qBAAqB,MAAM,QAAQ,CACpC;EACH,sBAAsB,sBAAsB,aACvC,CAAC,GAAG,SACL,QAAQ,MACN,2BAEA,qBAAqB,MAAM,QAAQ,CACpC;CAEN,EAAC;AAEF,KAAI,2BAA2B;AAC7B,aAAW,SAAS,OAAO,WACzB,QAAO,eAAe,SAAS,MAAM;GACnC,cAAc;GACd,YAAY;GACZ,OAAO,uBACL,SAAS,IACT,SACA,MACD;GACD,UAAU;EACX,EAAC;AAEJ,aAAW,SAAS,SAAS,WAC3B,QAAO,eAAe,SAAS,QAAQ;GACrC,cAAc;GACd,YAAY;GACZ,OAAO;GACP,UAAU;EACX,EAAC;CAEL;AAED,QAAO;AACR;AAED,SAAS,qBACPW,MACAX,SACW;CACX,MAAM,WAAW,KAAK,GAAG,GAAG;AAC5B,YAAW,aAAa,WAAY,QAAO,CAAC,GAAG,IAAK;CAEpD,MAAM,WAAW,yBAAyB,QAAQ;CAClD,MAAM,UAAU,iBACd,SAAS,KAAK,KAAK,SAAS,EAC5B,SACD;AACD,QAAO,CAAC,GAAG,KAAK,MAAM,GAAG,GAAG,EAAE,OAAQ;AACvC;AAED,SAAS,iBACPY,MACAC,UACa;AACb,KAAI,SAAS,UAAU,EACrB,QAAO,SAELC,SACAC,MACM;EACN,MAAM,cAAc,CAAC,GAAG,SACtB,QAAQ,MAAM,UAAU,MAAM,KAAK;AACrC,EAAK,KAAK,MACR,IAAI,QAAc,CAAC,SAAS,WAAW;GACrC,IAAI,UAAU;GACd,MAAMC,cAAiC,CAACC,UAAoB;AAC1D,QAAI,QAAS;AACb,cAAU;AACV,QAAI,SAAS,KAAM,UAAS;QACvB,QAAO,MAAM;GACnB;AAED,OAAI;AACF,gBAAY,SAAS,YAAY;GAClC,SAAQ,OAAO;AACd,WAAO,MAAM;GACd;EACF,GACF,EAAE,CAAC,KACF,MAAM,MAAM,EACZ,CAACC,UAAmB,KAAK,MAAM,CAChC;CACF;AAGH,KAAI,SAAS,WAAW,EACtB,QAAO,WAA2C;AAChD,SAAO,KAAK,MAAM,QAAQ,MAAM,UAAU,MAAM,CAAE,EAAC,CAAC,EAAE;CACvD;AAGH,QAAO,SAAyBJ,SAAwC;AACtE,SAAO,KAAK,MAAM,QAAQ,MAAM,UAAU,MAAM,CAAC,OAAQ,EAAC,CAAC,EAAE;CAC9D;AACF"}
1
+ {"version":3,"file":"mod.js","names":["options: FailureLogReporterOptions","nodeIt","test: NodeTestFunction","it: NodeTestFunction","only: NodeTestFunction","skip: NodeTestFunction","todo: NodeTestFunction","expectFailure: NodeTestFunction | undefined","assert: unknown","snapshot: unknown","baseTest: BaseNodeTestFunction","register: NodeTestFunction","args: readonly unknown[]","wrap: ReturnType<typeof createFailureLogReporter>[\"wrap\"]","callback: AnyFunction","context: TestContext","done: NodeDoneCallback","pendingDoneError: unknown","error?: unknown","wrappedDone: NodeDoneCallback","error: unknown","value: unknown"],"sources":["../src/mod.ts"],"sourcesContent":["// deno-coverage-ignore-file -- This package targets node:test. Deno's\n// node:test shim rejects the nested registrations needed by the integration\n// tests, so coverage for this module comes from the Node.js and Bun jobs.\nimport nodeTest, { it as nodeIt } from \"node:test\";\nimport type { TestContext } from \"node:test\";\n\nimport {\n createFailureLogReporter,\n type FailureLogReporterOptions,\n} from \"@logtape/testing/reporter\";\n\nexport type {\n FailureLogReporterOptions,\n FailureLogReportMode,\n} from \"@logtape/testing/reporter\";\nexport {\n after,\n afterEach,\n before,\n beforeEach,\n describe,\n mock,\n run,\n suite,\n} from \"node:test\";\n\n/**\n * Options accepted by Node.js `test()` and `it()` functions.\n *\n * The shape intentionally mirrors Node's documented option bag while allowing\n * newer Node.js options to pass through even when a runtime's bundled TypeScript\n * declarations lag behind the current documentation.\n *\n * @since 2.3.0\n */\nexport interface NodeTestOptions {\n readonly concurrency?: number | boolean;\n readonly expectFailure?:\n | boolean\n | string\n | RegExp\n | ((error: unknown) => boolean)\n | object\n | Error;\n readonly only?: boolean;\n readonly signal?: AbortSignal;\n readonly skip?: boolean | string;\n readonly tags?: readonly string[];\n readonly todo?: boolean | string;\n readonly timeout?: number;\n readonly plan?: number;\n}\n\n/**\n * A callback passed to Node.js `test()` or `it()`.\n *\n * @since 2.3.0\n */\nexport type NodeTestCallback = (\n context: TestContext,\n done?: NodeDoneCallback,\n) => unknown;\n\n/**\n * A Node.js `test()`-compatible function.\n *\n * @since 2.3.0\n */\nexport interface NodeTestFunction {\n (name?: string, options?: NodeTestOptions, fn?: NodeTestCallback): Promise<\n void\n >;\n (name?: string, fn?: NodeTestCallback): Promise<void>;\n (options?: NodeTestOptions, fn?: NodeTestCallback): Promise<void>;\n (fn?: NodeTestCallback): Promise<void>;\n readonly only: NodeTestFunction;\n readonly skip: NodeTestFunction;\n readonly todo: NodeTestFunction;\n readonly expectFailure?: NodeTestFunction;\n readonly it?: NodeTestFunction;\n readonly test?: NodeTestFunction;\n}\n\ntype NodeDoneCallback = (error?: unknown) => void;\ntype AnyFunction = (...args: never[]) => unknown;\ntype BaseNodeTestFunction = AnyFunction & {\n readonly only: AnyFunction;\n readonly skip: AnyFunction;\n readonly todo: AnyFunction;\n readonly expectFailure?: AnyFunction;\n readonly it?: AnyFunction;\n readonly test?: AnyFunction;\n};\n\n/**\n * Creates a `node:test` test function that reports LogTape records from failed\n * test callbacks.\n *\n * The returned function preserves Node.js test options and shorthand helpers\n * such as `test.only()`, `test.skip()`, and `test.todo()`. Only callback\n * arguments are adapted; options are passed through to `node:test`.\n *\n * @param options Failure log reporter options.\n * @returns A configured `node:test`-compatible test function.\n * @since 2.3.0\n */\nexport function createTest(\n options: FailureLogReporterOptions = {},\n): NodeTestFunction {\n return createNodeTestFunction(\n nodeTest as unknown as BaseNodeTestFunction,\n options,\n );\n}\n\n/**\n * Creates an `it()` alias that reports LogTape records from failed test\n * callbacks.\n *\n * @param options Failure log reporter options.\n * @returns A configured `node:test`-compatible `it()` function.\n * @since 2.3.0\n */\nexport function createIt(\n options: FailureLogReporterOptions = {},\n): NodeTestFunction {\n return createNodeTestFunction(\n nodeIt as unknown as BaseNodeTestFunction,\n options,\n );\n}\n\n/**\n * A `node:test` test function that reports LogTape records from failed test\n * callbacks using the default reporter options.\n *\n * @since 2.3.0\n */\nexport const test: NodeTestFunction = createTest();\n\n/**\n * A `node:test` `it()` alias that reports LogTape records from failed test\n * callbacks using the default reporter options.\n *\n * @since 2.3.0\n */\nexport const it: NodeTestFunction = createIt();\n\n/**\n * Shorthand for marking a test as `only`.\n *\n * @since 2.3.0\n */\nexport const only: NodeTestFunction = test.only;\n\n/**\n * Shorthand for skipping a test.\n *\n * @since 2.3.0\n */\nexport const skip: NodeTestFunction = test.skip;\n\n/**\n * Shorthand for marking a test as TODO.\n *\n * @since 2.3.0\n */\nexport const todo: NodeTestFunction = test.todo;\n\n/**\n * Shorthand for expecting a test to fail when supported by the active Node.js\n * runtime.\n *\n * @since 2.3.0\n */\nexport const expectFailure: NodeTestFunction | undefined = test.expectFailure;\n\n/**\n * Node.js' test assertion tracker when supported by the active runtime.\n *\n * @since 2.3.0\n */\nexport const assert: unknown = (test as { readonly assert?: unknown }).assert;\n\n/**\n * Node.js' snapshot helper when supported by the active runtime.\n *\n * @since 2.3.0\n */\nexport const snapshot: unknown = (test as { readonly snapshot?: unknown })\n .snapshot;\n\nexport default test;\n\nfunction createNodeTestFunction(\n baseTest: BaseNodeTestFunction,\n options: FailureLogReporterOptions,\n includeExtendedProperties = true,\n): NodeTestFunction {\n const register: NodeTestFunction = ((...args: unknown[]) =>\n Reflect.apply(\n baseTest,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction;\n\n const baseExpectFailure = baseTest.expectFailure;\n const wrapped = Object.assign(register, baseTest, {\n only: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.only,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"only\"],\n skip: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.skip,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"skip\"],\n todo: ((...args: unknown[]) =>\n Reflect.apply(\n baseTest.todo,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"todo\"],\n expectFailure: typeof baseExpectFailure === \"function\"\n ? ((...args: unknown[]) =>\n Reflect.apply(\n baseExpectFailure,\n undefined,\n wrapCallbackArgument(args, options),\n )) as NodeTestFunction[\"expectFailure\"]\n : undefined,\n });\n\n if (includeExtendedProperties) {\n if (typeof baseTest.it === \"function\") {\n Object.defineProperty(wrapped, \"it\", {\n configurable: true,\n enumerable: true,\n value: createNodeTestFunction(\n baseTest.it as BaseNodeTestFunction,\n options,\n false,\n ),\n writable: true,\n });\n }\n if (typeof baseTest.test === \"function\") {\n Object.defineProperty(wrapped, \"test\", {\n configurable: true,\n enumerable: true,\n value: wrapped,\n writable: true,\n });\n }\n }\n\n return wrapped;\n}\n\nfunction wrapCallbackArgument(\n args: readonly unknown[],\n options: FailureLogReporterOptions,\n): unknown[] {\n const callback = args.at(-1);\n if (typeof callback !== \"function\") return [...args];\n\n const reporter = createFailureLogReporter(options);\n const wrapped = wrapNodeCallback(\n reporter.wrap.bind(reporter),\n callback as unknown as AnyFunction,\n );\n return [...args.slice(0, -1), wrapped];\n}\n\nfunction wrapNodeCallback(\n wrap: ReturnType<typeof createFailureLogReporter>[\"wrap\"],\n callback: AnyFunction,\n): AnyFunction {\n if (callback.length >= 2) {\n return function (\n this: unknown,\n context: TestContext,\n done: NodeDoneCallback,\n ): void {\n const runCallback = (...args: readonly unknown[]): unknown =>\n Reflect.apply(callback, this, args);\n void wrap(() =>\n new Promise<void>((resolve, reject) => {\n let callbackReturned = false;\n let doneCalled = false;\n let pendingDone = false;\n let pendingDoneError: unknown;\n let settled = false;\n const settle = (error?: unknown): void => {\n if (settled) return;\n settled = true;\n if (error == null) resolve();\n else reject(error);\n };\n const wrappedDone: NodeDoneCallback = ((error?: unknown) => {\n if (doneCalled) return;\n doneCalled = true;\n if (!callbackReturned) {\n pendingDone = true;\n pendingDoneError = error;\n return;\n }\n settle(error);\n }) as NodeDoneCallback;\n\n try {\n const result = runCallback(context, wrappedDone);\n callbackReturned = true;\n if (isPromiseLike(result)) {\n reject(\n new TypeError(\n \"Callback-style node:test functions must not return a Promise.\",\n ),\n );\n return;\n }\n if (pendingDone) settle(pendingDoneError);\n } catch (error) {\n callbackReturned = true;\n reject(error);\n }\n })\n )().then(\n () => done(),\n (error: unknown) => done(error),\n );\n };\n }\n\n return function (this: unknown, context: TestContext): unknown {\n return wrap(() => Reflect.apply(callback, this, [context]))();\n };\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return typeof value === \"object\" && value != null &&\n \"then\" in value &&\n typeof value.then === \"function\";\n}\n\nexport type { TestContext };\n"],"mappings":";;;;;;;;;;;;;;;;AA0GA,SAAgB,WACdA,UAAqC,CAAE,GACrB;AAClB,QAAO,uBACL,UACA,QACD;AACF;;;;;;;;;AAUD,SAAgB,SACdA,UAAqC,CAAE,GACrB;AAClB,QAAO,uBACLC,MACA,QACD;AACF;;;;;;;AAQD,MAAaC,OAAyB,YAAY;;;;;;;AAQlD,MAAaC,KAAuB,UAAU;;;;;;AAO9C,MAAaC,OAAyB,KAAK;;;;;;AAO3C,MAAaC,OAAyB,KAAK;;;;;;AAO3C,MAAaC,OAAyB,KAAK;;;;;;;AAQ3C,MAAaC,gBAA8C,KAAK;;;;;;AAOhE,MAAaC,SAAmB,KAAuC;;;;;;AAOvE,MAAaC,WAAqB,KAC/B;AAEH,kBAAe;AAEf,SAAS,uBACPC,UACAV,SACA,4BAA4B,MACV;CAClB,MAAMW,WAA8B,CAAC,GAAG,SACtC,QAAQ,MACN,kBAEA,qBAAqB,MAAM,QAAQ,CACpC;CAEH,MAAM,oBAAoB,SAAS;CACnC,MAAM,UAAU,OAAO,OAAO,UAAU,UAAU;EAChD,MAAO,CAAC,GAAG,SACT,QAAQ,MACN,SAAS,cAET,qBAAqB,MAAM,QAAQ,CACpC;EACH,MAAO,CAAC,GAAG,SACT,QAAQ,MACN,SAAS,cAET,qBAAqB,MAAM,QAAQ,CACpC;EACH,MAAO,CAAC,GAAG,SACT,QAAQ,MACN,SAAS,cAET,qBAAqB,MAAM,QAAQ,CACpC;EACH,sBAAsB,sBAAsB,aACvC,CAAC,GAAG,SACL,QAAQ,MACN,2BAEA,qBAAqB,MAAM,QAAQ,CACpC;CAEN,EAAC;AAEF,KAAI,2BAA2B;AAC7B,aAAW,SAAS,OAAO,WACzB,QAAO,eAAe,SAAS,MAAM;GACnC,cAAc;GACd,YAAY;GACZ,OAAO,uBACL,SAAS,IACT,SACA,MACD;GACD,UAAU;EACX,EAAC;AAEJ,aAAW,SAAS,SAAS,WAC3B,QAAO,eAAe,SAAS,QAAQ;GACrC,cAAc;GACd,YAAY;GACZ,OAAO;GACP,UAAU;EACX,EAAC;CAEL;AAED,QAAO;AACR;AAED,SAAS,qBACPC,MACAZ,SACW;CACX,MAAM,WAAW,KAAK,GAAG,GAAG;AAC5B,YAAW,aAAa,WAAY,QAAO,CAAC,GAAG,IAAK;CAEpD,MAAM,WAAW,yBAAyB,QAAQ;CAClD,MAAM,UAAU,iBACd,SAAS,KAAK,KAAK,SAAS,EAC5B,SACD;AACD,QAAO,CAAC,GAAG,KAAK,MAAM,GAAG,GAAG,EAAE,OAAQ;AACvC;AAED,SAAS,iBACPa,MACAC,UACa;AACb,KAAI,SAAS,UAAU,EACrB,QAAO,SAELC,SACAC,MACM;EACN,MAAM,cAAc,CAAC,GAAG,SACtB,QAAQ,MAAM,UAAU,MAAM,KAAK;AACrC,EAAK,KAAK,MACR,IAAI,QAAc,CAAC,SAAS,WAAW;GACrC,IAAI,mBAAmB;GACvB,IAAI,aAAa;GACjB,IAAI,cAAc;GAClB,IAAIC;GACJ,IAAI,UAAU;GACd,MAAM,SAAS,CAACC,UAA0B;AACxC,QAAI,QAAS;AACb,cAAU;AACV,QAAI,SAAS,KAAM,UAAS;QACvB,QAAO,MAAM;GACnB;GACD,MAAMC,cAAiC,CAACD,UAAoB;AAC1D,QAAI,WAAY;AAChB,iBAAa;AACb,SAAK,kBAAkB;AACrB,mBAAc;AACd,wBAAmB;AACnB;IACD;AACD,WAAO,MAAM;GACd;AAED,OAAI;IACF,MAAM,SAAS,YAAY,SAAS,YAAY;AAChD,uBAAmB;AACnB,QAAI,cAAc,OAAO,EAAE;AACzB,YACE,IAAI,UACF,iEAEH;AACD;IACD;AACD,QAAI,YAAa,QAAO,iBAAiB;GAC1C,SAAQ,OAAO;AACd,uBAAmB;AACnB,WAAO,MAAM;GACd;EACF,GACF,EAAE,CAAC,KACF,MAAM,MAAM,EACZ,CAACE,UAAmB,KAAK,MAAM,CAChC;CACF;AAGH,QAAO,SAAyBL,SAA+B;AAC7D,SAAO,KAAK,MAAM,QAAQ,MAAM,UAAU,MAAM,CAAC,OAAQ,EAAC,CAAC,EAAE;CAC9D;AACF;AAED,SAAS,cAAcM,OAA+C;AACpE,eAAc,UAAU,YAAY,SAAS,QAC3C,UAAU,gBACH,MAAM,SAAS;AACzB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logtape/testing-node",
3
- "version": "2.3.0-dev.0",
3
+ "version": "2.3.0-dev.840+34e837bf",
4
4
  "description": "Node.js test runner integration for LogTape failure log reporting",
5
5
  "keywords": [
6
6
  "logging",
@@ -60,15 +60,15 @@
60
60
  "dist/"
61
61
  ],
62
62
  "dependencies": {
63
- "@logtape/testing": "^2.3.0"
63
+ "@logtape/testing": "^2.3.0-dev.840+34e837bf"
64
64
  },
65
65
  "peerDependencies": {
66
- "@logtape/logtape": "^2.3.0"
66
+ "@logtape/logtape": "^2.3.0-dev.840+34e837bf"
67
67
  },
68
68
  "devDependencies": {
69
69
  "tsdown": "^0.12.7",
70
70
  "typescript": "^5.8.3",
71
- "@logtape/logtape": "^2.3.0"
71
+ "@logtape/logtape": "^2.3.0-dev.840+34e837bf"
72
72
  },
73
73
  "scripts": {
74
74
  "build": "tsdown",