nole 3.0.0 → 3.2.0

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.
Files changed (84) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +514 -294
  3. package/bin/nole.js +145 -110
  4. package/dist/cjs/const.js +45 -0
  5. package/dist/cjs/core.js +61 -0
  6. package/dist/cjs/dynamic.js +56 -0
  7. package/dist/cjs/handle/after-each-hooks.js +29 -0
  8. package/dist/cjs/handle/after-hooks.js +27 -0
  9. package/dist/cjs/handle/before-each-hooks.js +29 -0
  10. package/dist/cjs/handle/before-hooks.js +37 -0
  11. package/dist/cjs/handle/cleanup-hooks.js +37 -0
  12. package/dist/cjs/handle/specs.js +52 -0
  13. package/dist/cjs/index.js +14 -0
  14. package/dist/cjs/package.json +1 -0
  15. package/dist/cjs/run.js +216 -0
  16. package/dist/cjs/symbol.js +6 -0
  17. package/dist/cjs/test-wrap.js +33 -0
  18. package/dist/cjs/utils/executor.js +23 -0
  19. package/dist/cjs/utils/time_difference.js +26 -0
  20. package/dist/cjs/utils/time_factor.js +31 -0
  21. package/dist/core.d.ts +3 -1
  22. package/dist/core.d.ts.map +1 -1
  23. package/dist/core.js +2 -2
  24. package/dist/dynamic.d.ts +2 -0
  25. package/dist/dynamic.d.ts.map +1 -1
  26. package/dist/dynamic.js +16 -1
  27. package/dist/handle/before-hooks.d.ts.map +1 -1
  28. package/dist/handle/before-hooks.js +12 -2
  29. package/dist/handle/specs.d.ts.map +1 -1
  30. package/dist/handle/specs.js +12 -3
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +2 -2
  34. package/dist/run.d.ts.map +1 -1
  35. package/dist/run.js +16 -7
  36. package/dist/symbol.d.ts +1 -0
  37. package/dist/symbol.d.ts.map +1 -1
  38. package/dist/symbol.js +3 -2
  39. package/dist/test-wrap.d.ts +1 -0
  40. package/dist/test-wrap.d.ts.map +1 -1
  41. package/dist/test-wrap.js +1 -1
  42. package/dist/utils/time_difference.d.ts.map +1 -1
  43. package/package.json +68 -57
  44. package/dist/utils/executor.test.d.ts +0 -8
  45. package/dist/utils/executor.test.d.ts.map +0 -1
  46. package/dist/utils/executor.test.js +0 -22
  47. package/dist/utils/time_difference.test.d.ts +0 -6
  48. package/dist/utils/time_difference.test.d.ts.map +0 -1
  49. package/dist/utils/time_difference.test.js +0 -11
  50. package/dist/utils/time_factor.test.d.ts +0 -6
  51. package/dist/utils/time_factor.test.d.ts.map +0 -1
  52. package/dist/utils/time_factor.test.js +0 -27
  53. package/src/const.ts +0 -11
  54. package/src/core.ts +0 -89
  55. package/src/dynamic.ts +0 -53
  56. package/src/handle/after-each-hooks.ts +0 -41
  57. package/src/handle/after-hooks.ts +0 -38
  58. package/src/handle/before-each-hooks.ts +0 -40
  59. package/src/handle/before-hooks.ts +0 -39
  60. package/src/handle/cleanup-hooks.ts +0 -55
  61. package/src/handle/specs.ts +0 -68
  62. package/src/index.ts +0 -3
  63. package/src/run.ts +0 -259
  64. package/src/symbol.ts +0 -1
  65. package/src/test-wrap.ts +0 -48
  66. package/src/utils/executor.test.ts +0 -24
  67. package/src/utils/executor.ts +0 -22
  68. package/src/utils/time_difference.test.ts +0 -11
  69. package/src/utils/time_difference.ts +0 -26
  70. package/src/utils/time_factor.test.ts +0 -28
  71. package/src/utils/time_factor.ts +0 -33
  72. package/test/basic.test.ts +0 -23
  73. package/test/before.test.ts +0 -41
  74. package/test/clean-up.test.ts +0 -48
  75. package/test/dynamic-skip.test.ts +0 -6
  76. package/test/dynamic.test.ts +0 -28
  77. package/test/extend.test.ts +0 -43
  78. package/test/hook.test.ts +0 -26
  79. package/test/multi-dependency.test.ts +0 -43
  80. package/test/multiple-uppercased-chars.test.ts +0 -20
  81. package/test/skip-all.test.ts +0 -10
  82. package/test/tsconfig.json +0 -24
  83. package/test/turkish-chars.test.ts +0 -20
  84. package/tsconfig.json +0 -16
