nole 2.2.2 → 3.1.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 (107) hide show
  1. package/.github/workflows/ci.yaml +34 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +474 -388
  4. package/bin/nole.js +145 -111
  5. package/dist/const.d.ts +8 -0
  6. package/dist/const.d.ts.map +1 -0
  7. package/dist/const.js +9 -0
  8. package/dist/core.d.ts +22 -0
  9. package/dist/core.d.ts.map +1 -0
  10. package/dist/core.js +56 -0
  11. package/dist/dynamic.d.ts +5 -1
  12. package/dist/dynamic.d.ts.map +1 -1
  13. package/dist/dynamic.js +35 -1
  14. package/dist/handle/after-each-hooks.d.ts +3 -0
  15. package/dist/handle/after-each-hooks.d.ts.map +1 -0
  16. package/dist/handle/after-each-hooks.js +26 -0
  17. package/dist/handle/after-hooks.d.ts +3 -0
  18. package/dist/handle/after-hooks.d.ts.map +1 -0
  19. package/dist/handle/after-hooks.js +24 -0
  20. package/dist/handle/before-each-hooks.d.ts +3 -0
  21. package/dist/handle/before-each-hooks.d.ts.map +1 -0
  22. package/dist/handle/before-each-hooks.js +26 -0
  23. package/dist/handle/before-hooks.d.ts +3 -0
  24. package/dist/handle/before-hooks.d.ts.map +1 -0
  25. package/dist/handle/before-hooks.js +34 -0
  26. package/dist/handle/cleanup-hooks.d.ts +3 -0
  27. package/dist/handle/cleanup-hooks.d.ts.map +1 -0
  28. package/dist/handle/cleanup-hooks.js +34 -0
  29. package/dist/handle/specs.d.ts +3 -0
  30. package/dist/handle/specs.d.ts.map +1 -0
  31. package/dist/handle/specs.js +50 -0
  32. package/dist/index.d.ts +3 -3
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +4 -4
  35. package/dist/pipeline.test.d.ts +7 -0
  36. package/dist/pipeline.test.d.ts.map +1 -0
  37. package/dist/pipeline.test.js +124 -0
  38. package/dist/run.d.ts +7 -6
  39. package/dist/run.d.ts.map +1 -1
  40. package/dist/run.js +166 -196
  41. package/dist/symbol.d.ts +2 -0
  42. package/dist/symbol.d.ts.map +1 -0
  43. package/dist/symbol.js +2 -0
  44. package/dist/test-wrap.d.ts +38 -0
  45. package/dist/test-wrap.d.ts.map +1 -0
  46. package/dist/test-wrap.js +30 -0
  47. package/dist/utils/executor.js +1 -1
  48. package/dist/utils/executor.test.d.ts +3 -1
  49. package/dist/utils/executor.test.d.ts.map +1 -1
  50. package/dist/utils/executor.test.js +3 -30
  51. package/dist/utils/time_difference.d.ts +9 -0
  52. package/dist/utils/time_difference.d.ts.map +1 -1
  53. package/dist/utils/time_difference.js +10 -1
  54. package/dist/utils/time_difference.test.d.ts +3 -1
  55. package/dist/utils/time_difference.test.d.ts.map +1 -1
  56. package/dist/utils/time_difference.test.js +5 -18
  57. package/dist/utils/time_factor.d.ts.map +1 -1
  58. package/dist/utils/time_factor.js +2 -3
  59. package/dist/utils/time_factor.test.d.ts +3 -1
  60. package/dist/utils/time_factor.test.d.ts.map +1 -1
  61. package/dist/utils/time_factor.test.js +3 -18
  62. package/package.json +58 -58
  63. package/tsconfig.json +18 -18
  64. package/dist/data.d.ts +0 -3
  65. package/dist/data.d.ts.map +0 -1
  66. package/dist/data.js +0 -9
  67. package/dist/data.js.map +0 -1
  68. package/dist/decorators.d.ts +0 -9
  69. package/dist/decorators.d.ts.map +0 -1
  70. package/dist/decorators.js +0 -118
  71. package/dist/decorators.js.map +0 -1
  72. package/dist/dynamic.js.map +0 -1
  73. package/dist/index.js.map +0 -1
  74. package/dist/run.js.map +0 -1
  75. package/dist/test.d.ts +0 -39
  76. package/dist/test.d.ts.map +0 -1
  77. package/dist/test.js +0 -25
  78. package/dist/test.js.map +0 -1
  79. package/dist/utils/executor.js.map +0 -1
  80. package/dist/utils/executor.test.js.map +0 -1
  81. package/dist/utils/time_difference.js.map +0 -1
  82. package/dist/utils/time_difference.test.js.map +0 -1
  83. package/dist/utils/time_factor.js.map +0 -1
  84. package/dist/utils/time_factor.test.js.map +0 -1
  85. package/src/data.ts +0 -13
  86. package/src/decorators.ts +0 -208
  87. package/src/dynamic.ts +0 -11
  88. package/src/index.ts +0 -13
  89. package/src/run.ts +0 -331
  90. package/src/test.ts +0 -47
  91. package/src/utils/executor.test.ts +0 -27
  92. package/src/utils/executor.ts +0 -22
  93. package/src/utils/time_difference.test.ts +0 -12
  94. package/src/utils/time_difference.ts +0 -26
  95. package/src/utils/time_factor.test.ts +0 -29
  96. package/src/utils/time_factor.ts +0 -35
  97. package/test/basic.test.ts +0 -24
  98. package/test/before.test.ts +0 -54
  99. package/test/clean-up.test.ts +0 -52
  100. package/test/dynamic-skip.test.ts +0 -8
  101. package/test/dynamic.test.ts +0 -13
  102. package/test/hook.test.ts +0 -27
  103. package/test/multi-dependency.test.ts +0 -45
  104. package/test/multiple-uppercased-chars.test.ts +0 -19
  105. package/test/skip-all.test.ts +0 -19
  106. package/test/tsconfig.json +0 -24
  107. package/test/turkish-chars.test.ts +0 -19
