|
|
@@ -53,6 +53,12 @@
|
|
53
|
53
|
color: var(--color-secondary);
|
|
54
|
54
|
font-size: 80%;
|
|
55
|
55
|
}
|
|
|
56
|
+ .testcasererun {
|
|
|
57
|
+ float: right;
|
|
|
58
|
+ padding-left: 0.5em;
|
|
|
59
|
+ cursor: pointer;
|
|
|
60
|
+ font-size: 150%;
|
|
|
61
|
+ }
|
|
56
|
62
|
.testcaseresult {
|
|
57
|
63
|
height: 1em;
|
|
58
|
64
|
}
|
|
|
@@ -252,6 +258,18 @@
|
|
252
|
258
|
toHTML() {
|
|
253
|
259
|
var html = `<div class="testcase" id="${this.#cssId}">`;
|
|
254
|
260
|
html += `<div class="testcasename"><span class="testcasemethod">${this.methodName}</span></div>`;
|
|
|
261
|
+ if (this.result == ResultType.passed || this.result == ResultType.failed || this.result == ResultType.errored) {
|
|
|
262
|
+ const rerunId = `testcasererun-${this.#cssId}`;
|
|
|
263
|
+ const testId = this.uniqueId;
|
|
|
264
|
+ html += `<div class="testcasererun" id="${rerunId}">🔄</div>`;
|
|
|
265
|
+ setTimeout(() => {
|
|
|
266
|
+ const node = document.getElementById(rerunId);
|
|
|
267
|
+ if (!node) return;
|
|
|
268
|
+ node.addEventListener('click', () => {
|
|
|
269
|
+ TestClassRunner.rerun(testId);
|
|
|
270
|
+ });
|
|
|
271
|
+ }, 0);
|
|
|
272
|
+ }
|
|
255
|
273
|
html += '<div class="testcaseresult">';
|
|
256
|
274
|
switch (this.result) {
|
|
257
|
275
|
case ResultType.untested:
|
|
|
@@ -399,38 +417,66 @@
|
|
399
|
417
|
break;
|
|
400
|
418
|
}
|
|
401
|
419
|
}
|
|
402
|
|
- document.getElementById(`${this.#cssId}details`).open = !allPassed;
|
|
|
420
|
+ if (!TestClassRunner.#isRerunning) {
|
|
|
421
|
+ document.getElementById(`${this.#cssId}details`).open = !allPassed;
|
|
|
422
|
+ }
|
|
403
|
423
|
}
|
|
404
|
424
|
}
|
|
405
|
425
|
|
|
|
426
|
+ static #idToTestCase = {}; // number -> [TestClassRunner, TestCaseRunner]
|
|
406
|
427
|
static runAll(testClasses) {
|
|
407
|
|
- var tests = []; // tuples of TestClassRunner and TestCaseRunner
|
|
408
|
428
|
for (const testClass of testClasses) {
|
|
409
|
429
|
const classRunner = new TestClassRunner(testClass);
|
|
410
|
430
|
classRunner.updateHTML();
|
|
411
|
|
- tests.push(...classRunner.testCases.map(function(test) { return [ classRunner, test ] }));
|
|
|
431
|
+ const cases = classRunner.testCases.map(function(test) { return [ classRunner, test ] });
|
|
|
432
|
+ for (const testTuple of cases) {
|
|
|
433
|
+ this.#idToTestCase[testTuple[1].uniqueId] = testTuple;
|
|
|
434
|
+ }
|
|
|
435
|
+ this.#testQueue.push(...cases);
|
|
412
|
436
|
}
|
|
413
|
|
- var testInterval = setInterval(function() {
|
|
414
|
|
- if (tests.length == 0) {
|
|
415
|
|
- clearInterval(testInterval);
|
|
416
|
|
- testInterval = null;
|
|
|
437
|
+ this.#runTestQueue();
|
|
|
438
|
+ }
|
|
|
439
|
+
|
|
|
440
|
+ static #testQueue = []; // tuples of [TestClassRunner, TestCaseRunner]
|
|
|
441
|
+ static #testInterval = null;
|
|
|
442
|
+ static #isRerunning = false;
|
|
|
443
|
+ static #runTestQueue() {
|
|
|
444
|
+ if (this.#testInterval) return;
|
|
|
445
|
+ this.#testInterval = setInterval(function() {
|
|
|
446
|
+ if (TestClassRunner.#testQueue.length == 0) {
|
|
|
447
|
+ clearInterval(TestClassRunner.#testInterval);
|
|
|
448
|
+ TestClassRunner.#testInterval = null;
|
|
417
|
449
|
return;
|
|
418
|
450
|
}
|
|
419
|
451
|
var classRunner;
|
|
420
|
452
|
var testCase;
|
|
421
|
|
- [ classRunner, testCase ] = tests[0];
|
|
|
453
|
+ [ classRunner, testCase ] = TestClassRunner.#testQueue[0];
|
|
422
|
454
|
if (testCase.result == ResultType.untested) {
|
|
423
|
455
|
testCase.result = ResultType.testing;
|
|
424
|
456
|
testCase.updateHTML();
|
|
425
|
457
|
classRunner.updateHTML();
|
|
426
|
458
|
} else if (testCase.result == ResultType.testing) {
|
|
427
|
|
- tests.splice(0, 1);
|
|
|
459
|
+ TestClassRunner.#testQueue.splice(0, 1);
|
|
428
|
460
|
testCase.run();
|
|
429
|
461
|
testCase.updateHTML();
|
|
430
|
462
|
classRunner.updateHTML();
|
|
431
|
463
|
}
|
|
432
|
464
|
}, 1);
|
|
433
|
465
|
}
|
|
|
466
|
+
|
|
|
467
|
+ static rerun(testId) {
|
|
|
468
|
+ const tuple = this.#idToTestCase[testId];
|
|
|
469
|
+ if (!tuple) return;
|
|
|
470
|
+ /** @type {TestClassRunner} */
|
|
|
471
|
+ const testClass = tuple[0];
|
|
|
472
|
+ /** @type {TestCaseRunner} */
|
|
|
473
|
+ const testCase = tuple[1];
|
|
|
474
|
+ testCase.result = ResultType.untested;
|
|
|
475
|
+ testCase.updateHTML();
|
|
|
476
|
+ this.#testQueue.push([testClass, testCase]);
|
|
|
477
|
+ this.#isRerunning = true;
|
|
|
478
|
+ this.#runTestQueue();
|
|
|
479
|
+ }
|
|
434
|
480
|
}
|
|
435
|
481
|
</script>
|
|
436
|
482
|
<!-- Tests -->
|