@git.zone/tstest 3.1.1 → 3.1.4
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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_tapbundle/webhelpers.js +12 -2
- package/npmextra.json +11 -5
- package/package.json +13 -12
- package/readme.md +19 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/dist_ts/tstest.classes.tap.parser.old.d.ts +0 -50
- package/dist_ts/tstest.classes.tap.parser.old.js +0 -332
- package/dist_ts_tapbundle/tapbundle.protocols.d.ts +0 -88
- package/dist_ts_tapbundle/tapbundle.protocols.js +0 -168
- package/dist_ts_tapbundle/ts_tapbundle/00_commitinfo_data.d.ts +0 -8
- package/dist_ts_tapbundle/ts_tapbundle/00_commitinfo_data.js +0 -9
- package/dist_ts_tapbundle/ts_tapbundle/index.d.ts +0 -6
- package/dist_ts_tapbundle/ts_tapbundle/index.js +0 -7
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.pretask.d.ts +0 -10
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.pretask.js +0 -13
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.tap.d.ts +0 -104
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.tap.js +0 -401
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.taptest.d.ts +0 -38
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.taptest.js +0 -110
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.taptools.d.ts +0 -109
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.taptools.js +0 -241
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.tapwrap.d.ts +0 -8
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.classes.tapwrap.js +0 -7
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.plugins.d.ts +0 -8
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.plugins.js +0 -10
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.tapcreator.d.ts +0 -3
- package/dist_ts_tapbundle/ts_tapbundle/tapbundle.tapcreator.js +0 -5
- package/dist_ts_tapbundle/ts_tapbundle/webhelpers.d.ts +0 -7
- package/dist_ts_tapbundle/ts_tapbundle/webhelpers.js +0 -35
- package/dist_ts_tapbundle/ts_tapbundle_node/classes.pathinject.d.ts +0 -5
- package/dist_ts_tapbundle/ts_tapbundle_node/classes.pathinject.js +0 -13
- package/dist_ts_tapbundle/ts_tapbundle_node/plugins.d.ts +0 -11
- package/dist_ts_tapbundle/ts_tapbundle_node/plugins.js +0 -14
|
@@ -1,401 +0,0 @@
|
|
|
1
|
-
import * as plugins from './tapbundle.plugins.js';
|
|
2
|
-
import { PreTask } from './tapbundle.classes.pretask.js';
|
|
3
|
-
import { TapTest } from './tapbundle.classes.taptest.js';
|
|
4
|
-
class TestBuilder {
|
|
5
|
-
constructor(tap) {
|
|
6
|
-
this._tags = [];
|
|
7
|
-
this._priority = 'medium';
|
|
8
|
-
this._tap = tap;
|
|
9
|
-
}
|
|
10
|
-
tags(...tags) {
|
|
11
|
-
this._tags = tags;
|
|
12
|
-
return this;
|
|
13
|
-
}
|
|
14
|
-
priority(level) {
|
|
15
|
-
this._priority = level;
|
|
16
|
-
return this;
|
|
17
|
-
}
|
|
18
|
-
retry(count) {
|
|
19
|
-
this._retryCount = count;
|
|
20
|
-
return this;
|
|
21
|
-
}
|
|
22
|
-
timeout(ms) {
|
|
23
|
-
this._timeoutMs = ms;
|
|
24
|
-
return this;
|
|
25
|
-
}
|
|
26
|
-
test(description, testFunction) {
|
|
27
|
-
const test = this._tap.test(description, testFunction, 'normal');
|
|
28
|
-
// Apply settings to the test
|
|
29
|
-
if (this._tags.length > 0) {
|
|
30
|
-
test.tags = this._tags;
|
|
31
|
-
}
|
|
32
|
-
test.priority = this._priority;
|
|
33
|
-
if (this._retryCount !== undefined) {
|
|
34
|
-
test.tapTools.retry(this._retryCount);
|
|
35
|
-
}
|
|
36
|
-
if (this._timeoutMs !== undefined) {
|
|
37
|
-
test.timeoutMs = this._timeoutMs;
|
|
38
|
-
}
|
|
39
|
-
return test;
|
|
40
|
-
}
|
|
41
|
-
testOnly(description, testFunction) {
|
|
42
|
-
const test = this._tap.test(description, testFunction, 'only');
|
|
43
|
-
// Apply settings to the test
|
|
44
|
-
if (this._tags.length > 0) {
|
|
45
|
-
test.tags = this._tags;
|
|
46
|
-
}
|
|
47
|
-
test.priority = this._priority;
|
|
48
|
-
if (this._retryCount !== undefined) {
|
|
49
|
-
test.tapTools.retry(this._retryCount);
|
|
50
|
-
}
|
|
51
|
-
if (this._timeoutMs !== undefined) {
|
|
52
|
-
test.timeoutMs = this._timeoutMs;
|
|
53
|
-
}
|
|
54
|
-
return test;
|
|
55
|
-
}
|
|
56
|
-
testSkip(description, testFunction) {
|
|
57
|
-
const test = this._tap.test(description, testFunction, 'skip');
|
|
58
|
-
// Apply settings to the test
|
|
59
|
-
if (this._tags.length > 0) {
|
|
60
|
-
test.tags = this._tags;
|
|
61
|
-
}
|
|
62
|
-
test.priority = this._priority;
|
|
63
|
-
if (this._retryCount !== undefined) {
|
|
64
|
-
test.tapTools.retry(this._retryCount);
|
|
65
|
-
}
|
|
66
|
-
if (this._timeoutMs !== undefined) {
|
|
67
|
-
test.timeoutMs = this._timeoutMs;
|
|
68
|
-
}
|
|
69
|
-
return test;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
export class Tap {
|
|
73
|
-
constructor() {
|
|
74
|
-
this._skipCount = 0;
|
|
75
|
-
this._filterTags = [];
|
|
76
|
-
/**
|
|
77
|
-
* skips a test
|
|
78
|
-
* tests marked with tap.skip.test() are never executed
|
|
79
|
-
*/
|
|
80
|
-
this.skip = {
|
|
81
|
-
test: (descriptionArg, functionArg) => {
|
|
82
|
-
console.log(`skipped test: ${descriptionArg}`);
|
|
83
|
-
this._skipCount++;
|
|
84
|
-
},
|
|
85
|
-
testParallel: (descriptionArg, functionArg) => {
|
|
86
|
-
console.log(`skipped test: ${descriptionArg}`);
|
|
87
|
-
this._skipCount++;
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
/**
|
|
91
|
-
* only executes tests marked as ONLY
|
|
92
|
-
*/
|
|
93
|
-
this.only = {
|
|
94
|
-
test: (descriptionArg, testFunctionArg) => {
|
|
95
|
-
this.test(descriptionArg, testFunctionArg, 'only');
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
this._tapPreTasks = [];
|
|
99
|
-
this._tapTests = [];
|
|
100
|
-
this._tapTestsOnly = [];
|
|
101
|
-
this._currentSuite = null;
|
|
102
|
-
this._rootSuites = [];
|
|
103
|
-
// Get filter tags from environment
|
|
104
|
-
if (process.env.TSTEST_FILTER_TAGS) {
|
|
105
|
-
this._filterTags = process.env.TSTEST_FILTER_TAGS.split(',');
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// Fluent test builder
|
|
109
|
-
tags(...tags) {
|
|
110
|
-
const builder = new TestBuilder(this);
|
|
111
|
-
return builder.tags(...tags);
|
|
112
|
-
}
|
|
113
|
-
priority(level) {
|
|
114
|
-
const builder = new TestBuilder(this);
|
|
115
|
-
return builder.priority(level);
|
|
116
|
-
}
|
|
117
|
-
retry(count) {
|
|
118
|
-
const builder = new TestBuilder(this);
|
|
119
|
-
return builder.retry(count);
|
|
120
|
-
}
|
|
121
|
-
timeout(ms) {
|
|
122
|
-
const builder = new TestBuilder(this);
|
|
123
|
-
return builder.timeout(ms);
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Normal test function, will run one by one
|
|
127
|
-
* @param testDescription - A description of what the test does
|
|
128
|
-
* @param testFunction - A Function that returns a Promise and resolves or rejects
|
|
129
|
-
*/
|
|
130
|
-
test(testDescription, testFunction, modeArg = 'normal') {
|
|
131
|
-
const localTest = new TapTest({
|
|
132
|
-
description: testDescription,
|
|
133
|
-
testFunction,
|
|
134
|
-
parallel: false,
|
|
135
|
-
});
|
|
136
|
-
// No options applied here - use the fluent builder syntax instead
|
|
137
|
-
// If we're in a suite, add test to the suite
|
|
138
|
-
if (this._currentSuite) {
|
|
139
|
-
this._currentSuite.tests.push(localTest);
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
// Otherwise add to global test list
|
|
143
|
-
if (modeArg === 'normal') {
|
|
144
|
-
this._tapTests.push(localTest);
|
|
145
|
-
}
|
|
146
|
-
else if (modeArg === 'only') {
|
|
147
|
-
this._tapTestsOnly.push(localTest);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return localTest;
|
|
151
|
-
}
|
|
152
|
-
preTask(descriptionArg, functionArg) {
|
|
153
|
-
this._tapPreTasks.push(new PreTask(descriptionArg, functionArg));
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* A parallel test that will not be waited for before the next starts.
|
|
157
|
-
* @param testDescription - A description of what the test does
|
|
158
|
-
* @param testFunction - A Function that returns a Promise and resolves or rejects
|
|
159
|
-
*/
|
|
160
|
-
testParallel(testDescription, testFunction) {
|
|
161
|
-
const localTest = new TapTest({
|
|
162
|
-
description: testDescription,
|
|
163
|
-
testFunction,
|
|
164
|
-
parallel: true,
|
|
165
|
-
});
|
|
166
|
-
if (this._currentSuite) {
|
|
167
|
-
this._currentSuite.tests.push(localTest);
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
this._tapTests.push(localTest);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Create a test suite for grouping related tests
|
|
175
|
-
*/
|
|
176
|
-
describe(description, suiteFunction) {
|
|
177
|
-
const suite = {
|
|
178
|
-
description,
|
|
179
|
-
tests: [],
|
|
180
|
-
children: [],
|
|
181
|
-
parent: this._currentSuite,
|
|
182
|
-
};
|
|
183
|
-
// Add to parent or root
|
|
184
|
-
if (this._currentSuite) {
|
|
185
|
-
this._currentSuite.children.push(suite);
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
this._rootSuites.push(suite);
|
|
189
|
-
}
|
|
190
|
-
// Execute suite function in context
|
|
191
|
-
const previousSuite = this._currentSuite;
|
|
192
|
-
this._currentSuite = suite;
|
|
193
|
-
try {
|
|
194
|
-
suiteFunction();
|
|
195
|
-
}
|
|
196
|
-
finally {
|
|
197
|
-
this._currentSuite = previousSuite;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Set up a function to run before each test in the current suite
|
|
202
|
-
*/
|
|
203
|
-
beforeEach(setupFunction) {
|
|
204
|
-
if (this._currentSuite) {
|
|
205
|
-
this._currentSuite.beforeEach = setupFunction;
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
throw new Error('beforeEach can only be used inside a describe block');
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Set up a function to run after each test in the current suite
|
|
213
|
-
*/
|
|
214
|
-
afterEach(teardownFunction) {
|
|
215
|
-
if (this._currentSuite) {
|
|
216
|
-
this._currentSuite.afterEach = teardownFunction;
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
throw new Error('afterEach can only be used inside a describe block');
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* collect all tests from suites
|
|
224
|
-
*/
|
|
225
|
-
_collectTests(suite, tests = []) {
|
|
226
|
-
tests.push(...suite.tests);
|
|
227
|
-
for (const childSuite of suite.children) {
|
|
228
|
-
this._collectTests(childSuite, tests);
|
|
229
|
-
}
|
|
230
|
-
return tests;
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* starts the test evaluation
|
|
234
|
-
*/
|
|
235
|
-
async start(optionsArg) {
|
|
236
|
-
// lets set the tapbundle promise
|
|
237
|
-
const smartenvInstance = new plugins.smartenv.Smartenv();
|
|
238
|
-
smartenvInstance.isBrowser
|
|
239
|
-
? (globalThis.tapbundleDeferred = plugins.smartpromise.defer())
|
|
240
|
-
: null;
|
|
241
|
-
// Initialize path helpers for Node.js environment
|
|
242
|
-
if (!smartenvInstance.isBrowser) {
|
|
243
|
-
try {
|
|
244
|
-
const { initializePathHelpers } = await import('../ts_tapbundle_node/classes.pathinject.js');
|
|
245
|
-
initializePathHelpers();
|
|
246
|
-
}
|
|
247
|
-
catch (error) {
|
|
248
|
-
// tapbundle_node not available in browser environment
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
// lets continue with running the tests
|
|
252
|
-
const promiseArray = [];
|
|
253
|
-
// Collect all tests including those in suites
|
|
254
|
-
let allTests = [...this._tapTests];
|
|
255
|
-
for (const suite of this._rootSuites) {
|
|
256
|
-
this._collectTests(suite, allTests);
|
|
257
|
-
}
|
|
258
|
-
// safeguard against empty test array
|
|
259
|
-
if (allTests.length === 0 && this._tapTestsOnly.length === 0) {
|
|
260
|
-
console.log('no tests specified. Ending here!');
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
// determine which tests to run
|
|
264
|
-
let concerningTests;
|
|
265
|
-
if (this._tapTestsOnly.length > 0) {
|
|
266
|
-
concerningTests = this._tapTestsOnly;
|
|
267
|
-
}
|
|
268
|
-
else {
|
|
269
|
-
concerningTests = allTests;
|
|
270
|
-
}
|
|
271
|
-
// Filter tests by tags if specified
|
|
272
|
-
if (this._filterTags.length > 0) {
|
|
273
|
-
concerningTests = concerningTests.filter(test => {
|
|
274
|
-
// Skip tests without tags when filtering is active
|
|
275
|
-
if (!test.tags || test.tags.length === 0) {
|
|
276
|
-
return false;
|
|
277
|
-
}
|
|
278
|
-
// Check if test has any of the filter tags
|
|
279
|
-
return test.tags.some(tag => this._filterTags.includes(tag));
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
// lets run the pretasks
|
|
283
|
-
for (const preTask of this._tapPreTasks) {
|
|
284
|
-
await preTask.run();
|
|
285
|
-
}
|
|
286
|
-
// Count actual tests that will be run
|
|
287
|
-
console.log(`1..${concerningTests.length}`);
|
|
288
|
-
// Run tests from suites with lifecycle hooks
|
|
289
|
-
let testKey = 0;
|
|
290
|
-
// Run all concerning tests (filtered by tags if applicable)
|
|
291
|
-
for (const currentTest of concerningTests) {
|
|
292
|
-
const testPromise = currentTest.run(testKey++);
|
|
293
|
-
if (currentTest.parallel) {
|
|
294
|
-
promiseArray.push(testPromise);
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
await testPromise;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
await Promise.all(promiseArray);
|
|
301
|
-
// when tests have been run and all promises are fullfilled
|
|
302
|
-
const failReasons = [];
|
|
303
|
-
const executionNotes = [];
|
|
304
|
-
// collect failed tests
|
|
305
|
-
for (const tapTest of concerningTests) {
|
|
306
|
-
if (tapTest.status !== 'success' && tapTest.status !== 'skipped') {
|
|
307
|
-
failReasons.push(`Test ${tapTest.testKey + 1} failed with status ${tapTest.status}:\n` +
|
|
308
|
-
`|| ${tapTest.description}\n` +
|
|
309
|
-
`|| for more information please take a look the logs above`);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
// render fail Reasons
|
|
313
|
-
for (const failReason of failReasons) {
|
|
314
|
-
console.log(failReason);
|
|
315
|
-
}
|
|
316
|
-
if (optionsArg && optionsArg.throwOnError && failReasons.length > 0) {
|
|
317
|
-
if (!smartenvInstance.isBrowser)
|
|
318
|
-
process.exit(1);
|
|
319
|
-
}
|
|
320
|
-
if (smartenvInstance.isBrowser) {
|
|
321
|
-
globalThis.tapbundleDeferred.resolve();
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Run tests in a suite with lifecycle hooks
|
|
326
|
-
*/
|
|
327
|
-
async _runSuite(parentSuite, suites, promiseArray, context) {
|
|
328
|
-
for (const suite of suites) {
|
|
329
|
-
// Run beforeEach from parent suites
|
|
330
|
-
const beforeEachFunctions = [];
|
|
331
|
-
let currentSuite = suite;
|
|
332
|
-
while (currentSuite) {
|
|
333
|
-
if (currentSuite.beforeEach) {
|
|
334
|
-
beforeEachFunctions.unshift(currentSuite.beforeEach);
|
|
335
|
-
}
|
|
336
|
-
currentSuite = currentSuite.parent || null;
|
|
337
|
-
}
|
|
338
|
-
// Run tests in this suite
|
|
339
|
-
for (const test of suite.tests) {
|
|
340
|
-
// Create wrapper test function that includes lifecycle hooks
|
|
341
|
-
const originalFunction = test.testFunction;
|
|
342
|
-
test.testFunction = async (tapTools) => {
|
|
343
|
-
// Run all beforeEach hooks
|
|
344
|
-
for (const beforeEach of beforeEachFunctions) {
|
|
345
|
-
await beforeEach(tapTools);
|
|
346
|
-
}
|
|
347
|
-
// Run the actual test
|
|
348
|
-
const result = await originalFunction(tapTools);
|
|
349
|
-
// Run afterEach hooks in reverse order
|
|
350
|
-
const afterEachFunctions = [];
|
|
351
|
-
currentSuite = suite;
|
|
352
|
-
while (currentSuite) {
|
|
353
|
-
if (currentSuite.afterEach) {
|
|
354
|
-
afterEachFunctions.push(currentSuite.afterEach);
|
|
355
|
-
}
|
|
356
|
-
currentSuite = currentSuite.parent || null;
|
|
357
|
-
}
|
|
358
|
-
for (const afterEach of afterEachFunctions) {
|
|
359
|
-
await afterEach(tapTools);
|
|
360
|
-
}
|
|
361
|
-
return result;
|
|
362
|
-
};
|
|
363
|
-
const testPromise = test.run(context.testKey++);
|
|
364
|
-
if (test.parallel) {
|
|
365
|
-
promiseArray.push(testPromise);
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
await testPromise;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
// Recursively run child suites
|
|
372
|
-
await this._runSuite(suite, suite.children, promiseArray, context);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
async stopForcefully(codeArg = 0, directArg = false) {
|
|
376
|
-
console.log(`tap stopping forcefully! Code: ${codeArg} / Direct: ${directArg}`);
|
|
377
|
-
if (directArg) {
|
|
378
|
-
process.exit(codeArg);
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
setTimeout(() => {
|
|
382
|
-
process.exit(codeArg);
|
|
383
|
-
}, 10);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
/**
|
|
387
|
-
* handle errors
|
|
388
|
-
*/
|
|
389
|
-
threw(err) {
|
|
390
|
-
console.log(err);
|
|
391
|
-
}
|
|
392
|
-
/**
|
|
393
|
-
* Explicitly fail the current test with a custom message
|
|
394
|
-
* @param message - The failure message to display
|
|
395
|
-
*/
|
|
396
|
-
fail(message = 'Test failed') {
|
|
397
|
-
throw new Error(message);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
export const tap = new Tap();
|
|
401
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwYnVuZGxlLmNsYXNzZXMudGFwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHNfdGFwYnVuZGxlL3RhcGJ1bmRsZS5jbGFzc2VzLnRhcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHdCQUF3QixDQUFDO0FBRWxELE9BQU8sRUFBeUIsT0FBTyxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDaEYsT0FBTyxFQUFFLE9BQU8sRUFBc0IsTUFBTSxnQ0FBZ0MsQ0FBQztBQVc3RSxNQUFNLFdBQVc7SUFPZixZQUFZLEdBQVc7UUFMZixVQUFLLEdBQWEsRUFBRSxDQUFDO1FBQ3JCLGNBQVMsR0FBOEIsUUFBUSxDQUFDO1FBS3RELElBQUksQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFDO0lBQ2xCLENBQUM7SUFFRCxJQUFJLENBQUMsR0FBRyxJQUFjO1FBQ3BCLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDO1FBQ2xCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELFFBQVEsQ0FBQyxLQUFnQztRQUN2QyxJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQztRQUN2QixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxLQUFLLENBQUMsS0FBYTtRQUNqQixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQztRQUN6QixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxPQUFPLENBQUMsRUFBVTtRQUNoQixJQUFJLENBQUMsVUFBVSxHQUFHLEVBQUUsQ0FBQztRQUNyQixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxJQUFJLENBQUMsV0FBbUIsRUFBRSxZQUE4QjtRQUN0RCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsWUFBWSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBRWpFLDZCQUE2QjtRQUM3QixJQUFJLElBQUks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
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { TapTools } from './tapbundle.classes.taptools.js';
|
|
2
|
-
import { HrtMeasurement } from '@push.rocks/smarttime';
|
|
3
|
-
export type TTestStatus = 'success' | 'error' | 'pending' | 'errorAfterSuccess' | 'timeout' | 'skipped';
|
|
4
|
-
export interface ITestFunction<T> {
|
|
5
|
-
(tapTools?: TapTools): Promise<T>;
|
|
6
|
-
}
|
|
7
|
-
export declare class TapTest<T = unknown> {
|
|
8
|
-
description: string;
|
|
9
|
-
failureAllowed: boolean;
|
|
10
|
-
hrtMeasurement: HrtMeasurement;
|
|
11
|
-
parallel: boolean;
|
|
12
|
-
status: TTestStatus;
|
|
13
|
-
tapTools: TapTools;
|
|
14
|
-
testFunction: ITestFunction<T>;
|
|
15
|
-
testKey: number;
|
|
16
|
-
timeoutMs?: number;
|
|
17
|
-
isTodo: boolean;
|
|
18
|
-
todoReason?: string;
|
|
19
|
-
tags: string[];
|
|
20
|
-
priority: 'high' | 'medium' | 'low';
|
|
21
|
-
fileName?: string;
|
|
22
|
-
private testDeferred;
|
|
23
|
-
testPromise: Promise<TapTest<T>>;
|
|
24
|
-
private testResultDeferred;
|
|
25
|
-
testResultPromise: Promise<T>;
|
|
26
|
-
/**
|
|
27
|
-
* constructor
|
|
28
|
-
*/
|
|
29
|
-
constructor(optionsArg: {
|
|
30
|
-
description: string;
|
|
31
|
-
testFunction: ITestFunction<T>;
|
|
32
|
-
parallel: boolean;
|
|
33
|
-
});
|
|
34
|
-
/**
|
|
35
|
-
* run the test
|
|
36
|
-
*/
|
|
37
|
-
run(testKeyArg: number): Promise<void>;
|
|
38
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import * as plugins from './tapbundle.plugins.js';
|
|
2
|
-
import { tapCreator } from './tapbundle.tapcreator.js';
|
|
3
|
-
import { TapTools, SkipError } from './tapbundle.classes.taptools.js';
|
|
4
|
-
// imported interfaces
|
|
5
|
-
import { Deferred } from '@push.rocks/smartpromise';
|
|
6
|
-
import { HrtMeasurement } from '@push.rocks/smarttime';
|
|
7
|
-
export class TapTest {
|
|
8
|
-
/**
|
|
9
|
-
* constructor
|
|
10
|
-
*/
|
|
11
|
-
constructor(optionsArg) {
|
|
12
|
-
this.isTodo = false;
|
|
13
|
-
this.tags = [];
|
|
14
|
-
this.priority = 'medium';
|
|
15
|
-
this.testDeferred = plugins.smartpromise.defer();
|
|
16
|
-
this.testPromise = this.testDeferred.promise;
|
|
17
|
-
this.testResultDeferred = plugins.smartpromise.defer();
|
|
18
|
-
this.testResultPromise = this.testResultDeferred.promise;
|
|
19
|
-
this.description = optionsArg.description;
|
|
20
|
-
this.hrtMeasurement = new HrtMeasurement();
|
|
21
|
-
this.parallel = optionsArg.parallel;
|
|
22
|
-
this.status = 'pending';
|
|
23
|
-
this.tapTools = new TapTools(this);
|
|
24
|
-
this.testFunction = optionsArg.testFunction;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* run the test
|
|
28
|
-
*/
|
|
29
|
-
async run(testKeyArg) {
|
|
30
|
-
this.testKey = testKeyArg;
|
|
31
|
-
const testNumber = testKeyArg + 1;
|
|
32
|
-
// Handle todo tests
|
|
33
|
-
if (this.isTodo) {
|
|
34
|
-
const todoText = this.todoReason ? `# TODO ${this.todoReason}` : '# TODO';
|
|
35
|
-
console.log(`ok ${testNumber} - ${this.description} ${todoText}`);
|
|
36
|
-
this.status = 'success';
|
|
37
|
-
this.testDeferred.resolve(this);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
// Run test with retries
|
|
41
|
-
let lastError;
|
|
42
|
-
const maxRetries = this.tapTools.maxRetries;
|
|
43
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
44
|
-
this.hrtMeasurement.start();
|
|
45
|
-
try {
|
|
46
|
-
// Set up timeout if specified
|
|
47
|
-
let timeoutHandle;
|
|
48
|
-
let timeoutPromise = null;
|
|
49
|
-
if (this.timeoutMs) {
|
|
50
|
-
timeoutPromise = new Promise((_, reject) => {
|
|
51
|
-
timeoutHandle = setTimeout(() => {
|
|
52
|
-
this.status = 'timeout';
|
|
53
|
-
reject(new Error(`Test timed out after ${this.timeoutMs}ms`));
|
|
54
|
-
}, this.timeoutMs);
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
// Run the test function with potential timeout
|
|
58
|
-
const testPromise = this.testFunction(this.tapTools);
|
|
59
|
-
const testReturnValue = timeoutPromise
|
|
60
|
-
? await Promise.race([testPromise, timeoutPromise])
|
|
61
|
-
: await testPromise;
|
|
62
|
-
// Clear timeout if test completed
|
|
63
|
-
if (timeoutHandle) {
|
|
64
|
-
clearTimeout(timeoutHandle);
|
|
65
|
-
}
|
|
66
|
-
this.hrtMeasurement.stop();
|
|
67
|
-
console.log(`ok ${testNumber} - ${this.description} # time=${this.hrtMeasurement.milliSeconds}ms`);
|
|
68
|
-
this.status = 'success';
|
|
69
|
-
this.testDeferred.resolve(this);
|
|
70
|
-
this.testResultDeferred.resolve(testReturnValue);
|
|
71
|
-
return; // Success, exit retry loop
|
|
72
|
-
}
|
|
73
|
-
catch (err) {
|
|
74
|
-
this.hrtMeasurement.stop();
|
|
75
|
-
// Handle skip
|
|
76
|
-
if (err instanceof SkipError || err.name === 'SkipError') {
|
|
77
|
-
console.log(`ok ${testNumber} - ${this.description} # SKIP ${err.message.replace('Skipped: ', '')}`);
|
|
78
|
-
this.status = 'skipped';
|
|
79
|
-
this.testDeferred.resolve(this);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
lastError = err;
|
|
83
|
-
// If we have retries left, try again
|
|
84
|
-
if (attempt < maxRetries) {
|
|
85
|
-
console.log(`# Retry ${attempt + 1}/${maxRetries} for test: ${this.description}`);
|
|
86
|
-
this.tapTools._incrementRetryCount();
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
// Final failure
|
|
90
|
-
console.log(`not ok ${testNumber} - ${this.description} # time=${this.hrtMeasurement.milliSeconds}ms`);
|
|
91
|
-
this.testDeferred.resolve(this);
|
|
92
|
-
this.testResultDeferred.resolve(err);
|
|
93
|
-
// if the test has already succeeded before
|
|
94
|
-
if (this.status === 'success') {
|
|
95
|
-
this.status = 'errorAfterSuccess';
|
|
96
|
-
console.log('!!! ALERT !!!: weird behaviour, since test has been already successfull');
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
this.status = 'error';
|
|
100
|
-
}
|
|
101
|
-
// if the test is allowed to fail
|
|
102
|
-
if (this.failureAllowed) {
|
|
103
|
-
console.log(`please note: failure allowed!`);
|
|
104
|
-
}
|
|
105
|
-
console.log(err);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwYnVuZGxlLmNsYXNzZXMudGFwdGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzX3RhcGJ1bmRsZS90YXBidW5kbGUuY2xhc3Nlcy50YXB0ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sd0JBQXdCLENBQUM7QUFDbEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFdEUsc0JBQXNCO0FBQ3RCLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFTdkQsTUFBTSxPQUFPLE9BQU87SUFtQmxCOztPQUVHO0lBQ0gsWUFBWSxVQUlYO1FBaEJNLFdBQU0sR0FBWSxLQUFLLENBQUM7UUFFeEIsU0FBSSxHQUFhLEVBQUUsQ0FBQztRQUNwQixhQUFRLEdBQThCLFFBQVEsQ0FBQztRQUU5QyxpQkFBWSxHQUF5QixPQUFPLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ25FLGdCQUFXLEdBQXdCLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDO1FBQzVELHVCQUFrQixHQUFnQixPQUFPLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2hFLHNCQUFpQixHQUFlLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUM7UUFTckUsSUFBSSxDQUFDLFdBQVcsR0FBRyxVQUFVLENBQUMsV0FBVyxDQUFDO1FBQzFDLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxjQUFjLEVBQUUsQ0FBQztRQUMzQyxJQUFJLENBQUMsUUFBUSxHQUFHLFVBQVUsQ0FBQyxRQUFRLENBQUM7UUFDcEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUM7UUFDeEIsSUFB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
|