1
1
// Copyright 2018-2025 the Deno authors. MIT license.
2
2
3
3
import { primordials } from "ext:core/mod.js" ;
4
- const { PromisePrototypeThen } = primordials ;
4
+ const {
5
+ PromisePrototypeThen,
6
+ ArrayPrototypePush,
7
+ SafePromiseAll,
8
+ SafePromisePrototypeFinally,
9
+ } = primordials ;
5
10
import { notImplemented , warnNotImplemented } from "ext:deno_node/_utils.ts" ;
6
11
7
12
export function run ( ) {
@@ -87,6 +92,49 @@ class NodeTestContext {
87
92
}
88
93
}
89
94
95
+ let currentSuite : TestSuite | null = null ;
96
+
97
+ class TestSuite {
98
+ #denoTestContext: Deno . TestContext ;
99
+ steps : Promise < boolean > [ ] = [ ] ;
100
+
101
+ constructor ( t : Deno . TestContext ) {
102
+ this . #denoTestContext = t ;
103
+ }
104
+
105
+ addTest ( name , options , fn , overrides ) {
106
+ const prepared = prepareOptions ( name , options , fn , overrides ) ;
107
+ const step = this . #denoTestContext. step ( {
108
+ name : prepared . name ,
109
+ fn : ( denoTestContext ) => {
110
+ const newNodeTextContext = new NodeTestContext ( denoTestContext ) ;
111
+ return prepared . fn ( newNodeTextContext ) ;
112
+ } ,
113
+ ignore : prepared . options . todo || prepared . options . skip ,
114
+ sanitizeExit : false ,
115
+ sanitizeOps : false ,
116
+ sanitizeResources : false ,
117
+ } ) ;
118
+ ArrayPrototypePush ( this . steps , step ) ;
119
+ }
120
+
121
+ addSuite ( name , options , fn , overrides ) {
122
+ const prepared = prepareOptions ( name , options , fn , overrides ) ;
123
+ // deno-lint-ignore prefer-primordials
124
+ const { promise, resolve } = Promise . withResolvers ( ) ;
125
+ const step = this . #denoTestContext. step ( {
126
+ name : prepared . name ,
127
+ fn : wrapSuiteFn ( prepared . fn , resolve ) ,
128
+ ignore : prepared . options . todo || prepared . options . skip ,
129
+ sanitizeExit : false ,
130
+ sanitizeOps : false ,
131
+ sanitizeResources : false ,
132
+ } ) ;
133
+ ArrayPrototypePush ( this . steps , step ) ;
134
+ return promise ;
135
+ }
136
+ }
137
+
90
138
function prepareOptions ( name , options , fn , overrides ) {
91
139
if ( typeof name === "function" ) {
92
140
fn = name ;
@@ -147,30 +195,104 @@ function prepareDenoTest(name, options, fn, overrides) {
147
195
return promise ;
148
196
}
149
197
150
- export function test ( name , options , fn ) {
151
- return prepareDenoTest ( name , options , fn , { } ) ;
198
+ function wrapSuiteFn ( fn , resolve ) {
199
+ return function ( t ) {
200
+ const prevSuite = currentSuite ;
201
+ const suite = currentSuite = new TestSuite ( t ) ;
202
+ try {
203
+ fn ( ) ;
204
+ } finally {
205
+ currentSuite = prevSuite ;
206
+ }
207
+ return SafePromisePrototypeFinally ( SafePromiseAll ( suite . steps ) , resolve ) ;
208
+ } ;
209
+ }
210
+
211
+ function prepareDenoTestForSuite ( name , options , fn , overrides ) {
212
+ const prepared = prepareOptions ( name , options , fn , overrides ) ;
213
+
214
+ // deno-lint-ignore prefer-primordials
215
+ const { promise, resolve } = Promise . withResolvers ( ) ;
216
+
217
+ const denoTestOptions = {
218
+ name : prepared . name ,
219
+ fn : wrapSuiteFn ( prepared . fn , resolve ) ,
220
+ only : prepared . options . only ,
221
+ ignore : prepared . options . todo || prepared . options . skip ,
222
+ sanitizeExit : false ,
223
+ sanitizeOps : false ,
224
+ sanitizeResources : false ,
225
+ } ;
226
+ Deno . test ( denoTestOptions ) ;
227
+ return promise ;
228
+ }
229
+
230
+ export function test ( name , options , fn , overrides ) {
231
+ if ( currentSuite ) {
232
+ return currentSuite . addTest ( name , options , fn , overrides ) ;
233
+ }
234
+ return prepareDenoTest ( name , options , fn , overrides ) ;
152
235
}
153
236
154
237
test . skip = function skip ( name , options , fn ) {
155
- return prepareDenoTest ( name , options , fn , { skip : true } ) ;
238
+ return test ( name , options , fn , { skip : true } ) ;
156
239
} ;
157
240
158
241
test . todo = function todo ( name , options , fn ) {
159
- return prepareDenoTest ( name , options , fn , { todo : true } ) ;
242
+ return test ( name , options , fn , { todo : true } ) ;
160
243
} ;
161
244
162
245
test . only = function only ( name , options , fn ) {
163
- return prepareDenoTest ( name , options , fn , { only : true } ) ;
246
+ return test ( name , options , fn , { only : true } ) ;
247
+ } ;
248
+
249
+ export function describe ( name , options , fn ) {
250
+ return suite ( name , options , fn , { } ) ;
251
+ }
252
+
253
+ describe . skip = function skip ( name , options , fn ) {
254
+ return suite . skip ( name , options , fn ) ;
255
+ } ;
256
+ describe . todo = function todo ( name , options , fn ) {
257
+ return suite . todo ( name , options , fn ) ;
258
+ } ;
259
+ describe . only = function only ( name , options , fn ) {
260
+ return suite . only ( name , options , fn ) ;
164
261
} ;
165
262
166
- export function describe ( ) {
167
- notImplemented ( "test.describe" ) ;
263
+ export function suite ( name , options , fn , overrides ) {
264
+ if ( currentSuite ) {
265
+ return currentSuite . addSuite ( name , options , fn , overrides ) ;
266
+ }
267
+ return prepareDenoTestForSuite ( name , options , fn , overrides ) ;
168
268
}
169
269
170
- export function it ( ) {
171
- notImplemented ( "test.it" ) ;
270
+ suite . skip = function skip ( name , options , fn ) {
271
+ return suite ( name , options , fn , { skip : true } ) ;
272
+ } ;
273
+ suite . todo = function todo ( name , options , fn ) {
274
+ return suite ( name , options , fn , { todo : true } ) ;
275
+ } ;
276
+ suite . only = function only ( name , options , fn ) {
277
+ return suite ( name , options , fn , { only : true } ) ;
278
+ } ;
279
+
280
+ export function it ( name , options , fn ) {
281
+ return test ( name , options , fn , { } ) ;
172
282
}
173
283
284
+ it . skip = function skip ( name , options , fn ) {
285
+ return test . skip ( name , options , fn ) ;
286
+ } ;
287
+
288
+ it . todo = function todo ( name , options , fn ) {
289
+ return test . todo ( name , options , fn ) ;
290
+ } ;
291
+
292
+ it . only = function only ( name , options , fn ) {
293
+ return test . only ( name , options , fn ) ;
294
+ } ;
295
+
174
296
export function before ( ) {
175
297
notImplemented ( "test.before" ) ;
176
298
}
@@ -187,6 +309,10 @@ export function afterEach() {
187
309
notImplemented ( "test.afterEach" ) ;
188
310
}
189
311
312
+ test . it = it ;
313
+ test . describe = describe ;
314
+ test . suite = suite ;
315
+
190
316
export const mock = {
191
317
fn : ( ) => {
192
318
notImplemented ( "test.mock.fn" ) ;
0 commit comments