package/README.md CHANGED
@@ -1,294 +1,514 @@
1
- ![](docs/nole.png)
2
-
3
- # Nole
4
-
5
- Nole is a testing platform just like mocha..
6
-
7
- > Breaking change at nole v3, plain old classes are better at this task.
8
-
9
- > Use nole 2.x for ESM and Typescript.
10
-
11
- > Use nole 1.x for CommonJS. (ability to disable Typescript with -T option)
12
-
13
- ```ts
14
- // test/queue.test.ts
15
- import { Test } from "nole";
16
-
17
- export class QueueTest extends Test() {
18
- queue!: Queue;
19
-
20
- createInstance() {
21
- this.queue = new Queue();
22
- }
23
-
24
- push() {
25
- this.queue.push(10);
26
- }
27
-
28
- async pipe() {
29
- await this.queue.pipe(somewhere);
30
- }
31
- }
32
- ```
33
-
34
- ```bash
35
- $ nole ./test/**/*.test.ts
36
- (ok) 0.09 ms QueueTest.createInstance()
37
- (ok) 0.11 ms QueueTest.push()
38
- (ok) 1.09 ms QueueTest.pipe()
39
- ```
40
-
41
- ## Skip
42
-
43
- You can skip tests. Make sure method name starts with skip
44
-
45
- ```ts
46
- // test/queue.test.ts
47
- import { Test } from "nole";
48
-
49
- export class QueueTest extends Test() {
50
- skip_Push() {
51
- this.queue.push(10);
52
- }
53
- }
54
- ```
55
-
56
- ```bash
57
- $ nole ./**/test/*.test.ts
58
- (skip) QueueTest.skip_Push() {marked as skipped}
59
- ```
60
-
61
- ```ts
62
- // test/queue.test.ts
63
- import { Test } from "nole";
64
-
65
- export class QueueTest extends Test({
66
- skip: "no need",
67
- }) {
68
- push() {
69
- this.queue.push(10);
70
- }
71
- }
72
- ```
73
-
74
- ```bash
75
- $ nole ./**/test/*.test.ts
76
- (skip) QueueTest.skip_Push() {no need}
77
- ```
78
-
79
- ## Dependencies
80
-
81
- You can include other tests and wait them to complete.
82
-
83
- ```ts
84
- // test/database.test.ts
85
- import { Test } from "nole";
86
-
87
- export class Database extends Test() {
88
- connection!: any;
89
-
90
- async connect() {
91
- connection = new Connection("...");
92
-
93
- await connection.connect();
94
- }
95
- }
96
- ```
97
-
98
- ```ts
99
- // test/other.test.ts
100
- import { Test } from "nole";
101
- import { Database } from "./database.test";
102
-
103
- export class Other extends Test({
104
- dependencies: {
105
- database: () => Database,
106
- },
107
- }) {
108
- async DoThings() {
109
- await this.database.connection.doStuff();
110
- }
111
- }
112
- ```
113
-
114
- > - All dependencies will be waited until done
115
- > - If dependencies cannot resolve, it will occurr an error after the available tests done.
116
-
117
- ## Wait other tests
118
-
119
- ```ts
120
- // test/redis.test.ts
121
- import { Test } from "nole";
122
-
123
- export class A extends Test() {
124
- async doThings() {}
125
- }
126
-
127
- export class B extends Test({ before: () => [A] }) {
128
- async doThings() {}
129
- }
130
- ```
131
-
132
- ## Hook
133
-
134
- Hooks will help you to develop helper methods.
135
-
136
- ```ts
137
- // test/hook.test.ts
138
- import { Test } from "nole";
139
-
140
- export class HookTest {
141
- value!: number;
142
-
143
- async beforeEach() {
144
- this.value = Math.random();
145
- }
146
-
147
- validateNumber() {
148
- if (this.value > 0.5) {
149
- throw new Error("Should not be higher than 0.5");
150
- }
151
- }
152
- }
153
- ```
154
-
155
- ## Dynamic Tests
156
-
157
- ```ts
158
- // test/dynamic.test.ts
159
- import { Test, addTest } from "nole";
160
-
161
- // not exported, nole cannot auto-bind this class
162
- class DynamicTest extends Test() {
163
- test() {}
164
- }
165
-
166
- // adds it anyway
167
- addTest(() => DynamicTest);
168
- ```
169
-
170
- ```ts
171
- // test/dynamic2.test.ts
172
- import { Test, addTest } from "nole";
173
-
174
- if (something) {
175
- addTest(
176
- () =>
177
- class Special extends Test() {
178
- check() {}
179
- },
180
- );
181
- }
182
- ```
183
-
184
- ```ts
185
- // test/dynamic3.test.ts
186
- import { Test, addTest } from "nole";
187
-
188
- export class DeepTest extends Test() {
189
- check() {
190
- if (something) {
191
- addTest(() => class Wololo extends Test() {});
192
- }
193
- }
194
- }
195
- ```
196
-
197
- ## Test cleanup
198
-
199
- There is a special hook that can be used to capture test finishing stage.
200
-
201
- > **Lifecycle:**
202
- >
203
- > - (class) Before
204
- > - - (method) BeforeEach
205
- > - - (method) Spec
206
- > - - (method) AfterEach
207
- > - (class) After
208
- > - (class) CleanUp \*called after dependency execution
209
-
210
- ```ts
211
- // test/database-with-cleanup.test.ts
212
- import { Test } from "nole";
213
-
214
- export class DatabaseWithCleanup extends Test() {
215
- connection!: any;
216
-
217
- async connect() {
218
- this.connection = new Connection("...");
219
-
220
- await connection.connect();
221
- }
222
-
223
- async cleanUp() {
224
- this.connection.close();
225
- console.log("Connection closed!");
226
- }
227
- }
228
- ```
229
-
230
- ```ts
231
- // test/other.test.ts
232
- import { Test } from "nole";
233
- import { Database } from "./database.test";
234
-
235
- export class Other extends Test({
236
- dependencies: {
237
- database: () => DatabaseWithCleanup,
238
- },
239
- }) {
240
- async doThings() {
241
- await this.database.connection.doStuff();
242
- }
243
- }
244
- ```
245
-
246
- ```bash
247
- $ nole ./test/**/*.test.ts
248
- (ok) 0.09 ms DatabaseWithCleanup.connect()
249
- (ok) 0.11 ms Other.doThings()
250
- Connection closed!
251
- ```
252
-
253
- ## Test extending
254
-
255
- If they are classes we should be able to extend them right
256
-
257
- ```ts
258
- // test/extending.test.ts
259
- import { Test } from "nole";
260
-
261
- // Simple is not exported, so nole wont handle it
262
- class Simple extends Test() {
263
- value = 1;
264
-
265
- check() {
266
- if (this.value !== 1) {
267
- // yeah it should be 1 anyway
268
- }
269
- }
270
- }
271
-
272
- export class Complex extends Simple {
273
- check() {
274
- if (this.value > 0) {
275
- // maybe it is more than just 1?
276
- }
277
-
278
- super.check(); // or
279
- }
280
- }
281
-
282
- export class MoreComplex extends Simple {
283
- moreSpecs() {
284
- // mooree
285
- }
286
- }
287
- ```
288
-
289
- ```bash
290
- $ nole ./test/**/*.test.ts
291
- (ok) 0.09 ms Complex.check()
292
- (ok) 0.11 ms MoreComplex.check()
293
- (ok) 0.11 ms MoreComplex.moreSpecs()
294
- ```
1
+ ![](docs/nole.png)
2
+
3
+ # Nole
4
+
5
+ Nole is a testing platform just like mocha.. Feels simple, works really well.
6
+
7
+ ```ts
8
+ // test/queue.test.ts
9
+ import { Test } from "nole";
10
+
11
+ export class QueueTest extends Test() {
12
+ queue!: Queue;
13
+
14
+ createInstance() {
15
+ this.queue = new Queue();
16
+ }
17
+
18
+ push() {
19
+ this.queue.push(10);
20
+ }
21
+
22
+ async pipe() {
23
+ await this.queue.pipe(somewhere);
24
+ }
25
+ }
26
+ ```
27
+
28
+ ```bash
29
+ $ nole ./test/**/*.test.ts
30
+ (ok) 0.09 ms QueueTest.createInstance()
31
+ (ok) 0.11 ms QueueTest.push()
32
+ (ok) 1.09 ms QueueTest.pipe()
33
+ ```
34
+
35
+ ## Skip
36
+
37
+ You can skip tests. Make sure method name starts with skip
38
+
39
+ ```ts
40
+ // test/queue.test.ts
41
+ import { Test } from "nole";
42
+
43
+ export class QueueTest extends Test() {
44
+ skip_Push() {
45
+ this.queue.push(10);
46
+ }
47
+ }
48
+ ```
49
+
50
+ ```bash
51
+ $ nole ./**/test/*.test.ts
52
+ (skip) QueueTest.skip_Push() {marked as skipped}
53
+ ```
54
+
55
+ ```ts
56
+ // test/queue.test.ts
57
+ import { Test } from "nole";
58
+
59
+ export class QueueTest extends Test({
60
+ skip: "no need",
61
+ }) {
62
+ push() {
63
+ this.queue.push(10);
64
+ }
65
+ }
66
+ ```
67
+
68
+ ```bash
69
+ $ nole ./**/test/*.test.ts
70
+ (skip) QueueTest.skip_Push() {no need}
71
+ ```
72
+
73
+ ## Dynamic Skip
74
+
75
+ Sometimes you only know at runtime whether a test should run. Call `skipTest()`
76
+ inside a spec to skip just that spec.
77
+
78
+ ```ts
79
+ // test/queue.test.ts
80
+ import { Test, skipTest } from "nole";
81
+
82
+ export class QueueTest extends Test() {
83
+ push() {
84
+ if (!process.env.QUEUE_URL) {
85
+ skipTest("QUEUE_URL is not set");
86
+ }
87
+
88
+ this.queue.push(10);
89
+ }
90
+ }
91
+ ```
92
+
93
+ ```bash
94
+ $ nole ./test/**/*.test.ts
95
+ (dskip) QueueTest.push() {QUEUE_URL is not set}
96
+ ```
97
+
98
+ ### Skipping the whole class
99
+
100
+ Use `skipClass()` to dynamically skip every remaining spec of the class. This is
101
+ handy inside the `before` hook, so an unmet precondition skips the entire class
102
+ instead of failing.
103
+
104
+ ```ts
105
+ // test/queue.test.ts
106
+ import { Test, skipClass } from "nole";
107
+
108
+ export class QueueTest extends Test() {
109
+ async before() {
110
+ if (!process.env.QUEUE_URL) {
111
+ skipClass("QUEUE_URL is not set");
112
+ }
113
+ }
114
+
115
+ push() {
116
+ this.queue.push(10);
117
+ }
118
+
119
+ async pipe() {
120
+ await this.queue.pipe(somewhere);
121
+ }
122
+ }
123
+ ```
124
+
125
+ ```bash
126
+ $ nole ./test/**/*.test.ts
127
+ (dskip) QueueTest:before() {QUEUE_URL is not set}
128
+ (dskip) QueueTest.push()
129
+ ↳ skip came from :before
130
+ (dskip) QueueTest.pipe()
131
+ ↳ skip came from :before
132
+ ```
133
+
134
+ > You can also call `skipClass()` from a spec — every spec that hasn't run yet
135
+ > will be skipped, and the report shows where the skip came from.
136
+ >
137
+ > `skipClass()` can only be used inside specs and the `before` hook. Hooks
138
+ > cannot be skipped calling `skipTest()` inside `before` is an error; you
139
+ > probably meant `skipClass()`.
140
+
141
+ ## Internal functions
142
+
143
+ Nole treats every method as a spec by default. If you need a plain helper method
144
+ that Nole should not run as a spec, prefix its name with `_`.
145
+
146
+ ```ts
147
+ // test/queue.test.ts
148
+ import { Test } from "nole";
149
+
150
+ export class QueueTest extends Test() {
151
+ async _connect() {
152
+ // not a spec, just a helper you call yourself
153
+ return new Connection("...");
154
+ }
155
+
156
+ async push() {
157
+ const conn = await this._connect();
158
+ conn.push(10);
159
+ }
160
+ }
161
+ ```
162
+
163
+ ```bash
164
+ $ nole ./test/**/*.test.ts
165
+ (ok) 0.11 ms QueueTest.push()
166
+ ```
167
+
168
+ > The prefix is configurable via the `SPEC_SKIP_PREFIX` environment variable
169
+ > (defaults to `_`).
170
+
171
+ ## Dependencies
172
+
173
+ You can include other tests and wait them to complete.
174
+
175
+ ```ts
176
+ // test/database.test.ts
177
+ import { Test } from "nole";
178
+
179
+ export class Database extends Test() {
180
+ connection!: any;
181
+
182
+ async connect() {
183
+ connection = new Connection("...");
184
+
185
+ await connection.connect();
186
+ }
187
+ }
188
+ ```
189
+
190
+ ```ts
191
+ // test/other.test.ts
192
+ import { Test } from "nole";
193
+ import { Database } from "./database.test";
194
+
195
+ export class Other extends Test({
196
+ dependencies: {
197
+ database: () => Database,
198
+ },
199
+ }) {
200
+ async DoThings() {
201
+ await this.database.connection.doStuff();
202
+ }
203
+ }
204
+ ```
205
+
206
+ > - All dependencies will be waited until done
207
+ > - If dependencies cannot resolve, it will occurr an error after the available tests done.
208
+
209
+ ## Wait other tests
210
+
211
+ ```ts
212
+ // test/redis.test.ts
213
+ import { Test } from "nole";
214
+
215
+ export class A extends Test() {
216
+ async doThings() {}
217
+ }
218
+
219
+ export class B extends Test({ before: () => [A] }) {
220
+ async doThings() {}
221
+ }
222
+ ```
223
+
224
+ ## Hook
225
+
226
+ Hooks will help you to develop helper methods.
227
+
228
+ ```ts
229
+ // test/hook.test.ts
230
+ import { Test } from "nole";
231
+
232
+ export class HookTest {
233
+ value!: number;
234
+
235
+ async beforeEach() {
236
+ this.value = Math.random();
237
+ }
238
+
239
+ validateNumber() {
240
+ if (this.value > 0.5) {
241
+ throw new Error("Should not be higher than 0.5");
242
+ }
243
+ }
244
+ }
245
+ ```
246
+
247
+ ## Dynamic Tests
248
+
249
+ ```ts
250
+ // test/dynamic.test.ts
251
+ import { Test, addTest } from "nole";
252
+
253
+ // not exported, nole cannot auto-bind this class
254
+ class DynamicTest extends Test() {
255
+ test() {}
256
+ }
257
+
258
+ // adds it anyway
259
+ addTest(() => DynamicTest);
260
+ ```
261
+
262
+ ```ts
263
+ // test/dynamic2.test.ts
264
+ import { Test, addTest } from "nole";
265
+
266
+ if (something) {
267
+ addTest(
268
+ () =>
269
+ class Special extends Test() {
270
+ check() {}
271
+ },
272
+ );
273
+ }
274
+ ```
275
+
276
+ ```ts
277
+ // test/dynamic3.test.ts
278
+ import { Test, addTest } from "nole";
279
+
280
+ export class DeepTest extends Test() {
281
+ check() {
282
+ if (something) {
283
+ addTest(() => class Wololo extends Test() {});
284
+ }
285
+ }
286
+ }
287
+ ```
288
+
289
+ ## Test cleanup
290
+
291
+ There is a special hook that can be used to capture test finishing stage.
292
+
293
+ > **Lifecycle:**
294
+ >
295
+ > - (class) Before
296
+ > - - (method) BeforeEach
297
+ > - - (method) Spec
298
+ > - - (method) AfterEach
299
+ > - (class) After
300
+ > - (class) CleanUp \*called after dependency execution
301
+
302
+ ```ts
303
+ // test/database-with-cleanup.test.ts
304
+ import { Test } from "nole";
305
+
306
+ export class DatabaseWithCleanup extends Test() {
307
+ connection!: any;
308
+
309
+ async connect() {
310
+ this.connection = new Connection("...");
311
+
312
+ await connection.connect();
313
+ }
314
+
315
+ async cleanUp() {
316
+ this.connection.close();
317
+ console.log("Connection closed!");
318
+ }
319
+ }
320
+ ```
321
+
322
+ ```ts
323
+ // test/other.test.ts
324
+ import { Test } from "nole";
325
+ import { Database } from "./database.test";
326
+
327
+ export class Other extends Test({
328
+ dependencies: {
329
+ database: () => DatabaseWithCleanup,
330
+ },
331
+ }) {
332
+ async doThings() {
333
+ await this.database.connection.doStuff();
334
+ }
335
+ }
336
+ ```
337
+
338
+ ```bash
339
+ $ nole ./test/**/*.test.ts
340
+ (ok) 0.09 ms DatabaseWithCleanup.connect()
341
+ (ok) 0.11 ms Other.doThings()
342
+ Connection closed!
343
+ ```
344
+
345
+ ## Test extending
346
+
347
+ If they are classes we should be able to extend them right
348
+
349
+ ```ts
350
+ // test/extending.test.ts
351
+ import { Test } from "nole";
352
+
353
+ // Simple is not exported, so nole wont handle it
354
+ class Simple extends Test() {
355
+ value = 1;
356
+
357
+ check() {
358
+ if (this.value !== 1) {
359
+ // yeah it should be 1 anyway
360
+ }
361
+ }
362
+ }
363
+
364
+ export class Complex extends Simple {
365
+ check() {
366
+ if (this.value > 0) {
367
+ // maybe it is more than just 1?
368
+ }
369
+
370
+ super.check(); // or
371
+ }
372
+ }
373
+
374
+ export class MoreComplex extends Simple {
375
+ moreSpecs() {
376
+ // mooree
377
+ }
378
+ }
379
+ ```
380
+
381
+ ```bash
382
+ $ nole ./test/**/*.test.ts
383
+ (ok) 0.09 ms Complex.check()
384
+ (ok) 0.11 ms MoreComplex.check()
385
+ (ok) 0.11 ms MoreComplex.moreSpecs()
386
+ ```
387
+
388
+ ### Execution order
389
+
390
+ Inherited specs run parent-first, so a child can rely on the state left behind
391
+ by its ancestors.
392
+
393
+ ```ts
394
+ // test/inheritance.test.ts
395
+ import * as assert from "assert";
396
+ import { Test } from "nole";
397
+
398
+ export class GrandparentTest extends Test() {
399
+ variable = 1;
400
+
401
+ async doesSomething() {
402
+ assert.equal(this.variable, 1);
403
+ this.variable = 2;
404
+ }
405
+ }
406
+
407
+ export class FatherTest extends GrandparentTest {
408
+ async doesSomethingElse() {
409
+ assert.equal(this.variable, 2);
410
+ this.variable = 3;
411
+ }
412
+ }
413
+
414
+ export class ChildTest extends FatherTest {
415
+ async doesMoreStuff() {
416
+ assert.equal(this.variable, 3);
417
+ this.variable = 4;
418
+ }
419
+ }
420
+ ```
421
+
422
+ ```bash
423
+ $ nole ./test/**/*.test.ts
424
+ (ok) 0.09 ms ChildTest.doesSomething()
425
+ (ok) 0.10 ms ChildTest.doesSomethingElse()
426
+ (ok) 0.11 ms ChildTest.doesMoreStuff()
427
+ ```
428
+
429
+ ### Inheriting behavior
430
+
431
+ Skips and hooks are inherited too. A `skipClass()` defined on a base class skips
432
+ every subclass that reaches it, and an overridden hook can call `super` to keep
433
+ the parent's setup.
434
+
435
+ ```ts
436
+ // test/inheritance.test.ts
437
+ import { Test, skipClass } from "nole";
438
+
439
+ // not exported, only used as a base
440
+ class CompanyTest extends Test() {
441
+ async noWorkingAllowed() {
442
+ skipClass("no working allowed");
443
+ }
444
+ }
445
+
446
+ export class EmployeeTest extends CompanyTest {
447
+ async work() {
448
+ // never runs, the class is skipped
449
+ }
450
+ }
451
+
452
+ class HookInitialTest extends Test() {
453
+ variable = 1;
454
+
455
+ before() {
456
+ this.variable = 2;
457
+ }
458
+
459
+ test() {
460
+ assert.equal(this.variable, 2);
461
+ }
462
+ }
463
+
464
+ export class HookOverrideTest extends HookInitialTest {
465
+ before() {
466
+ super.before(); // keep the parent's setup
467
+ this.variable = 10;
468
+ }
469
+
470
+ test() {
471
+ assert.equal(this.variable, 10);
472
+ }
473
+ }
474
+ ```
475
+
476
+ ## CommonJS support
477
+
478
+ Nole ships both an ESM and a CommonJS build, wired up through the package
479
+ `exports` map. Use whichever your project speaks — `import` gets the ESM build,
480
+ `require` gets the CommonJS one:
481
+
482
+ ```js
483
+ import { Test } from "nole"; // ESM
484
+ const { Test } = require("nole"); // CommonJS
485
+ ```
486
+
487
+ You don't even need TypeScript. A plain CommonJS `.js` test file works:
488
+
489
+ ```js
490
+ // test/commonjs/require.test.js
491
+ const { Test } = require("nole");
492
+
493
+ exports.CommonJSTest = class CommonJSTest extends Test() {
494
+ async check() {
495
+ console.log("It works from CommonJS");
496
+ }
497
+ };
498
+ ```
499
+
500
+ When discovering tests, nole loads each file with the loader that matches its own
501
+ module format: ESM files via `import()`, CommonJS files via `require()`. The
502
+ format is decided the same way Node decides it — `.mts`/`.cts` win by extension,
503
+ otherwise the nearest `package.json` `type` field is used. So ESM and CommonJS
504
+ test files can even live side by side in one run:
505
+
506
+ ```bash
507
+ $ nole './test/**/*.test.{ts,js}'
508
+ (ok) 0.11 ms QueueTest.push()
509
+ (ok) 0.58 ms CommonJSTest.check()
510
+ ```
511
+
512
+ > Quote your globs (`'./test/**/*.test.{ts,js}'`) so nole expands them itself
513
+ > instead of relying on the shell — this keeps discovery consistent across
514
+ > environments.