package/README.md CHANGED
@@ -1,388 +1,474 @@
1
- ![](docs/nole.png)
2
-
3
- Nole
4
- ==========
5
-
6
- Nole is a testing platform just like mocha.. You can create test classes and declare specs with decorators..
7
-
8
- > Use nole 2.x for ESM and Typescript.
9
-
10
- > Use nole 1.x for CommonJS. (ability to disable Typescript with -T option)
11
-
12
- ```ts
13
- // test/queue.test.ts
14
- import { Spec } from 'nole';
15
-
16
- class QueueTest {
17
- queue!: Queue;
18
-
19
- @Spec()
20
- CreateInstance() {
21
- this.queue = new Queue();
22
- }
23
-
24
- @Spec()
25
- Push() {
26
- this.queue.push(10);
27
- }
28
-
29
- @Spec(1000)
30
- async Pipe() {
31
- await this.queue.pipe(somewhere);
32
- }
33
- }
34
- ```
35
-
36
- ```bash
37
- $ nole ./test/**/*.test.ts
38
- (ok) 0.09 ms QueueTest.CreateInstance()
39
- (ok) 0.11 ms QueueTest.Push()
40
- (ok) 1.09 ms QueueTest.Pipe()
41
- ```
42
-
43
- ## Spec
44
-
45
- Declaring the spec tag will notify the nole core and assigns the tasks for later use. You can also specify timeout. Default timeout is 5000 ms.
46
-
47
- ```ts
48
- // test/queue.test.ts
49
- import { Spec } from 'nole';
50
-
51
- class QueueTest {
52
- @Spec(10000)
53
- Push() {
54
- this.queue.push(10);
55
- }
56
- }
57
- ```
58
-
59
- > * All specs will be executed as creation order.
60
- > * Timing colors are defined by timeout value. If value smaller than (timeout / 5) output will be green. If value bigger than this but smaller than (timeout / 2.5); it will be yellow. In all other cases color will be red.
61
-
62
-
63
- ## Skip
64
-
65
- You can skip tests. (hooks will be disabled for this spec)
66
-
67
- ```ts
68
- // test/queue.test.ts
69
- import { Spec, Skip } from 'nole';
70
-
71
- class QueueTest {
72
- @Skip('deprecated unit')
73
- @Spec()
74
- Push() {
75
- this.queue.push(10);
76
- }
77
- }
78
- ```
79
-
80
- > * Skipping the task make it yellow colored.
81
-
82
- ```bash
83
- $ nole ./**/test/*.test.ts
84
- (skip) QueueTest.Push() {deprecated unit}
85
- ```
86
-
87
- ## SkipClass
88
-
89
- You can skip whole test classes. It's equivalent of spec skipping, but you don't have to select one by one.
90
- **Kindly reminder**: Dependents might require this test class and props.
91
-
92
- ```ts
93
- // test/queue-skip-class.test.ts
94
- import { Spec, Skip, SkipClass } from 'nole';
95
-
96
- @SkipClass('No need anymore')
97
- class QueueTest {
98
- @Spec()
99
- Push() { }
100
-
101
- @Skip('deprecated unit')
102
- @Spec()
103
- PushButSomehowDifferent() { }
104
- }
105
- ```
106
-
107
- ```bash
108
- $ nole ./**/test/*.test.ts
109
- (skip) QueueTest.Push() {No need anymore}
110
- (skip) QueueTest.PushButSomehowDifferent() {deprecated unit}
111
- ```
112
-
113
-
114
- ## Dependencies
115
-
116
- You can include other tests and wait them to complete.
117
-
118
- ```ts
119
- // test/database.test.ts
120
- import { Spec } from 'nole';
121
-
122
- export class Database {
123
- connection!: any;
124
-
125
- @Spec()
126
- async Connect() {
127
- connection = new Connection('...');
128
-
129
- await connection.connect();
130
- }
131
- }
132
- ```
133
-
134
- ```ts
135
- // test/other.test.ts
136
- import { Spec, Dependency } from 'nole';
137
- import { Database } from './database.test';
138
-
139
- class Other {
140
- @Dependency(Database)
141
- database!: Database;
142
-
143
- @Spec()
144
- async DoThings() {
145
- await database.connection.doStuff();
146
- }
147
- }
148
- ```
149
-
150
- > * All dependencies will be waited until done
151
- > * If dependencies cannot resolve, it will occurr an error after the available tests done.
152
-
153
-
154
- ## Multi Dependencies
155
-
156
- Easier way to declare dependencies by decorating class with an array.
157
-
158
- ```ts
159
- // test/redis.test.ts
160
- import { Spec, Dependencies } from 'nole';
161
- import { Database } from './database.test';
162
- import { Other } from './other.test';
163
-
164
- @Dependencies([
165
- Database,
166
- Other
167
- ])
168
- class Redis {
169
- database: Database; // camel-case syntax
170
- // even though other does not exist in this test, but nole will make sure it is completed when this test runs
171
-
172
- @Spec()
173
- async DoThings() {
174
- await database.connection.doStuff();
175
- }
176
- }
177
- ```
178
-
179
- ## Lazy multi Dependencies / after
180
-
181
- Can solve order of execution issues
182
-
183
- ```ts
184
- // test/redis.test.ts
185
- import { Spec, Dependencies, After } from 'nole';
186
-
187
- @Dependencies(() => [ B ])
188
- // or
189
- // @After(() => [ B ])
190
- class A {
191
- b: B;
192
-
193
- @Spec()
194
- async DoThings() { }
195
- }
196
-
197
- class B {
198
- @Spec()
199
- async DoThings() { }
200
- }
201
- ```
202
-
203
- ## Reverse dependency / dependent / before
204
-
205
-
206
-
207
- ```ts
208
- // test/redis.test.ts
209
- import { Spec, Dependents, Before } from 'nole';
210
-
211
- class A {
212
- b: B;
213
-
214
- @Spec()
215
- async DoThings() { }
216
- }
217
-
218
- @Before(() => [ A ])
219
- class B {
220
- @Spec()
221
- async DoThings() { }
222
- }
223
- ```
224
-
225
- ## Hook
226
-
227
- Hooks will help you to develop helper methods.
228
-
229
- ```ts
230
- // test/hook.test.ts
231
- import { Spec, Hook, HookType } from 'nole';
232
-
233
- class HookTest {
234
- value!: number;
235
-
236
- @Hook(HookType.BeforeEach)
237
- async beforeEach() {
238
- this.value = Math.random();
239
- }
240
-
241
- @Spec()
242
- ValidateNumber() {
243
- if (this.value > 0.5) {
244
- throw new Error('Should not be higher than 0.5');
245
- }
246
- }
247
- }
248
- ```
249
-
250
- > * Hooks can be async tasks.
251
- > * Hooks do have timeout, you can change it by second parameter.
252
- > * If you name hook same as hook type then; When it occurr an error, It will print "class:hookType" otherwise "class.name:hoopType"
253
- > * Hooks cannot be spec
254
- > * Hooks cannot skipped
255
-
256
- ## Dynamic Tests
257
-
258
- Dynamic tests are not featured in but you can create another method and call it dynamicly.
259
-
260
-
261
- ```ts
262
- // test/dynamic.test.ts
263
- import { Spec } from 'nole';
264
-
265
- class DynamicTest {
266
- @Spec()
267
- Some() {
268
- for (let i = 0; i < 10; i++) {
269
- this.single(i);
270
- }
271
- }
272
-
273
- single(i) {
274
- // ...
275
- }
276
- }
277
- ```
278
-
279
- ## Dependency hook
280
-
281
- After end of the test tree, special hook will be called. Nole will follow execution order to run; first executed spec's "CleanUp" hook will be called last.
282
-
283
-
284
- ```ts
285
- // test/database-with-cleanup.test.ts
286
- import { Spec, HookType, Hook } from 'nole';
287
-
288
- export class DatabaseWithCleanup {
289
- connection!: any;
290
-
291
- @Spec()
292
- async Connect() {
293
- connection = new Connection('...');
294
-
295
- await connection.connect();
296
- }
297
-
298
- @Hook(HookType.CleanUp)
299
- async cleanUp() {
300
- this.connection.close();
301
- console.log('Connection closed!');
302
- }
303
- }
304
- ```
305
-
306
- ```ts
307
- // test/other.test.ts
308
- import { Spec, Dependency } from 'nole';
309
- import { Database } from './database.test';
310
-
311
- class Other {
312
- @Dependency(DatabaseWithCleanup)
313
- database!: DatabaseWithCleanup;
314
-
315
- @Spec()
316
- async DoThings() {
317
- await database.connection.doStuff();
318
- }
319
- }
320
- ```
321
-
322
- ```bash
323
- $ nole ./test/**/*.test.ts
324
- (ok) 0.09 ms DatabaseWithCleanup.Connect()
325
- (ok) 0.11 ms Other.DoThings()
326
- Connection closed!
327
- ```
328
-
329
-
330
-
331
- ## Assert
332
-
333
- We do not provide assert library. You can use chai or should.js.
334
-
335
- ## Debugging
336
-
337
- Having cleanup features with missing dependencies could lead to issues and time loses. To make sure execution of tests correct, use `-O` parameter to print out every spec and hook without calling the function. It will also print before/after hook orders.
338
-
339
- ```bash
340
- $ nole -O ./test/**/*.test.ts
341
- (skip) SkipAllTest.wontRun() {skip all class}
342
- (skip) SkipAllTest.wontRunToo() {wont run too}
343
- (skip) SkipAllWithoutReason.wontRun()
344
- (ok) 0 ms BasicTest.checkEqual()
345
- (ok) 0 ms DependencyTest.check()
346
- (ok) 0 ms CleanUpLayer1Test.start()
347
- (ok) 0 ms CleanUpLayer2Test.start()
348
- (ok) 0 ms CleanUpLayer3Test.start()
349
- (ok) 0 ms DynamicSkipTest.thisShouldBeSkipped()
350
- (ok) 0 ms HookTest.pushFourIntoArray:beforeEach()
351
- (ok) 0 ms HookTest.hasToBe4()
352
- (skip) HookTest.hasToBe4Again() {no need}
353
- (ok) 0 ms HookTest.pushFourIntoArray:beforeEach()
354
- (ok) 0.03 ms HookTest.hasToBe4AgainButNotSkipped()
355
- (ok) 0 ms MultiDependency.test()
356
- (ok) 0 ms CleanUpLayer3Test:cleanUp()
357
- (ok) 0 ms CleanUpLayer2Test:cleanUp()
358
- (ok) 0 ms CleanUpLayer1Test:cleanUp()
359
- (ok) 0 ms DynamicTest.thisTestsShouldNotFail()
360
- (ok) 0 ms TimeFactorTest.evaluate()
361
- (ok) 0 ms TimeDifferenceTest.evaluate()
362
- (ok) 0 ms ExecutorTest.evaluate()
363
- (ok) 0 ms ExecutorTest.throws()
364
- (ok) 0 ms ExecutorTest.timeout()
365
- ```
366
-
367
- ## Compiled files
368
-
369
- > Deprecated (v2.x+), It will always use ts-node/esm module
370
-
371
- You can run the compiled test files with `-T` option.
372
-
373
- ```bash
374
- $ nole -T ./build/test/**/*.test.js
375
- (ok) 0.09 ms QueueTest.CreateInstance()
376
- (ok) 0.11 ms QueueTest.Push()
377
- (ok) 1.09 ms QueueTest.Pipe()
378
- ```
379
-
380
- > This will prevent to load ts-node register. It will be quite faster.
381
-
382
- ## Environment values to configure stuff
383
-
384
- ```
385
- NOLE_PRESERVE_CONSECUTIVE_UPPERCASE=true
386
- NOLE_PASCALCASE=false
387
- NOLE_WAIT_PERIOD=500
388
- ```
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
+ ```