testeranto 0.9.21 → 0.15.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.
- package/README.md +2 -2
- package/bin/report.sh +0 -1
- package/bin/testeranto.sh +3 -0
- package/package.json +22 -17
- package/src/Report.tsx +1 -1
- package/src/index.d.mts +277 -0
- package/src/index.mjs +480 -0
- package/src/index.mts +1129 -0
- package/src/testeranto.mts +398 -0
- package/testerantoDemo.gif +0 -0
- package/testerantoDemo.mov +0 -0
- package/tsconfig.json +4 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/bin/build.sh +0 -5
- package/bin/watch.sh +0 -5
- package/dist/reporter.css +0 -10326
- package/dist/reporter.html +0 -16
- package/dist/reporter.js +0 -26777
- package/example-testeranto.config.json +0 -65
- package/src/BaseClasses.ts +0 -353
- package/src/Features.ts +0 -102
- package/src/Project.ts +0 -23
- package/src/build.js +0 -88
- package/src/index.ts +0 -153
- package/src/lib/Scheduler.ts +0 -350
- package/src/lib/level0.ts +0 -157
- package/src/lib/level1.ts +0 -191
- package/src/types.ts +0 -122
- package/src/watch.ts +0 -69
- package/yarn-error.log +0 -3144
package/src/index.mts
ADDED
|
@@ -0,0 +1,1129 @@
|
|
|
1
|
+
import pkg from 'graphology';
|
|
2
|
+
/* @ts-ignore:next-line */
|
|
3
|
+
const { DirectedGraph, UndirectedGraph } = pkg;
|
|
4
|
+
|
|
5
|
+
export class BaseFeature {
|
|
6
|
+
name: string;
|
|
7
|
+
constructor(name: string) {
|
|
8
|
+
this.name = name;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
abstract class TesterantoGraph {
|
|
13
|
+
name: string;
|
|
14
|
+
abstract graph;
|
|
15
|
+
|
|
16
|
+
constructor(name: string) {
|
|
17
|
+
this.name = name;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class TesterantoGraphUndirected implements TesterantoGraph {
|
|
22
|
+
name: string;
|
|
23
|
+
graph: typeof UndirectedGraph
|
|
24
|
+
constructor(name: string) {
|
|
25
|
+
this.name = name;
|
|
26
|
+
this.graph = new UndirectedGraph();
|
|
27
|
+
}
|
|
28
|
+
connect(a, b, relation?: string) {
|
|
29
|
+
this.graph.mergeEdge(a, b, { type: relation });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class TesterantoGraphDirected implements TesterantoGraph {
|
|
34
|
+
name: string;
|
|
35
|
+
graph: typeof DirectedGraph;
|
|
36
|
+
constructor(name: string) {
|
|
37
|
+
this.name = name;
|
|
38
|
+
this.graph = new DirectedGraph();
|
|
39
|
+
}
|
|
40
|
+
connect(to, from, relation?: string) {
|
|
41
|
+
this.graph.mergeEdge(to, from, { type: relation });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class TesterantoGraphDirectedAcyclic implements TesterantoGraph {
|
|
46
|
+
name: string;
|
|
47
|
+
graph: typeof DirectedGraph;
|
|
48
|
+
constructor(name: string) {
|
|
49
|
+
this.name = name;
|
|
50
|
+
this.graph = new DirectedGraph();
|
|
51
|
+
}
|
|
52
|
+
connect(to, from, relation?: string) {
|
|
53
|
+
this.graph.mergeEdge(to, from, { type: relation });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class TesterantoFeatures {
|
|
58
|
+
features: Record<string, BaseFeature>;
|
|
59
|
+
graphs: {
|
|
60
|
+
undirected: TesterantoGraphUndirected[],
|
|
61
|
+
directed: TesterantoGraphDirected[],
|
|
62
|
+
dags: TesterantoGraphDirectedAcyclic[]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
constructor(
|
|
66
|
+
features: Record<string, BaseFeature>,
|
|
67
|
+
graphs: {
|
|
68
|
+
undirected: TesterantoGraphUndirected[],
|
|
69
|
+
directed: TesterantoGraphDirected[],
|
|
70
|
+
dags: TesterantoGraphDirectedAcyclic[]
|
|
71
|
+
}
|
|
72
|
+
) {
|
|
73
|
+
this.features = features;
|
|
74
|
+
this.graphs = graphs;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
networks() {
|
|
78
|
+
return [
|
|
79
|
+
...this.graphs.undirected.values(),
|
|
80
|
+
...this.graphs.directed.values(),
|
|
81
|
+
...this.graphs.dags.values()
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
toObj() {
|
|
86
|
+
return {
|
|
87
|
+
features: Object.entries(this.features).map(([name, feature]) => {
|
|
88
|
+
return {
|
|
89
|
+
...feature,
|
|
90
|
+
inNetworks: this.networks().filter((network) => {
|
|
91
|
+
return network.graph.hasNode(feature.name);
|
|
92
|
+
}).map((network) => {
|
|
93
|
+
return {
|
|
94
|
+
|
|
95
|
+
network: network.name,
|
|
96
|
+
neighbors: network.graph.neighbors(feature.name)
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
}),
|
|
101
|
+
networks: this.networks().map((network) => {
|
|
102
|
+
return {
|
|
103
|
+
...network
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const testOutPath = "./dist/results/";
|
|
111
|
+
|
|
112
|
+
export type ITTestResourceRequirement = {
|
|
113
|
+
"ports": number
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
type ITTestResource = {
|
|
117
|
+
"ports": number[]
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export type IT_FeatureNetwork = {
|
|
121
|
+
name: string,
|
|
122
|
+
// graph: DirectedGraph
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export type IT = {
|
|
126
|
+
toObj(): object;
|
|
127
|
+
aborter: () => any;
|
|
128
|
+
name: string;
|
|
129
|
+
givens: BaseGiven<unknown, unknown, unknown, unknown, unknown>[];
|
|
130
|
+
checks: BaseCheck<unknown, unknown, unknown, unknown, ITTestShape, unknown>[];
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export type ITestJob = {
|
|
134
|
+
toObj(): object;
|
|
135
|
+
test: IT;
|
|
136
|
+
runner: (testResource) => Promise<boolean>;
|
|
137
|
+
testResource: ITTestResourceRequirement;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export type ITestResults = Promise<{
|
|
141
|
+
test: IT;
|
|
142
|
+
}>[];
|
|
143
|
+
|
|
144
|
+
export type Modify<T, R> = Omit<T, keyof R> & R;
|
|
145
|
+
|
|
146
|
+
export type ITTestShape = {
|
|
147
|
+
suites;
|
|
148
|
+
givens;
|
|
149
|
+
whens;
|
|
150
|
+
thens;
|
|
151
|
+
checks;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export type ITestSpecification<ITestShape extends ITTestShape, IFeatureShape> = (
|
|
155
|
+
Suite: {
|
|
156
|
+
[K in keyof ITestShape["suites"]]: (
|
|
157
|
+
name: string,
|
|
158
|
+
givens: BaseGiven<unknown, unknown, unknown, unknown, unknown>[],
|
|
159
|
+
checks: BaseCheck<unknown, unknown, unknown, unknown, ITestShape, IFeatureShape>[]
|
|
160
|
+
) => BaseSuite<unknown, unknown, unknown, unknown, unknown, ITestShape, IFeatureShape>;
|
|
161
|
+
},
|
|
162
|
+
Given: {
|
|
163
|
+
[K in keyof ITestShape["givens"]]: (
|
|
164
|
+
features: (keyof IFeatureShape)[],
|
|
165
|
+
whens: BaseWhen<unknown, unknown, unknown>[],
|
|
166
|
+
thens: BaseThen<unknown, unknown, unknown>[],
|
|
167
|
+
...xtras: ITestShape["givens"][K]
|
|
168
|
+
) => BaseGiven<unknown, unknown, unknown, unknown, unknown>;
|
|
169
|
+
},
|
|
170
|
+
When: {
|
|
171
|
+
[K in keyof ITestShape["whens"]]: (
|
|
172
|
+
...xtras: ITestShape["whens"][K]
|
|
173
|
+
) => BaseWhen<unknown, unknown, unknown>;
|
|
174
|
+
},
|
|
175
|
+
Then: {
|
|
176
|
+
[K in keyof ITestShape["thens"]]: (
|
|
177
|
+
...xtras: ITestShape["thens"][K]
|
|
178
|
+
) => BaseThen<unknown, unknown, unknown>;
|
|
179
|
+
},
|
|
180
|
+
Check: {
|
|
181
|
+
[K in keyof ITestShape["checks"]]: (
|
|
182
|
+
|
|
183
|
+
name: string,
|
|
184
|
+
features: (keyof IFeatureShape)[],
|
|
185
|
+
callbackA: (
|
|
186
|
+
whens: {
|
|
187
|
+
[K in keyof ITestShape["whens"]]: (...unknown) => BaseWhen<unknown, unknown, unknown>
|
|
188
|
+
},
|
|
189
|
+
thens: {
|
|
190
|
+
[K in keyof ITestShape["thens"]]: (...unknown) => BaseThen<unknown, unknown, unknown>
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
) => unknown,
|
|
194
|
+
// whens: BaseWhen<unknown, unknown, unknown>[],
|
|
195
|
+
// thens: BaseThen<unknown, unknown, unknown>[],
|
|
196
|
+
|
|
197
|
+
...xtras: ITestShape["checks"][K]
|
|
198
|
+
) => BaseCheck<unknown, unknown, unknown, unknown, ITestShape, IFeatureShape>;
|
|
199
|
+
}
|
|
200
|
+
) => any[];
|
|
201
|
+
|
|
202
|
+
export type ITestImplementation<
|
|
203
|
+
IState,
|
|
204
|
+
ISelection,
|
|
205
|
+
IWhenShape,
|
|
206
|
+
IThenShape,
|
|
207
|
+
ITestShape extends ITTestShape
|
|
208
|
+
> = {
|
|
209
|
+
Suites: {
|
|
210
|
+
[K in keyof ITestShape["suites"]]: string;
|
|
211
|
+
};
|
|
212
|
+
Givens: {
|
|
213
|
+
[K in keyof ITestShape["givens"]]: (
|
|
214
|
+
...Ig: ITestShape["givens"][K]
|
|
215
|
+
) => IState;
|
|
216
|
+
};
|
|
217
|
+
Whens: {
|
|
218
|
+
[K in keyof ITestShape["whens"]]: (
|
|
219
|
+
...Iw: ITestShape["whens"][K]
|
|
220
|
+
) => (zel: ISelection) => IWhenShape;
|
|
221
|
+
};
|
|
222
|
+
Thens: {
|
|
223
|
+
[K in keyof ITestShape["thens"]]: (
|
|
224
|
+
...It: ITestShape["thens"][K]
|
|
225
|
+
) => (ssel: ISelection) => IThenShape;
|
|
226
|
+
};
|
|
227
|
+
Checks: {
|
|
228
|
+
[K in keyof ITestShape["checks"]]: (
|
|
229
|
+
...Ic: ITestShape["checks"][K]
|
|
230
|
+
) => IState;
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
class TestArtifact {
|
|
235
|
+
binary: Buffer | string;
|
|
236
|
+
|
|
237
|
+
constructor(binary) {
|
|
238
|
+
this.binary = binary
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
export abstract class BaseSuite<
|
|
244
|
+
IInput,
|
|
245
|
+
ISubject,
|
|
246
|
+
IStore,
|
|
247
|
+
ISelection,
|
|
248
|
+
IThenShape,
|
|
249
|
+
ITestShape extends ITTestShape,
|
|
250
|
+
IFeatureShape,
|
|
251
|
+
> {
|
|
252
|
+
name: string;
|
|
253
|
+
givens: BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>[];
|
|
254
|
+
checks: BaseCheck<ISubject, IStore, ISelection, IThenShape, ITestShape, IFeatureShape>[];
|
|
255
|
+
store: IStore;
|
|
256
|
+
aborted: boolean;
|
|
257
|
+
fails: BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>[];
|
|
258
|
+
testResourceConfiguration: ITTestResource;
|
|
259
|
+
|
|
260
|
+
constructor(
|
|
261
|
+
name: string,
|
|
262
|
+
givens: BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>[] = [],
|
|
263
|
+
checks: BaseCheck<ISubject, IStore, ISelection, IThenShape, ITestShape, IFeatureShape>[] = []
|
|
264
|
+
) {
|
|
265
|
+
this.name = name;
|
|
266
|
+
this.givens = givens;
|
|
267
|
+
this.checks = checks;
|
|
268
|
+
this.fails = [];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async aborter() {
|
|
272
|
+
this.aborted = true;
|
|
273
|
+
await Promise.all((this.givens || []).map((g, ndx) => g.aborter(ndx)))
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
public toObj() {
|
|
277
|
+
return {
|
|
278
|
+
name: this.name,
|
|
279
|
+
givens: this.givens.map((g) => g.toObj()),
|
|
280
|
+
fails: this.fails
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
setup(s: IInput): Promise<ISubject> {
|
|
285
|
+
return new Promise((res) => res(s as unknown as ISubject));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
test(t: IThenShape): unknown {
|
|
289
|
+
return t;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async run(input, testResourceConfiguration: ITTestResource): Promise<boolean> {
|
|
293
|
+
this.testResourceConfiguration = Object.keys(testResourceConfiguration).length ? testResourceConfiguration : { ports: [] };
|
|
294
|
+
const subject = await this.setup(input);
|
|
295
|
+
console.log("\nSuite:", this.name, testResourceConfiguration);
|
|
296
|
+
for (const [ndx, giver] of this.givens.entries()) {
|
|
297
|
+
try {
|
|
298
|
+
if (!this.aborted) {
|
|
299
|
+
this.store = await giver.give(subject, ndx, testResourceConfiguration, this.test);
|
|
300
|
+
}
|
|
301
|
+
} catch (e) {
|
|
302
|
+
console.error(e);
|
|
303
|
+
this.fails.push(giver)
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
for (const [ndx, thater] of this.checks.entries()) {
|
|
308
|
+
await thater.check(subject, ndx, testResourceConfiguration, this.test);
|
|
309
|
+
}
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export abstract class BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape> {
|
|
315
|
+
name: string;
|
|
316
|
+
features: (keyof IFeatureShape)[];
|
|
317
|
+
whens: BaseWhen<IStore, ISelection, IThenShape>[];
|
|
318
|
+
thens: BaseThen<ISelection, IStore, IThenShape>[];
|
|
319
|
+
error: Error;
|
|
320
|
+
abort: boolean;
|
|
321
|
+
store: IStore;
|
|
322
|
+
testArtifacts: Record<string, any[]>
|
|
323
|
+
|
|
324
|
+
constructor(
|
|
325
|
+
name: string,
|
|
326
|
+
features: (keyof IFeatureShape)[],
|
|
327
|
+
whens: BaseWhen<IStore, ISelection, IThenShape>[],
|
|
328
|
+
thens: BaseThen<ISelection, IStore, IThenShape>[],
|
|
329
|
+
) {
|
|
330
|
+
this.name = name;
|
|
331
|
+
this.features = features;
|
|
332
|
+
this.whens = whens;
|
|
333
|
+
this.thens = thens;
|
|
334
|
+
this.testArtifacts = {};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
toObj() {
|
|
338
|
+
return {
|
|
339
|
+
name: this.name,
|
|
340
|
+
whens: this.whens.map((w) => w.toObj()),
|
|
341
|
+
thens: this.thens.map((t) => t.toObj()),
|
|
342
|
+
errors: this.error,
|
|
343
|
+
features: this.features,
|
|
344
|
+
testArtifacts: this.testArtifacts,
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
abstract givenThat(
|
|
349
|
+
subject: ISubject,
|
|
350
|
+
testResourceConfiguration?
|
|
351
|
+
): Promise<IStore>;
|
|
352
|
+
|
|
353
|
+
saveTestArtifact(k: string, testArtifact: TestArtifact) {
|
|
354
|
+
if (!this.testArtifacts[k]) {
|
|
355
|
+
this.testArtifacts[k] = []
|
|
356
|
+
}
|
|
357
|
+
this.testArtifacts[k].push(testArtifact)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
artifactSaver = {
|
|
361
|
+
png: (testArtifact) => this.saveTestArtifact('afterEach', new TestArtifact(testArtifact))
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async aborter(ndx: number) {
|
|
365
|
+
this.abort = true;
|
|
366
|
+
return Promise.all([
|
|
367
|
+
...this.whens.map((w, ndx) => new Promise((res) => res(w.aborter()))),
|
|
368
|
+
...this.thens.map((t, ndx) => new Promise((res) => res(t.aborter()))),
|
|
369
|
+
])
|
|
370
|
+
.then(async () => {
|
|
371
|
+
return await this.afterEach(this.store, ndx, this.artifactSaver)
|
|
372
|
+
})
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
async afterEach(store: IStore, ndx: number, cb): Promise<unknown> {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
async give(
|
|
380
|
+
subject: ISubject,
|
|
381
|
+
index: number,
|
|
382
|
+
testResourceConfiguration,
|
|
383
|
+
tester
|
|
384
|
+
) {
|
|
385
|
+
console.log(`\n Given: ${this.name}`);
|
|
386
|
+
try {
|
|
387
|
+
if (!this.abort) {
|
|
388
|
+
this.store = await this.givenThat(subject, testResourceConfiguration);
|
|
389
|
+
}
|
|
390
|
+
for (const whenStep of this.whens) {
|
|
391
|
+
await whenStep.test(this.store, testResourceConfiguration);
|
|
392
|
+
}
|
|
393
|
+
for (const thenStep of this.thens) {
|
|
394
|
+
const t = await thenStep.test(this.store, testResourceConfiguration);
|
|
395
|
+
tester(t);
|
|
396
|
+
}
|
|
397
|
+
} catch (e) {
|
|
398
|
+
this.error = e;
|
|
399
|
+
console.log('\u0007');// bell
|
|
400
|
+
throw e;
|
|
401
|
+
} finally {
|
|
402
|
+
|
|
403
|
+
try {
|
|
404
|
+
await this.afterEach(this.store, index, this.artifactSaver);
|
|
405
|
+
} catch {
|
|
406
|
+
console.error("afterEach failed! no error will be recorded!")
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
}
|
|
410
|
+
return this.store;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export abstract class BaseWhen<IStore, ISelection, IThenShape> {
|
|
415
|
+
public name: string;
|
|
416
|
+
actioner: (x: ISelection) => IThenShape;
|
|
417
|
+
error: boolean;
|
|
418
|
+
abort: boolean;
|
|
419
|
+
|
|
420
|
+
constructor(name: string, actioner: (xyz: ISelection) => IThenShape) {
|
|
421
|
+
this.name = name;
|
|
422
|
+
this.actioner = actioner;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
abstract andWhen(
|
|
426
|
+
store: IStore,
|
|
427
|
+
actioner: (x: ISelection) => IThenShape,
|
|
428
|
+
testResource
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
toObj() {
|
|
432
|
+
return {
|
|
433
|
+
name: this.name,
|
|
434
|
+
error: this.error,
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
aborter() {
|
|
439
|
+
this.abort = true;
|
|
440
|
+
return this.abort;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
async test(store: IStore, testResourceConfiguration?) {
|
|
444
|
+
console.log(" When:", this.name);
|
|
445
|
+
if (!this.abort) {
|
|
446
|
+
try {
|
|
447
|
+
return await this.andWhen(store, this.actioner, testResourceConfiguration);
|
|
448
|
+
} catch (e) {
|
|
449
|
+
this.error = true;
|
|
450
|
+
throw e
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export abstract class BaseThen<ISelection, IStore, IThenShape> {
|
|
457
|
+
public name: string;
|
|
458
|
+
thenCB: (storeState: ISelection) => IThenShape;
|
|
459
|
+
error: boolean;
|
|
460
|
+
abort: boolean;
|
|
461
|
+
|
|
462
|
+
constructor(name: string, thenCB: (val: ISelection) => IThenShape) {
|
|
463
|
+
this.name = name;
|
|
464
|
+
this.thenCB = thenCB;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
toObj() {
|
|
468
|
+
return {
|
|
469
|
+
name: this.name,
|
|
470
|
+
error: this.error,
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
abstract butThen(store: any, testResourceConfiguration?): Promise<ISelection>;
|
|
475
|
+
|
|
476
|
+
aborter() {
|
|
477
|
+
this.abort = true;
|
|
478
|
+
return this.abort;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
async test(store: IStore, testResourceConfiguration): Promise<IThenShape | undefined> {
|
|
482
|
+
if (!this.abort) {
|
|
483
|
+
console.log(" Then:", this.name);
|
|
484
|
+
try {
|
|
485
|
+
return await this.thenCB(await this.butThen(store, testResourceConfiguration));
|
|
486
|
+
} catch (e) {
|
|
487
|
+
this.error = true;
|
|
488
|
+
throw e
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export abstract class BaseCheck<
|
|
495
|
+
ISubject,
|
|
496
|
+
IStore,
|
|
497
|
+
ISelection,
|
|
498
|
+
IThenShape,
|
|
499
|
+
ITestShape extends ITTestShape,
|
|
500
|
+
IFeatureShape
|
|
501
|
+
> {
|
|
502
|
+
name: string;
|
|
503
|
+
features: (keyof IFeatureShape)[];
|
|
504
|
+
checkCB: (whens, thens) => any;
|
|
505
|
+
whens: {
|
|
506
|
+
[K in keyof ITestShape["whens"]]: (p, tc) =>
|
|
507
|
+
BaseWhen<IStore, ISelection, IThenShape>
|
|
508
|
+
}
|
|
509
|
+
thens: {
|
|
510
|
+
[K in keyof ITestShape["thens"]]: (p, tc) =>
|
|
511
|
+
BaseThen<ISelection, IStore, IThenShape>
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
constructor(
|
|
515
|
+
name: string,
|
|
516
|
+
features: (keyof IFeatureShape)[],
|
|
517
|
+
checkCB: (
|
|
518
|
+
whens,
|
|
519
|
+
thens
|
|
520
|
+
) => any,
|
|
521
|
+
whens,
|
|
522
|
+
thens
|
|
523
|
+
) {
|
|
524
|
+
|
|
525
|
+
this.name = name;
|
|
526
|
+
this.features = features;
|
|
527
|
+
this.checkCB = checkCB;
|
|
528
|
+
this.whens = whens;
|
|
529
|
+
this.thens = thens;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
abstract checkThat(
|
|
533
|
+
subject: ISubject,
|
|
534
|
+
testResourceConfiguration?
|
|
535
|
+
): Promise<IStore>;
|
|
536
|
+
|
|
537
|
+
async afterEach(store: IStore, ndx: number, cb?): Promise<unknown> {
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
async check(
|
|
542
|
+
subject: ISubject,
|
|
543
|
+
ndx: number,
|
|
544
|
+
testResourceConfiguration,
|
|
545
|
+
tester
|
|
546
|
+
) {
|
|
547
|
+
console.log(`\n Check: ${this.name}`);
|
|
548
|
+
const store = await this.checkThat(subject, testResourceConfiguration);
|
|
549
|
+
await this.checkCB(
|
|
550
|
+
|
|
551
|
+
(
|
|
552
|
+
Object.entries(this.whens)
|
|
553
|
+
.reduce((a, [key, when]) => {
|
|
554
|
+
a[key] = async (payload) => {
|
|
555
|
+
return await when(payload, testResourceConfiguration).test(
|
|
556
|
+
store,
|
|
557
|
+
testResourceConfiguration
|
|
558
|
+
);
|
|
559
|
+
};
|
|
560
|
+
return a;
|
|
561
|
+
}, {}
|
|
562
|
+
)
|
|
563
|
+
),
|
|
564
|
+
|
|
565
|
+
(
|
|
566
|
+
Object.entries(this.thens)
|
|
567
|
+
.reduce((a, [key, then]) => {
|
|
568
|
+
a[key] = async (payload) => {
|
|
569
|
+
const t = await then(payload, testResourceConfiguration).test(
|
|
570
|
+
store,
|
|
571
|
+
testResourceConfiguration
|
|
572
|
+
);
|
|
573
|
+
tester(t);
|
|
574
|
+
};
|
|
575
|
+
return a;
|
|
576
|
+
}, {}
|
|
577
|
+
)
|
|
578
|
+
)
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
await this.afterEach(store, ndx);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
export abstract class TesterantoLevelZero<
|
|
587
|
+
IInput,
|
|
588
|
+
ISubject,
|
|
589
|
+
IStore,
|
|
590
|
+
ISelection,
|
|
591
|
+
SuiteExtensions,
|
|
592
|
+
GivenExtensions,
|
|
593
|
+
WhenExtensions,
|
|
594
|
+
ThenExtensions,
|
|
595
|
+
CheckExtensions,
|
|
596
|
+
IThenShape,
|
|
597
|
+
IFeatureShape,
|
|
598
|
+
> {
|
|
599
|
+
constructorator: IStore;
|
|
600
|
+
|
|
601
|
+
suitesOverrides: Record<
|
|
602
|
+
keyof SuiteExtensions,
|
|
603
|
+
(
|
|
604
|
+
name: string,
|
|
605
|
+
givens: BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>[],
|
|
606
|
+
checks: BaseCheck<ISubject, IStore, ISelection, IThenShape, ITTestShape, IFeatureShape>[]
|
|
607
|
+
) => BaseSuite<IInput, ISubject, IStore, ISelection, IThenShape, ITTestShape, IFeatureShape>
|
|
608
|
+
>;
|
|
609
|
+
|
|
610
|
+
givenOverides: Record<
|
|
611
|
+
keyof GivenExtensions,
|
|
612
|
+
(
|
|
613
|
+
name: string,
|
|
614
|
+
features: (keyof IFeatureShape)[],
|
|
615
|
+
whens: BaseWhen<IStore, ISelection, IThenShape>[],
|
|
616
|
+
thens: BaseThen<ISelection, IStore, IThenShape>[],
|
|
617
|
+
...xtraArgs
|
|
618
|
+
) => BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>
|
|
619
|
+
>;
|
|
620
|
+
|
|
621
|
+
whenOverides: Record<
|
|
622
|
+
keyof WhenExtensions,
|
|
623
|
+
(any) => BaseWhen<IStore, ISelection, IThenShape>
|
|
624
|
+
>;
|
|
625
|
+
|
|
626
|
+
thenOverides: Record<
|
|
627
|
+
keyof ThenExtensions,
|
|
628
|
+
(
|
|
629
|
+
selection: ISelection,
|
|
630
|
+
expectation: any
|
|
631
|
+
) => BaseThen<ISelection, IStore, IThenShape>
|
|
632
|
+
>;
|
|
633
|
+
|
|
634
|
+
checkOverides: Record<
|
|
635
|
+
keyof CheckExtensions,
|
|
636
|
+
(
|
|
637
|
+
feature: string,
|
|
638
|
+
callback: (whens, thens) => any,
|
|
639
|
+
...xtraArgs
|
|
640
|
+
) => BaseCheck<ISubject, IStore, ISelection, IThenShape, ITTestShape, IFeatureShape>
|
|
641
|
+
>;
|
|
642
|
+
|
|
643
|
+
constructor(
|
|
644
|
+
public readonly cc: IStore,
|
|
645
|
+
suitesOverrides: Record<
|
|
646
|
+
keyof SuiteExtensions,
|
|
647
|
+
(
|
|
648
|
+
name: string,
|
|
649
|
+
givens: BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>[],
|
|
650
|
+
checks: BaseCheck<ISubject, IStore, ISelection, IThenShape, ITTestShape, IFeatureShape>[]
|
|
651
|
+
) => BaseSuite<IInput, ISubject, IStore, ISelection, IThenShape, ITTestShape, IFeatureShape>
|
|
652
|
+
>,
|
|
653
|
+
|
|
654
|
+
givenOverides: Record<
|
|
655
|
+
keyof GivenExtensions,
|
|
656
|
+
(
|
|
657
|
+
name: string,
|
|
658
|
+
features: (keyof IFeatureShape)[],
|
|
659
|
+
whens: BaseWhen<IStore, ISelection, IThenShape>[],
|
|
660
|
+
thens: BaseThen<ISelection, IStore, IThenShape>[],
|
|
661
|
+
...xtraArgs
|
|
662
|
+
) => BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>
|
|
663
|
+
>,
|
|
664
|
+
|
|
665
|
+
whenOverides: Record<
|
|
666
|
+
keyof WhenExtensions,
|
|
667
|
+
(c: any) => BaseWhen<IStore, ISelection, IThenShape>
|
|
668
|
+
>,
|
|
669
|
+
|
|
670
|
+
thenOverides: Record<
|
|
671
|
+
keyof ThenExtensions,
|
|
672
|
+
(
|
|
673
|
+
selection: ISelection,
|
|
674
|
+
expectation: any
|
|
675
|
+
) => BaseThen<ISelection, IStore, IThenShape>
|
|
676
|
+
>,
|
|
677
|
+
|
|
678
|
+
checkOverides: Record<
|
|
679
|
+
keyof CheckExtensions,
|
|
680
|
+
(
|
|
681
|
+
feature: string,
|
|
682
|
+
callback: (whens, thens) => any,
|
|
683
|
+
...xtraArgs
|
|
684
|
+
) => BaseCheck<ISubject, IStore, ISelection, IThenShape, ITTestShape, IFeatureShape>
|
|
685
|
+
>
|
|
686
|
+
) {
|
|
687
|
+
this.constructorator = cc;
|
|
688
|
+
this.suitesOverrides = suitesOverrides;
|
|
689
|
+
this.givenOverides = givenOverides;
|
|
690
|
+
this.whenOverides = whenOverides;
|
|
691
|
+
this.thenOverides = thenOverides;
|
|
692
|
+
this.checkOverides = checkOverides;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
Suites() {
|
|
696
|
+
return this.suitesOverrides;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
Given(): Record<
|
|
700
|
+
keyof GivenExtensions,
|
|
701
|
+
(
|
|
702
|
+
name: string,
|
|
703
|
+
features: (keyof IFeatureShape)[],
|
|
704
|
+
whens: BaseWhen<IStore, ISelection, IThenShape>[],
|
|
705
|
+
thens: BaseThen<ISelection, IStore, IThenShape>[],
|
|
706
|
+
...xtraArgs
|
|
707
|
+
) => BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>
|
|
708
|
+
> {
|
|
709
|
+
return this.givenOverides;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
When(): Record<
|
|
713
|
+
keyof WhenExtensions,
|
|
714
|
+
(arg0: IStore, ...arg1: any) => BaseWhen<IStore, ISelection, IThenShape>
|
|
715
|
+
> {
|
|
716
|
+
return this.whenOverides;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
Then(): Record<
|
|
720
|
+
keyof ThenExtensions,
|
|
721
|
+
(
|
|
722
|
+
selection: ISelection,
|
|
723
|
+
expectation: any
|
|
724
|
+
) => BaseThen<ISelection, IStore, IThenShape>
|
|
725
|
+
> {
|
|
726
|
+
return this.thenOverides;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
Check(): Record<
|
|
730
|
+
keyof CheckExtensions,
|
|
731
|
+
(
|
|
732
|
+
feature: string,
|
|
733
|
+
callback: (whens, thens) => any,
|
|
734
|
+
whens,
|
|
735
|
+
thens
|
|
736
|
+
) => BaseCheck<ISubject, IStore, ISelection, IThenShape, ITTestShape, IFeatureShape>
|
|
737
|
+
> {
|
|
738
|
+
return this.checkOverides;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
export abstract class TesterantoLevelOne<
|
|
743
|
+
ITestShape extends ITTestShape,
|
|
744
|
+
IInitialState,
|
|
745
|
+
ISelection,
|
|
746
|
+
IStore,
|
|
747
|
+
ISubject,
|
|
748
|
+
IWhenShape,
|
|
749
|
+
IThenShape,
|
|
750
|
+
IInput,
|
|
751
|
+
IFeatureShape,
|
|
752
|
+
> {
|
|
753
|
+
constructor(
|
|
754
|
+
testImplementation: ITestImplementation<
|
|
755
|
+
IInitialState,
|
|
756
|
+
ISelection,
|
|
757
|
+
IWhenShape,
|
|
758
|
+
IThenShape,
|
|
759
|
+
ITestShape
|
|
760
|
+
>,
|
|
761
|
+
|
|
762
|
+
testSpecification: (
|
|
763
|
+
Suite: {
|
|
764
|
+
[K in keyof ITestShape["suites"]]: (
|
|
765
|
+
feature: string,
|
|
766
|
+
givens: BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>[],
|
|
767
|
+
checks: BaseCheck<ISubject, IStore, ISelection, IThenShape, ITestShape, IFeatureShape>[]
|
|
768
|
+
) => BaseSuite<IInput, ISubject, IStore, ISelection, IThenShape, ITestShape, IFeatureShape>;
|
|
769
|
+
},
|
|
770
|
+
Given: {
|
|
771
|
+
[K in keyof ITestShape["givens"]]: (
|
|
772
|
+
name: string,
|
|
773
|
+
features: (keyof IFeatureShape)[],
|
|
774
|
+
whens: BaseWhen<IStore, ISelection, IThenShape>[],
|
|
775
|
+
thens: BaseThen<ISelection, IStore, IThenShape>[],
|
|
776
|
+
...a: ITestShape["givens"][K]
|
|
777
|
+
) => BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>;
|
|
778
|
+
},
|
|
779
|
+
When: {
|
|
780
|
+
[K in keyof ITestShape["whens"]]: (
|
|
781
|
+
...a: ITestShape["whens"][K]
|
|
782
|
+
) => BaseWhen<IStore, ISelection, IThenShape>;
|
|
783
|
+
},
|
|
784
|
+
Then: {
|
|
785
|
+
[K in keyof ITestShape["thens"]]: (
|
|
786
|
+
...a: ITestShape["thens"][K]
|
|
787
|
+
) => BaseThen<ISelection, IStore, IThenShape>;
|
|
788
|
+
},
|
|
789
|
+
Check: {
|
|
790
|
+
[K in keyof ITestShape["checks"]]: (
|
|
791
|
+
name: string,
|
|
792
|
+
features: (keyof IFeatureShape)[],
|
|
793
|
+
cbz: (...any) => Promise<void>
|
|
794
|
+
) => any;
|
|
795
|
+
}
|
|
796
|
+
) => BaseSuite<IInput, ISubject, IStore, ISelection, IThenShape, ITestShape, IFeatureShape>[],
|
|
797
|
+
|
|
798
|
+
input: IInput,
|
|
799
|
+
|
|
800
|
+
suiteKlasser: (
|
|
801
|
+
name: string,
|
|
802
|
+
givens: BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>[],
|
|
803
|
+
checks: BaseCheck<ISubject, IStore, ISelection, IThenShape, ITestShape, IFeatureShape>[]
|
|
804
|
+
) =>
|
|
805
|
+
BaseSuite<IInput, ISubject, IStore, ISelection, IThenShape, ITestShape, IFeatureShape>,
|
|
806
|
+
givenKlasser: (n, f, w, t, z?) =>
|
|
807
|
+
BaseGiven<ISubject, IStore, ISelection, IThenShape, IFeatureShape>,
|
|
808
|
+
whenKlasser: (s, o) =>
|
|
809
|
+
BaseWhen<IStore, ISelection, IThenShape>,
|
|
810
|
+
thenKlasser: (s, o) =>
|
|
811
|
+
BaseThen<IStore, ISelection, IThenShape>,
|
|
812
|
+
checkKlasser: (n, f, cb, w, t) =>
|
|
813
|
+
BaseCheck<ISubject, IStore, ISelection, IThenShape, ITestShape, IFeatureShape>,
|
|
814
|
+
|
|
815
|
+
testResource
|
|
816
|
+
|
|
817
|
+
) {
|
|
818
|
+
const classySuites = Object.entries(testImplementation.Suites)
|
|
819
|
+
.reduce((a, [key]) => {
|
|
820
|
+
a[key] = (somestring, givens, checks) => {
|
|
821
|
+
return new suiteKlasser.prototype.constructor(somestring, givens, checks);
|
|
822
|
+
};
|
|
823
|
+
return a;
|
|
824
|
+
}, {}
|
|
825
|
+
);
|
|
826
|
+
|
|
827
|
+
const classyGivens = Object.entries(testImplementation.Givens)
|
|
828
|
+
.reduce((a, [key, z]) => {
|
|
829
|
+
a[key] = (features, whens, thens, ...xtrasW) => {
|
|
830
|
+
return new givenKlasser.prototype.constructor(z.name, features, whens, thens, z(...xtrasW))
|
|
831
|
+
};
|
|
832
|
+
return a;
|
|
833
|
+
}, {}
|
|
834
|
+
);
|
|
835
|
+
|
|
836
|
+
const classyWhens = Object.entries(testImplementation.Whens)
|
|
837
|
+
.reduce((a, [key, whEn]) => {
|
|
838
|
+
a[key] = (payload?: any) => {
|
|
839
|
+
return new whenKlasser.prototype.constructor(
|
|
840
|
+
`${whEn.name}: ${payload && payload.toString()}`,
|
|
841
|
+
whEn(payload)
|
|
842
|
+
)
|
|
843
|
+
};
|
|
844
|
+
return a;
|
|
845
|
+
}, {}
|
|
846
|
+
);
|
|
847
|
+
|
|
848
|
+
const classyThens = Object.entries(testImplementation.Thens)
|
|
849
|
+
.reduce((a, [key, thEn]) => {
|
|
850
|
+
a[key] = (expected: any, x) => {
|
|
851
|
+
return new thenKlasser.prototype.constructor(
|
|
852
|
+
`${thEn.name}: ${expected && expected.toString()}`,
|
|
853
|
+
thEn(expected)
|
|
854
|
+
);
|
|
855
|
+
};
|
|
856
|
+
return a;
|
|
857
|
+
}, {}
|
|
858
|
+
);
|
|
859
|
+
|
|
860
|
+
const classyChecks = Object.entries(testImplementation.Checks)
|
|
861
|
+
.reduce((a, [key, z]) => {
|
|
862
|
+
a[key] = (somestring, features, callback) => {
|
|
863
|
+
return new checkKlasser.prototype.constructor(somestring, features, callback, classyWhens, classyThens);
|
|
864
|
+
};
|
|
865
|
+
return a;
|
|
866
|
+
}, {}
|
|
867
|
+
);
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
const classyTesteranto = new (class <
|
|
871
|
+
IInput,
|
|
872
|
+
ISubject,
|
|
873
|
+
IStore,
|
|
874
|
+
ISelection,
|
|
875
|
+
SuiteExtensions,
|
|
876
|
+
GivenExtensions,
|
|
877
|
+
WhenExtensions,
|
|
878
|
+
ThenExtensions,
|
|
879
|
+
ICheckExtensions,
|
|
880
|
+
IThenShape,
|
|
881
|
+
IFeatureShape,
|
|
882
|
+
> extends TesterantoLevelZero<
|
|
883
|
+
IInput,
|
|
884
|
+
ISubject,
|
|
885
|
+
IStore,
|
|
886
|
+
ISelection,
|
|
887
|
+
SuiteExtensions,
|
|
888
|
+
GivenExtensions,
|
|
889
|
+
WhenExtensions,
|
|
890
|
+
ThenExtensions,
|
|
891
|
+
ICheckExtensions,
|
|
892
|
+
IThenShape,
|
|
893
|
+
IFeatureShape
|
|
894
|
+
> { })(
|
|
895
|
+
input,
|
|
896
|
+
classySuites,
|
|
897
|
+
classyGivens,
|
|
898
|
+
classyWhens,
|
|
899
|
+
classyThens,
|
|
900
|
+
classyChecks
|
|
901
|
+
);
|
|
902
|
+
|
|
903
|
+
const suites = testSpecification(
|
|
904
|
+
/* @ts-ignore:next-line */
|
|
905
|
+
classyTesteranto.Suites(),
|
|
906
|
+
classyTesteranto.Given(),
|
|
907
|
+
classyTesteranto.When(),
|
|
908
|
+
classyTesteranto.Then(),
|
|
909
|
+
classyTesteranto.Check()
|
|
910
|
+
);
|
|
911
|
+
|
|
912
|
+
/* @ts-ignore:next-line */
|
|
913
|
+
const toReturn: ITestJob[] = suites.map((suite) => {
|
|
914
|
+
return {
|
|
915
|
+
test: suite,
|
|
916
|
+
testResource,
|
|
917
|
+
|
|
918
|
+
toObj: () => {
|
|
919
|
+
return suite.toObj()
|
|
920
|
+
},
|
|
921
|
+
|
|
922
|
+
runner: async (allocatedPorts: number[]) => {
|
|
923
|
+
return suite.run(input, { ports: allocatedPorts });
|
|
924
|
+
},
|
|
925
|
+
|
|
926
|
+
};
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
return toReturn;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
export const Testeranto = async <
|
|
934
|
+
TestShape extends ITTestShape,
|
|
935
|
+
Input,
|
|
936
|
+
Subject,
|
|
937
|
+
Store,
|
|
938
|
+
Selection,
|
|
939
|
+
WhenShape,
|
|
940
|
+
ThenShape,
|
|
941
|
+
InitialStateShape,
|
|
942
|
+
IFeatureShape
|
|
943
|
+
>(
|
|
944
|
+
input: Input,
|
|
945
|
+
testSpecification: ITestSpecification<TestShape, IFeatureShape>,
|
|
946
|
+
testImplementation,
|
|
947
|
+
// testImplementation: ITestImplementation<
|
|
948
|
+
// InitialStateShape,
|
|
949
|
+
// Selection,
|
|
950
|
+
// WhenShape,
|
|
951
|
+
// ThenShape,
|
|
952
|
+
// TestShape
|
|
953
|
+
// >,
|
|
954
|
+
testResource: ITTestResourceRequirement,
|
|
955
|
+
|
|
956
|
+
testInterface: {
|
|
957
|
+
actionHandler?: (b: (...any) => any) => any,
|
|
958
|
+
afterEach?: (store: Store, ndx: number, cb) => unknown,
|
|
959
|
+
andWhen: (store: Store, actioner, testResource: ITTestResource) => Promise<Selection>,
|
|
960
|
+
assertioner?: (t: ThenShape) => any,
|
|
961
|
+
beforeAll?: (input: Input) => Promise<Subject>,
|
|
962
|
+
beforeEach?: (subject: Subject, initialValues, testResource: ITTestResource) => Promise<Store>,
|
|
963
|
+
butThen?: (store: Store, callback, testResource: ITTestResource) => Promise<Selection>,
|
|
964
|
+
},
|
|
965
|
+
|
|
966
|
+
) => {
|
|
967
|
+
|
|
968
|
+
const butThen = testInterface.butThen || (async (a) => a as any);
|
|
969
|
+
const { andWhen } = testInterface;
|
|
970
|
+
const actionHandler = testInterface.actionHandler || function (b: (...any: any[]) => any) {
|
|
971
|
+
return b;
|
|
972
|
+
};
|
|
973
|
+
const assertioner = testInterface.assertioner || (async (t) => t as any);
|
|
974
|
+
const beforeAll = testInterface.beforeAll || (async (input) => input as any);
|
|
975
|
+
const beforeEach = testInterface.beforeEach || async function (subject: Input, initialValues: any, testResource: any) {
|
|
976
|
+
return subject as any;
|
|
977
|
+
}
|
|
978
|
+
const afterEach = testInterface.afterEach || (async (s) => s);
|
|
979
|
+
|
|
980
|
+
class MrT extends TesterantoLevelOne<
|
|
981
|
+
TestShape,
|
|
982
|
+
InitialStateShape,
|
|
983
|
+
Selection,
|
|
984
|
+
Store,
|
|
985
|
+
Subject,
|
|
986
|
+
WhenShape,
|
|
987
|
+
ThenShape,
|
|
988
|
+
Input,
|
|
989
|
+
IFeatureShape
|
|
990
|
+
> {
|
|
991
|
+
constructor() {
|
|
992
|
+
super(
|
|
993
|
+
testImplementation,
|
|
994
|
+
/* @ts-ignore:next-line */
|
|
995
|
+
testSpecification,
|
|
996
|
+
input,
|
|
997
|
+
(class extends BaseSuite<Input, Subject, Store, Selection, ThenShape, TestShape, IFeatureShape> {
|
|
998
|
+
async setup(s: Input): Promise<Subject> {
|
|
999
|
+
return beforeAll(s);
|
|
1000
|
+
}
|
|
1001
|
+
test(t: ThenShape): unknown {
|
|
1002
|
+
return assertioner(t);
|
|
1003
|
+
}
|
|
1004
|
+
}),
|
|
1005
|
+
|
|
1006
|
+
class Given extends BaseGiven<Subject, Store, Selection, ThenShape, IFeatureShape> {
|
|
1007
|
+
initialValues: any;
|
|
1008
|
+
constructor(
|
|
1009
|
+
name: string,
|
|
1010
|
+
features: (keyof IFeatureShape)[],
|
|
1011
|
+
whens: BaseWhen<Store, Selection, ThenShape>[],
|
|
1012
|
+
thens: BaseThen<Selection, Store, ThenShape>[],
|
|
1013
|
+
initialValues: any
|
|
1014
|
+
) {
|
|
1015
|
+
super(name, features, whens, thens);
|
|
1016
|
+
this.initialValues = initialValues;
|
|
1017
|
+
}
|
|
1018
|
+
async givenThat(subject, testResource) {
|
|
1019
|
+
return beforeEach(subject, this.initialValues, testResource);
|
|
1020
|
+
}
|
|
1021
|
+
afterEach(store: Store, ndx: number, cb): Promise<unknown> {
|
|
1022
|
+
return new Promise((res) => res(afterEach(store, ndx, cb)))
|
|
1023
|
+
}
|
|
1024
|
+
},
|
|
1025
|
+
|
|
1026
|
+
class When extends BaseWhen<Store, Selection, WhenShape> {
|
|
1027
|
+
payload?: any;
|
|
1028
|
+
|
|
1029
|
+
constructor(name: string, actioner: (...any) => any, payload?: any) {
|
|
1030
|
+
super(name, (store) => {
|
|
1031
|
+
return actionHandler(actioner)
|
|
1032
|
+
});
|
|
1033
|
+
this.payload = payload;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
async andWhen(store, actioner, testResource) {
|
|
1037
|
+
return await andWhen(store, actioner, testResource);
|
|
1038
|
+
}
|
|
1039
|
+
},
|
|
1040
|
+
|
|
1041
|
+
class Then extends BaseThen<Selection, Store, ThenShape> {
|
|
1042
|
+
constructor(
|
|
1043
|
+
name: string,
|
|
1044
|
+
callback: (val: Selection) => ThenShape
|
|
1045
|
+
) {
|
|
1046
|
+
super(name, callback);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
async butThen(store: any, testResourceConfiguration?: any): Promise<Selection> {
|
|
1050
|
+
return await butThen(store, this.thenCB, testResourceConfiguration)
|
|
1051
|
+
}
|
|
1052
|
+
},
|
|
1053
|
+
|
|
1054
|
+
class Check extends BaseCheck<Subject, Store, Selection, ThenShape, TestShape, IFeatureShape> {
|
|
1055
|
+
initialValues: any;
|
|
1056
|
+
|
|
1057
|
+
constructor(
|
|
1058
|
+
name: string,
|
|
1059
|
+
features: (keyof IFeatureShape)[],
|
|
1060
|
+
checkCallback: (a, b) => any,
|
|
1061
|
+
whens,
|
|
1062
|
+
thens,
|
|
1063
|
+
initialValues: any,
|
|
1064
|
+
) {
|
|
1065
|
+
super(name, features, checkCallback, whens, thens);
|
|
1066
|
+
this.initialValues = initialValues;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
async checkThat(subject, testResource) {
|
|
1070
|
+
return beforeEach(subject, this.initialValues, testResource);
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
afterEach(store: Store, ndx: number, cb): Promise<unknown> {
|
|
1074
|
+
return new Promise((res) => res(afterEach(store, ndx, cb)))
|
|
1075
|
+
}
|
|
1076
|
+
},
|
|
1077
|
+
testResource
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
const mrt = new MrT();
|
|
1083
|
+
|
|
1084
|
+
console.log("requesting test resources from mothership...", testResource);
|
|
1085
|
+
/* @ts-ignore:next-line */
|
|
1086
|
+
process.send({
|
|
1087
|
+
type: 'testeranto:hola',
|
|
1088
|
+
data: {
|
|
1089
|
+
testResource
|
|
1090
|
+
}
|
|
1091
|
+
});
|
|
1092
|
+
|
|
1093
|
+
console.log("awaiting test resources from mothership...");
|
|
1094
|
+
process.on('message', async function (packet: { data: { go?: boolean, goWithTestResources?: string[] } }) {
|
|
1095
|
+
await mrt[0].runner(packet.data.goWithTestResources);
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
/* @ts-ignore:next-line */
|
|
1099
|
+
process.send({
|
|
1100
|
+
type: 'testeranto:adios',
|
|
1101
|
+
data: {
|
|
1102
|
+
testResource: mrt[0].test.testResourceConfiguration.ports,
|
|
1103
|
+
results: mrt[0].toObj()
|
|
1104
|
+
}
|
|
1105
|
+
}, (err) => {
|
|
1106
|
+
if (!err) { console.log(`✅`) }
|
|
1107
|
+
else { console.error(`❗️`, err) }
|
|
1108
|
+
process.exit(0); // :-)
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1114
|
+
process.on('SIGINT', function () {
|
|
1115
|
+
|
|
1116
|
+
console.log("SIGINT caught. Releasing test resources back to mothership...", mrt[0].test.testResourceConfiguration);
|
|
1117
|
+
console.log("`❗️`");
|
|
1118
|
+
/* @ts-ignore:next-line */
|
|
1119
|
+
process.send({
|
|
1120
|
+
type: 'testeranto:adios',
|
|
1121
|
+
data: {
|
|
1122
|
+
testResource: mrt[0].test.testResourceConfiguration?.ports || []
|
|
1123
|
+
}
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1126
|
+
process.exit(0); // :-)
|
|
1127
|
+
});
|
|
1128
|
+
|
|
1129
|
+
};
|