@camperaid/watest 2.4.12 → 2.5.1
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/core/base.js +10 -3
- package/core/series.js +70 -15
- package/core/settings.js +1 -1
- package/core/system.js +68 -0
- package/eslint.config.js +1 -1
- package/index.js +10 -0
- package/interfaces/servicer.js +0 -1
- package/package.json +1 -1
- package/tests/base/t_system.js +59 -0
- package/tests/base/t_throws.js +67 -0
- package/tests/e2e/t_folder.js +1 -1
- package/tests/e2e/t_loader.js +2 -2
- package/tests/e2e/t_loader_mixed.js +2 -2
- package/tests/e2e/t_loader_multiple.js +3 -3
- package/tests/e2e/t_loader_multiple_patterns.js +3 -3
- package/tests/e2e/t_single.js +1 -1
- package/tests/e2e/t_wd_firefox.js +2 -2
- package/tests/e2e/t_wd_firefox_chrome.js +2 -2
- package/tests/e2e/t_wd_firefox_chrome_pattern.js +2 -2
- package/tests/e2e/t_wd_mixed_firefox.js +2 -2
- package/tests/e2e/t_wd_mixed_firefox_chrome.js +2 -2
- package/tests/series/build/t_pattern_filtering.js +175 -0
- package/tests/series/logging/t_verify.js +1 -1
- package/tests/series/meta.js +1 -0
- package/tests/series/perform/t_failure.js +1 -0
- package/tests/series/perform/t_failure_notest.js +1 -0
- package/tests/series/perform/t_intermittent.js +2 -0
- package/tests/series/perform/t_intermittent_global.js +1 -0
- package/tests/series/perform/t_missing_perma.js +2 -0
- package/tests/series/perform/t_nested.js +1 -0
- package/tests/series/perform/t_perma.js +1 -0
- package/tests/series/perform/t_success.js +2 -0
- package/tests/series/run/t_debunk_failure.js +1 -1
- package/tests/series/run/t_debunk_success.js +1 -1
- package/tests/series/run/t_nested.js +1 -1
- package/tests/series/run/t_verify.js +1 -1
- package/tests/series/run/t_verify_webdriver.js +1 -1
- package/tests/series/servicer/t_servicer.js +84 -0
package/core/base.js
CHANGED
|
@@ -551,9 +551,16 @@ function is_out(got, expected, msg) {
|
|
|
551
551
|
return false;
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
-
function throws(func,
|
|
555
|
-
const on_no_exception = () => fail(`${msg}: no '${
|
|
556
|
-
const on_exception = e =>
|
|
554
|
+
function throws(func, expected, msg) {
|
|
555
|
+
const on_no_exception = () => fail(`${msg}: no '${expected}' exception`);
|
|
556
|
+
const on_exception = e =>
|
|
557
|
+
is(
|
|
558
|
+
expected instanceof RegExp || typeof expected === 'string'
|
|
559
|
+
? e?.message
|
|
560
|
+
: e,
|
|
561
|
+
expected,
|
|
562
|
+
msg,
|
|
563
|
+
);
|
|
557
564
|
return throw_internal(func, on_no_exception, on_exception);
|
|
558
565
|
}
|
|
559
566
|
|
package/core/series.js
CHANGED
|
@@ -145,9 +145,6 @@ class Series {
|
|
|
145
145
|
await this.runFor(this.failures, '2');
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
-
|
|
149
|
-
await settings.servicer.shutdown();
|
|
150
|
-
|
|
151
148
|
log(`Elapsed: ${Date.now() - start_time}ms`);
|
|
152
149
|
}
|
|
153
150
|
|
|
@@ -181,6 +178,7 @@ class Series {
|
|
|
181
178
|
}
|
|
182
179
|
|
|
183
180
|
shutdown() {
|
|
181
|
+
console.log(`Testsuite: shutdown`);
|
|
184
182
|
testflow.unlock();
|
|
185
183
|
return this.failures.length > 0 ? this.failures : null;
|
|
186
184
|
}
|
|
@@ -367,8 +365,24 @@ class Series {
|
|
|
367
365
|
return [];
|
|
368
366
|
}
|
|
369
367
|
|
|
368
|
+
// Filter subfolders to only process those that match the patterns
|
|
369
|
+
let filteredSubfolders = subfolders;
|
|
370
|
+
if (patterns.length > 0) {
|
|
371
|
+
filteredSubfolders = subfolders.filter(subfolder => {
|
|
372
|
+
const subfolderPath = `${folder}/${subfolder}`;
|
|
373
|
+
return (
|
|
374
|
+
this.matchedPatterns({
|
|
375
|
+
path: subfolderPath,
|
|
376
|
+
webdriver,
|
|
377
|
+
patterns,
|
|
378
|
+
path_is_not_final: true,
|
|
379
|
+
}).length > 0
|
|
380
|
+
);
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
370
384
|
let subtests_for_subfolders = await Promise.all(
|
|
371
|
-
|
|
385
|
+
filteredSubfolders.map(subfolder =>
|
|
372
386
|
this.build({
|
|
373
387
|
patterns,
|
|
374
388
|
folder: `${folder}/${subfolder}`,
|
|
@@ -428,13 +442,21 @@ class Series {
|
|
|
428
442
|
test_module.expected_failures || [],
|
|
429
443
|
);
|
|
430
444
|
|
|
431
|
-
//
|
|
445
|
+
// Set services if given.
|
|
446
|
+
if (test_module.servicer) {
|
|
447
|
+
if (this.#servicerType) {
|
|
448
|
+
throw new Error(`No nested servicers are supported`);
|
|
449
|
+
}
|
|
450
|
+
this.#servicerType = test_module.servicer;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Initialize.
|
|
432
454
|
if (test_module.services || test_module.init) {
|
|
433
455
|
let init = async () => {
|
|
434
456
|
// Start services if any.
|
|
435
457
|
let chain = Promise.resolve();
|
|
436
458
|
for (let service of test_module.services || []) {
|
|
437
|
-
chain = chain.then(() =>
|
|
459
|
+
chain = chain.then(() => this.getServicer().start(service));
|
|
438
460
|
}
|
|
439
461
|
await chain;
|
|
440
462
|
|
|
@@ -460,7 +482,7 @@ class Series {
|
|
|
460
482
|
// A function to notify the servicer the test is about to start and then
|
|
461
483
|
// to invoke the test.
|
|
462
484
|
const test_wrap = () =>
|
|
463
|
-
Promise.resolve(
|
|
485
|
+
Promise.resolve(this.#servicer?.ontest(name)).then(test);
|
|
464
486
|
|
|
465
487
|
let failures_info = Series.failuresInfo({
|
|
466
488
|
failures: expected_failures,
|
|
@@ -494,8 +516,13 @@ class Series {
|
|
|
494
516
|
await Promise.all(
|
|
495
517
|
[...(test_module.services || [])]
|
|
496
518
|
.reverse()
|
|
497
|
-
.map(s =>
|
|
519
|
+
.map(s => this.getServicer().stop(s)),
|
|
498
520
|
);
|
|
521
|
+
|
|
522
|
+
// Clean up service-level servicer
|
|
523
|
+
await this.#servicer?.shutdown();
|
|
524
|
+
this.#servicer = null;
|
|
525
|
+
this.#servicerType = null;
|
|
499
526
|
};
|
|
500
527
|
tests.push({
|
|
501
528
|
name: `${virtual_folder}/uninit`,
|
|
@@ -641,6 +668,16 @@ class Series {
|
|
|
641
668
|
let kungFuDeathGrip = null;
|
|
642
669
|
let kungFuDeathGripResolve = null;
|
|
643
670
|
let kungFuDeathGripTimer = 0;
|
|
671
|
+
|
|
672
|
+
// Take snapshots before the test runs
|
|
673
|
+
const testSnapshots = {
|
|
674
|
+
fcnt: this.core.failureCount,
|
|
675
|
+
icnt: this.core.intermittentCount,
|
|
676
|
+
tcnt: this.core.todoCount,
|
|
677
|
+
wcnt: this.core.warningCount,
|
|
678
|
+
ocnt: this.core.okCount,
|
|
679
|
+
};
|
|
680
|
+
|
|
644
681
|
try {
|
|
645
682
|
this.core.setExpectedFailures(failures_info);
|
|
646
683
|
|
|
@@ -687,6 +724,7 @@ class Series {
|
|
|
687
724
|
init_or_uninit,
|
|
688
725
|
path,
|
|
689
726
|
webdriver,
|
|
727
|
+
snapshots: testSnapshots,
|
|
690
728
|
});
|
|
691
729
|
|
|
692
730
|
// If failed, then stop running the current tests.
|
|
@@ -715,12 +753,12 @@ class Series {
|
|
|
715
753
|
await this.LogPipe.release();
|
|
716
754
|
}
|
|
717
755
|
|
|
718
|
-
recordStats({ name, init_or_uninit, path, webdriver }) {
|
|
756
|
+
recordStats({ name, init_or_uninit, path, webdriver, snapshots }) {
|
|
719
757
|
let hasChanged = false;
|
|
720
758
|
let hasFailures = false;
|
|
721
759
|
|
|
722
760
|
// Record intermittents.
|
|
723
|
-
let delta = this.core.intermittentCount -
|
|
761
|
+
let delta = this.core.intermittentCount - snapshots.icnt;
|
|
724
762
|
if (delta > 0) {
|
|
725
763
|
log(`>${name} has ${delta} intermittent(s)`);
|
|
726
764
|
this.icnt = this.core.intermittentCount;
|
|
@@ -728,7 +766,7 @@ class Series {
|
|
|
728
766
|
}
|
|
729
767
|
|
|
730
768
|
// Record todos.
|
|
731
|
-
delta = this.core.todoCount -
|
|
769
|
+
delta = this.core.todoCount - snapshots.tcnt;
|
|
732
770
|
if (delta > 0) {
|
|
733
771
|
log(`>${name} has ${delta} todo(s)`);
|
|
734
772
|
this.tcnt = this.core.todoCount;
|
|
@@ -736,7 +774,7 @@ class Series {
|
|
|
736
774
|
}
|
|
737
775
|
|
|
738
776
|
// Record warnings.
|
|
739
|
-
delta = this.core.warningCount -
|
|
777
|
+
delta = this.core.warningCount - snapshots.wcnt;
|
|
740
778
|
if (delta > 0) {
|
|
741
779
|
log(`>${name} has ${delta} warnings(s)`);
|
|
742
780
|
this.wcnt = this.core.warningCount;
|
|
@@ -744,14 +782,14 @@ class Series {
|
|
|
744
782
|
}
|
|
745
783
|
|
|
746
784
|
// Record successful test count.
|
|
747
|
-
delta = this.core.okCount -
|
|
785
|
+
delta = this.core.okCount - snapshots.ocnt;
|
|
748
786
|
if (delta > 0) {
|
|
749
787
|
this.ocnt = this.core.okCount;
|
|
750
788
|
hasChanged = true;
|
|
751
789
|
}
|
|
752
790
|
|
|
753
791
|
// Fail if no changes.
|
|
754
|
-
delta = this.core.failureCount -
|
|
792
|
+
delta = this.core.failureCount - snapshots.fcnt;
|
|
755
793
|
if (!init_or_uninit) {
|
|
756
794
|
if (delta == 0 && !hasChanged) {
|
|
757
795
|
delta = 1;
|
|
@@ -908,7 +946,10 @@ class Series {
|
|
|
908
946
|
let args = [];
|
|
909
947
|
if (loader) {
|
|
910
948
|
// Use the new --import flag with register() API instead of deprecated --loader
|
|
911
|
-
args.push(
|
|
949
|
+
args.push(
|
|
950
|
+
'--import',
|
|
951
|
+
`data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("${loader}", pathToFileURL("./"));`,
|
|
952
|
+
);
|
|
912
953
|
}
|
|
913
954
|
const watest_bin = nodepath.join(__dirname, '../bin/watest.js');
|
|
914
955
|
args.push(
|
|
@@ -1018,6 +1059,20 @@ class Series {
|
|
|
1018
1059
|
}
|
|
1019
1060
|
}
|
|
1020
1061
|
}
|
|
1062
|
+
|
|
1063
|
+
getServicer() {
|
|
1064
|
+
if (!this.#servicer) {
|
|
1065
|
+
this.#servicer = this.createServicer(this.#servicerType);
|
|
1066
|
+
}
|
|
1067
|
+
return this.#servicer;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
createServicer(servicerType) {
|
|
1071
|
+
return settings.getServicer(servicerType);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
#servicer;
|
|
1075
|
+
#servicerType;
|
|
1021
1076
|
}
|
|
1022
1077
|
|
|
1023
1078
|
export { Series };
|
package/core/settings.js
CHANGED
package/core/system.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { spawn } from './spawn.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Run a shell command and capture its output
|
|
5
|
+
* @param {string} cmd - Command to run
|
|
6
|
+
* @param {string[]} args - Command arguments
|
|
7
|
+
* @param {object} options - Spawn options
|
|
8
|
+
* @returns {Promise<{stdout: string, stderr: string, exitCode: number, stdoutLines: string[], stderrLines: string[]}>}
|
|
9
|
+
*/
|
|
10
|
+
export async function runCommand(cmd, args = [], options = {}) {
|
|
11
|
+
let stdout = [];
|
|
12
|
+
let stderr = [];
|
|
13
|
+
let exitCode = 0;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
exitCode = await spawn(cmd, args, options, buffer => {
|
|
17
|
+
for (let { str_data, is_stdout } of buffer) {
|
|
18
|
+
const lines = str_data.split('\n').filter(line => line);
|
|
19
|
+
if (is_stdout) {
|
|
20
|
+
stdout.push(...lines);
|
|
21
|
+
} else {
|
|
22
|
+
stderr.push(...lines);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
} catch (code) {
|
|
27
|
+
exitCode = code;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
stdout: stdout.join('\n'),
|
|
32
|
+
stderr: stderr.join('\n'),
|
|
33
|
+
exitCode,
|
|
34
|
+
stdoutLines: stdout,
|
|
35
|
+
stderrLines: stderr,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Run a bash script with proper error handling
|
|
41
|
+
* @param {string} script - Bash script content
|
|
42
|
+
* @param {string[]} args - Script arguments
|
|
43
|
+
* @param {object} options - Spawn options
|
|
44
|
+
* @returns {Promise<{stdout: string, stderr: string, exitCode: number, stdoutLines: string[], stderrLines: string[]}>}
|
|
45
|
+
*/
|
|
46
|
+
export async function runBashScript(script, args = [], options = {}) {
|
|
47
|
+
return runCommand('bash', ['-c', script, '--', ...args], options);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Run a shell command and return only stdout (for simple cases)
|
|
52
|
+
* @param {string} cmd - Command to run
|
|
53
|
+
* @param {string[]} args - Command arguments
|
|
54
|
+
* @param {object} options - Spawn options
|
|
55
|
+
* @returns {Promise<string>} stdout content
|
|
56
|
+
*/
|
|
57
|
+
export async function execCommand(cmd, args = [], options = {}) {
|
|
58
|
+
const result = await runCommand(cmd, args, options);
|
|
59
|
+
if (result.exitCode !== 0) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`Command failed with exit code ${result.exitCode}: ${result.stderr}`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
return result.stdout;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Export the raw spawn function for advanced use cases
|
|
68
|
+
export { spawn };
|
package/eslint.config.js
CHANGED
package/index.js
CHANGED
|
@@ -26,12 +26,19 @@ import { inspect } from './core/util.js';
|
|
|
26
26
|
import { AppDriver } from './webdriver/app_driver.js';
|
|
27
27
|
import { ControlDriver } from './webdriver/control_driver.js';
|
|
28
28
|
import { start_session, scope } from './webdriver/session.js';
|
|
29
|
+
import {
|
|
30
|
+
runCommand,
|
|
31
|
+
runBashScript,
|
|
32
|
+
execCommand,
|
|
33
|
+
spawn,
|
|
34
|
+
} from './core/system.js';
|
|
29
35
|
|
|
30
36
|
export {
|
|
31
37
|
AppDriver,
|
|
32
38
|
ControlDriver,
|
|
33
39
|
assert,
|
|
34
40
|
contains,
|
|
41
|
+
execCommand,
|
|
35
42
|
failed,
|
|
36
43
|
fail,
|
|
37
44
|
group,
|
|
@@ -42,7 +49,10 @@ export {
|
|
|
42
49
|
not_reached,
|
|
43
50
|
no_throws,
|
|
44
51
|
ok,
|
|
52
|
+
runBashScript,
|
|
53
|
+
runCommand,
|
|
45
54
|
scope,
|
|
55
|
+
spawn,
|
|
46
56
|
start_session,
|
|
47
57
|
success,
|
|
48
58
|
todo,
|
package/interfaces/servicer.js
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ok, contains } from '../../index.js';
|
|
2
|
+
import { runCommand, runBashScript, execCommand } from '../../core/system.js';
|
|
3
|
+
|
|
4
|
+
export async function test() {
|
|
5
|
+
// Test 1: runCommand with echo
|
|
6
|
+
{
|
|
7
|
+
const result = await runCommand('echo', ['hello', 'world']);
|
|
8
|
+
ok(result.exitCode === 0, 'echo command should succeed');
|
|
9
|
+
ok(result.stdout === 'hello world', 'stdout should contain echo output');
|
|
10
|
+
ok(result.stderr === '', 'stderr should be empty');
|
|
11
|
+
ok(result.stdoutLines.length === 1, 'should have one stdout line');
|
|
12
|
+
ok(result.stdoutLines[0] === 'hello world', 'stdout line should match');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Test 2: runBashScript with simple script
|
|
16
|
+
{
|
|
17
|
+
const script = 'echo "test script"; echo "line 2"';
|
|
18
|
+
const result = await runBashScript(script);
|
|
19
|
+
ok(result.exitCode === 0, 'bash script should succeed');
|
|
20
|
+
contains(result.stdout, 'test script', 'should contain first echo');
|
|
21
|
+
contains(result.stdout, 'line 2', 'should contain second echo');
|
|
22
|
+
ok(result.stdoutLines.length === 2, 'should have two stdout lines');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Test 3: execCommand for simple cases
|
|
26
|
+
{
|
|
27
|
+
const output = await execCommand('echo', ['simple test']);
|
|
28
|
+
ok(output === 'simple test', 'execCommand should return stdout directly');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Test 4: runCommand with failing command
|
|
32
|
+
{
|
|
33
|
+
const result = await runCommand('bash', ['-c', 'echo "error" >&2; exit 1']);
|
|
34
|
+
ok(result.exitCode === 1, 'failing command should return exit code 1');
|
|
35
|
+
ok(result.stdout === '', 'stdout should be empty');
|
|
36
|
+
ok(result.stderr === 'error', 'stderr should contain error message');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Test 5: execCommand should throw on failure
|
|
40
|
+
{
|
|
41
|
+
let threw = false;
|
|
42
|
+
try {
|
|
43
|
+
await execCommand('bash', ['-c', 'exit 1']);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
threw = true;
|
|
46
|
+
contains(error.message, 'exit code 1', 'error should mention exit code');
|
|
47
|
+
}
|
|
48
|
+
ok(threw, 'execCommand should throw on non-zero exit code');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Test 6: runBashScript with arguments
|
|
52
|
+
{
|
|
53
|
+
const script = 'echo "arg1: $1, arg2: $2"';
|
|
54
|
+
const result = await runBashScript(script, ['first', 'second']);
|
|
55
|
+
ok(result.exitCode === 0, 'bash script with args should succeed');
|
|
56
|
+
contains(result.stdout, 'arg1: first', 'should pass first argument');
|
|
57
|
+
contains(result.stdout, 'arg2: second', 'should pass second argument');
|
|
58
|
+
}
|
|
59
|
+
}
|
package/tests/base/t_throws.js
CHANGED
|
@@ -136,4 +136,71 @@ unexpected character: '2' at 6 pos, expected: '1' at '' line
|
|
|
136
136
|
],
|
|
137
137
|
`no_throws fail (async)`,
|
|
138
138
|
);
|
|
139
|
+
|
|
140
|
+
// throws: accept object descriptor (statusCode + JSON body)
|
|
141
|
+
await is_output(
|
|
142
|
+
() =>
|
|
143
|
+
throws(
|
|
144
|
+
() => {
|
|
145
|
+
const err = new Error(
|
|
146
|
+
'HTTP error code 422 for https://api.digitalocean.com/v2/droplets',
|
|
147
|
+
);
|
|
148
|
+
err.statusCode = 422;
|
|
149
|
+
err.responseBody = JSON.stringify({
|
|
150
|
+
id: 'unprocessable_entity',
|
|
151
|
+
message: 'You specified an invalid image for Droplet creation.',
|
|
152
|
+
});
|
|
153
|
+
throw err;
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
statusCode: 422,
|
|
157
|
+
responseBody: JSON.stringify({
|
|
158
|
+
id: 'unprocessable_entity',
|
|
159
|
+
message: 'You specified an invalid image for Droplet creation.',
|
|
160
|
+
}),
|
|
161
|
+
},
|
|
162
|
+
`Throws error descriptor`,
|
|
163
|
+
),
|
|
164
|
+
[
|
|
165
|
+
`Ok: Throws error descriptor, got: {statusCode: 422, responseBody: '{"id":"unprocessable_entity","message":"You specified an invalid image for Droplet creation."}'}`,
|
|
166
|
+
],
|
|
167
|
+
[],
|
|
168
|
+
`throws accept object descriptor`,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// throws: accept RegExp for message matching
|
|
172
|
+
await is_output(
|
|
173
|
+
() =>
|
|
174
|
+
throws(
|
|
175
|
+
() => {
|
|
176
|
+
throw new Error(
|
|
177
|
+
'Unexpected 404 response code for https://example.com/test from droplet 1',
|
|
178
|
+
);
|
|
179
|
+
},
|
|
180
|
+
/404|Unexpected/,
|
|
181
|
+
`Throws with RegExp`,
|
|
182
|
+
),
|
|
183
|
+
[
|
|
184
|
+
`Ok: Throws with RegExp 'Unexpected 404 response code for https://example.com/test from droplet 1' matches /404|Unexpected/ regexp`,
|
|
185
|
+
],
|
|
186
|
+
[],
|
|
187
|
+
`throws accept RegExp pattern`,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// throws: fail RegExp that doesn't match
|
|
191
|
+
await is_output(
|
|
192
|
+
() =>
|
|
193
|
+
throws(
|
|
194
|
+
() => {
|
|
195
|
+
throw new Error('Some other error message');
|
|
196
|
+
},
|
|
197
|
+
/404|Unexpected/,
|
|
198
|
+
`RegExp should match`,
|
|
199
|
+
),
|
|
200
|
+
[],
|
|
201
|
+
[
|
|
202
|
+
`Failed: RegExp should match 'Some other error message' doesn't match /404|Unexpected/ regexp`,
|
|
203
|
+
],
|
|
204
|
+
`throws fail RegExp no match`,
|
|
205
|
+
);
|
|
139
206
|
}
|
package/tests/e2e/t_folder.js
CHANGED
package/tests/e2e/t_loader.js
CHANGED
|
@@ -11,12 +11,12 @@ export async function test() {
|
|
|
11
11
|
'\x1B[32mOk:\x1B[0m Mocked!, got: mocked',
|
|
12
12
|
'>sample/t_test.js completed in',
|
|
13
13
|
'\x1B[38;5;243mCompleted\x1B[0m sample/',
|
|
14
|
-
'Testsuite: shutdown',
|
|
15
14
|
'Elapsed:',
|
|
15
|
+
'Testsuite: shutdown',
|
|
16
16
|
'\x1B[102mSuccess!\x1B[0m Total: 1',
|
|
17
17
|
'\x1B[38;5;243mCompleted\x1B[0m sample/',
|
|
18
|
-
'Testsuite: shutdown',
|
|
19
18
|
'Elapsed:',
|
|
19
|
+
'Testsuite: shutdown',
|
|
20
20
|
],
|
|
21
21
|
'stdout',
|
|
22
22
|
);
|
|
@@ -16,12 +16,12 @@ export async function test() {
|
|
|
16
16
|
'\x1B[32mOk:\x1B[0m Mocked!, got: mocked',
|
|
17
17
|
'>sample/ui/t_test.js completed in',
|
|
18
18
|
'\x1B[38;5;243mCompleted\x1B[0m sample/ui',
|
|
19
|
-
'Testsuite: shutdown',
|
|
20
19
|
'Elapsed:',
|
|
20
|
+
'Testsuite: shutdown',
|
|
21
21
|
'\x1B[102mSuccess!\x1B[0m Total: 2',
|
|
22
22
|
'\x1B[38;5;243mCompleted\x1B[0m sample/',
|
|
23
|
-
'Testsuite: shutdown',
|
|
24
23
|
'Elapsed:',
|
|
24
|
+
'Testsuite: shutdown',
|
|
25
25
|
],
|
|
26
26
|
'stdout',
|
|
27
27
|
);
|
|
@@ -11,19 +11,19 @@ export async function test() {
|
|
|
11
11
|
'\x1B[32mOk:\x1B[0m Mocked!, got: mocked',
|
|
12
12
|
'>sample/base/t_btest.js completed in',
|
|
13
13
|
'\x1B[38;5;243mCompleted\x1B[0m sample/base',
|
|
14
|
-
'Testsuite: shutdown',
|
|
15
14
|
'Elapsed:',
|
|
15
|
+
'Testsuite: shutdown',
|
|
16
16
|
'\x1B[38;5;99mStarted\x1B[0m sample/core',
|
|
17
17
|
'!Running: sample/core/t_ctest.js, path: tests/core/t_ctest.js',
|
|
18
18
|
'\x1B[32mOk:\x1B[0m Mocked!, got: mocked',
|
|
19
19
|
'>sample/core/t_ctest.js completed in',
|
|
20
20
|
'\x1B[38;5;243mCompleted\x1B[0m sample/core',
|
|
21
|
-
'Testsuite: shutdown',
|
|
22
21
|
'Elapsed:',
|
|
22
|
+
'Testsuite: shutdown',
|
|
23
23
|
'\x1B[102mSuccess!\x1B[0m Total: 2',
|
|
24
24
|
'\x1B[38;5;243mCompleted\x1B[0m sample/',
|
|
25
|
-
'Testsuite: shutdown',
|
|
26
25
|
'Elapsed:',
|
|
26
|
+
'Testsuite: shutdown',
|
|
27
27
|
],
|
|
28
28
|
'stdout',
|
|
29
29
|
);
|
|
@@ -13,19 +13,19 @@ export async function test() {
|
|
|
13
13
|
'\x1B[32mOk:\x1B[0m Mocked!, got: mocked',
|
|
14
14
|
'>sample/base/t_btest.js completed in',
|
|
15
15
|
'\x1B[38;5;243mCompleted\x1B[0m sample/base',
|
|
16
|
-
'Testsuite: shutdown',
|
|
17
16
|
'Elapsed:',
|
|
17
|
+
'Testsuite: shutdown',
|
|
18
18
|
'\x1B[38;5;99mStarted\x1B[0m sample/core',
|
|
19
19
|
'!Running: sample/core/t_ctest.js, path: tests/core/t_ctest.js',
|
|
20
20
|
'\x1B[32mOk:\x1B[0m Mocked!, got: mocked',
|
|
21
21
|
'>sample/core/t_ctest.js completed in',
|
|
22
22
|
'\x1B[38;5;243mCompleted\x1B[0m sample/core',
|
|
23
|
-
'Testsuite: shutdown',
|
|
24
23
|
'Elapsed:',
|
|
24
|
+
'Testsuite: shutdown',
|
|
25
25
|
'\x1B[102mSuccess!\x1B[0m Total: 2',
|
|
26
26
|
'\x1B[38;5;243mCompleted\x1B[0m sample/',
|
|
27
|
-
'Testsuite: shutdown',
|
|
28
27
|
'Elapsed:',
|
|
28
|
+
'Testsuite: shutdown',
|
|
29
29
|
],
|
|
30
30
|
'stdout',
|
|
31
31
|
);
|
package/tests/e2e/t_single.js
CHANGED
|
@@ -13,12 +13,12 @@ export async function test() {
|
|
|
13
13
|
'\x1B[32mOk:\x1B[0m Webdriver Works!',
|
|
14
14
|
'>sample/firefox/t_test.js completed in',
|
|
15
15
|
'\x1B[38;5;243mCompleted\x1B[0m sample/firefox',
|
|
16
|
-
'Testsuite: shutdown',
|
|
17
16
|
'Elapsed:',
|
|
17
|
+
'Testsuite: shutdown',
|
|
18
18
|
'\x1B[102mSuccess!\x1B[0m Total: 1',
|
|
19
19
|
'\x1B[38;5;243mCompleted\x1B[0m sample/',
|
|
20
|
-
'Testsuite: shutdown',
|
|
21
20
|
'Elapsed:',
|
|
21
|
+
'Testsuite: shutdown',
|
|
22
22
|
],
|
|
23
23
|
'stdout',
|
|
24
24
|
);
|
|
@@ -13,8 +13,8 @@ export async function test() {
|
|
|
13
13
|
'\x1B[32mOk:\x1B[0m Webdriver Works!',
|
|
14
14
|
'>sample/firefox/t_test.js completed in',
|
|
15
15
|
'\x1B[38;5;243mCompleted\x1B[0m sample/firefox',
|
|
16
|
-
'Testsuite: shutdown',
|
|
17
16
|
'Elapsed:',
|
|
17
|
+
'Testsuite: shutdown',
|
|
18
18
|
'\x1B[38;5;99mStarted\x1B[0m sample/chrome',
|
|
19
19
|
'!Running: sample/chrome/t_test.js, path: tests/t_test.js',
|
|
20
20
|
'\x1B[32mOk:\x1B[0m Webdriver Works!',
|
|
@@ -22,8 +22,8 @@ export async function test() {
|
|
|
22
22
|
'\x1B[38;5;243mCompleted\x1B[0m sample/chrome',
|
|
23
23
|
'\x1B[102mSuccess!\x1B[0m Total: 2',
|
|
24
24
|
'\x1B[38;5;243mCompleted\x1B[0m sample/',
|
|
25
|
-
'Testsuite: shutdown',
|
|
26
25
|
'Elapsed:',
|
|
26
|
+
'Testsuite: shutdown',
|
|
27
27
|
],
|
|
28
28
|
'stdout',
|
|
29
29
|
);
|
|
@@ -14,8 +14,8 @@ export async function test() {
|
|
|
14
14
|
'\x1B[32mOk:\x1B[0m Webdriver Works!',
|
|
15
15
|
'>sample/firefox/t_test.js completed in',
|
|
16
16
|
'\x1B[38;5;243mCompleted\x1B[0m sample/firefox',
|
|
17
|
-
'Testsuite: shutdown',
|
|
18
17
|
'Elapsed:',
|
|
18
|
+
'Testsuite: shutdown',
|
|
19
19
|
'\x1B[38;5;99mStarted\x1B[0m sample/chrome',
|
|
20
20
|
'!Running: sample/chrome/t_test.js, path: tests/t_test.js',
|
|
21
21
|
'\x1B[32mOk:\x1B[0m Webdriver Works!',
|
|
@@ -23,8 +23,8 @@ export async function test() {
|
|
|
23
23
|
'\x1B[38;5;243mCompleted\x1B[0m sample/chrome',
|
|
24
24
|
'\x1B[102mSuccess!\x1B[0m Total: 2',
|
|
25
25
|
'\x1B[38;5;243mCompleted\x1B[0m sample/',
|
|
26
|
-
'Testsuite: shutdown',
|
|
27
26
|
'Elapsed:',
|
|
27
|
+
'Testsuite: shutdown',
|
|
28
28
|
],
|
|
29
29
|
'stdout',
|
|
30
30
|
);
|
|
@@ -19,13 +19,13 @@ export async function test() {
|
|
|
19
19
|
'\x1B[32mOk:\x1B[0m Webdriver Works!',
|
|
20
20
|
'>sample/ui/firefox/t_test.js completed in',
|
|
21
21
|
'\x1B[38;5;243mCompleted\x1B[0m sample/ui/firefox',
|
|
22
|
-
'Testsuite: shutdown',
|
|
23
22
|
'Elapsed:',
|
|
23
|
+
'Testsuite: shutdown',
|
|
24
24
|
'\x1B[38;5;243mCompleted\x1B[0m sample/ui',
|
|
25
25
|
'\x1B[102mSuccess!\x1B[0m Total: 2',
|
|
26
26
|
'\x1B[38;5;243mCompleted\x1B[0m sample/',
|
|
27
|
-
'Testsuite: shutdown',
|
|
28
27
|
'Elapsed:',
|
|
28
|
+
'Testsuite: shutdown',
|
|
29
29
|
],
|
|
30
30
|
'stdout',
|
|
31
31
|
);
|
|
@@ -19,8 +19,8 @@ export async function test() {
|
|
|
19
19
|
'\x1B[32mOk:\x1B[0m Webdriver Works!',
|
|
20
20
|
'>sample/ui/firefox/t_test.js completed in',
|
|
21
21
|
'\x1B[38;5;243mCompleted\x1B[0m sample/ui/firefox',
|
|
22
|
-
'Testsuite: shutdown',
|
|
23
22
|
'Elapsed:',
|
|
23
|
+
'Testsuite: shutdown',
|
|
24
24
|
'\x1B[38;5;99mStarted\x1B[0m sample/ui/chrome',
|
|
25
25
|
'!Running: sample/ui/chrome/t_test.js, path: tests/ui/t_test.js',
|
|
26
26
|
'\x1B[32mOk:\x1B[0m Webdriver Works!',
|
|
@@ -29,8 +29,8 @@ export async function test() {
|
|
|
29
29
|
'\x1B[38;5;243mCompleted\x1B[0m sample/ui',
|
|
30
30
|
'\x1B[102mSuccess!\x1B[0m Total: 3',
|
|
31
31
|
'\x1B[38;5;243mCompleted\x1B[0m sample/',
|
|
32
|
-
'Testsuite: shutdown',
|
|
33
32
|
'Elapsed:',
|
|
33
|
+
'Testsuite: shutdown',
|
|
34
34
|
],
|
|
35
35
|
'stdout',
|
|
36
36
|
);
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { is, MockSeries } from '../test.js';
|
|
2
|
+
|
|
3
|
+
export async function test() {
|
|
4
|
+
// Test that buildSubtests only processes subfolders that match patterns
|
|
5
|
+
// This test tracks which directories are actually accessed to verify the optimization
|
|
6
|
+
|
|
7
|
+
const accessedDirs = [];
|
|
8
|
+
|
|
9
|
+
class TrackingMockSeries extends MockSeries {
|
|
10
|
+
loadTestMeta(folder) {
|
|
11
|
+
accessedDirs.push(folder);
|
|
12
|
+
return super.loadTestMeta(folder);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getTestFileList(folder) {
|
|
16
|
+
accessedDirs.push(folder);
|
|
17
|
+
return super.getTestFileList(folder);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const ts = {
|
|
22
|
+
'tests': {
|
|
23
|
+
meta: {
|
|
24
|
+
folders: ['unit', 'integration', 'e2e'],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
'tests/unit': {
|
|
28
|
+
meta: {
|
|
29
|
+
folders: ['base', 'core'],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
'tests/unit/base': {
|
|
33
|
+
files: ['t_test1.js'],
|
|
34
|
+
},
|
|
35
|
+
'tests/unit/base/t_test1.js': {
|
|
36
|
+
test() {},
|
|
37
|
+
},
|
|
38
|
+
'tests/unit/core': {
|
|
39
|
+
files: ['t_test2.js'],
|
|
40
|
+
},
|
|
41
|
+
'tests/unit/core/t_test2.js': {
|
|
42
|
+
test() {},
|
|
43
|
+
},
|
|
44
|
+
'tests/integration': {
|
|
45
|
+
files: ['t_integration.js'],
|
|
46
|
+
},
|
|
47
|
+
'tests/integration/t_integration.js': {
|
|
48
|
+
test() {},
|
|
49
|
+
},
|
|
50
|
+
'tests/e2e': {
|
|
51
|
+
files: ['t_e2e.js'],
|
|
52
|
+
},
|
|
53
|
+
'tests/e2e/t_e2e.js': {
|
|
54
|
+
test() {},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const series = new TrackingMockSeries([], { ts });
|
|
59
|
+
|
|
60
|
+
// Test 1: When targeting a specific test, only relevant folders should be processed
|
|
61
|
+
accessedDirs.length = 0; // Clear the array
|
|
62
|
+
|
|
63
|
+
const tests = await series.build({
|
|
64
|
+
patterns: [
|
|
65
|
+
{
|
|
66
|
+
path: 'tests/unit/base/t_test1.js',
|
|
67
|
+
webdriver: '',
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
folder: 'tests',
|
|
71
|
+
virtual_folder: 'mac',
|
|
72
|
+
});
|
|
73
|
+
series.shutdown();
|
|
74
|
+
|
|
75
|
+
// Should only build the unit folder and its relevant subfolders
|
|
76
|
+
// Should NOT build integration or e2e folders
|
|
77
|
+
const testNames = getAllTestNames(tests);
|
|
78
|
+
|
|
79
|
+
// Should include the targeted test and its path
|
|
80
|
+
is(
|
|
81
|
+
testNames.includes('mac/unit/base/t_test1.js'),
|
|
82
|
+
true,
|
|
83
|
+
'Should include the targeted test',
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// Should NOT include tests from unrelated folders
|
|
87
|
+
is(
|
|
88
|
+
testNames.includes('mac/integration/t_integration.js'),
|
|
89
|
+
false,
|
|
90
|
+
'Should not include integration tests when targeting unit test',
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
is(
|
|
94
|
+
testNames.includes('mac/e2e/t_e2e.js'),
|
|
95
|
+
false,
|
|
96
|
+
'Should not include e2e tests when targeting unit test',
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// Check directory access optimization - this will fail with commented optimization
|
|
100
|
+
is(
|
|
101
|
+
accessedDirs.includes('tests/integration'),
|
|
102
|
+
false,
|
|
103
|
+
'Should not access integration directory when targeting unit test',
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
is(
|
|
107
|
+
accessedDirs.includes('tests/e2e'),
|
|
108
|
+
false,
|
|
109
|
+
'Should not access e2e directory when targeting unit test',
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// Test 2: When no patterns specified, all folders should be processed
|
|
113
|
+
accessedDirs.length = 0; // Clear the array
|
|
114
|
+
|
|
115
|
+
const allTests = await series.build({
|
|
116
|
+
patterns: [],
|
|
117
|
+
folder: 'tests',
|
|
118
|
+
virtual_folder: 'mac',
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const allTestNames = getAllTestNames(allTests);
|
|
122
|
+
|
|
123
|
+
// Should include all tests when no patterns specified
|
|
124
|
+
is(
|
|
125
|
+
allTestNames.includes('mac/unit/base/t_test1.js'),
|
|
126
|
+
true,
|
|
127
|
+
'Should include unit test when no patterns',
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
is(
|
|
131
|
+
allTestNames.includes('mac/integration/t_integration.js'),
|
|
132
|
+
true,
|
|
133
|
+
'Should include integration test when no patterns',
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
is(
|
|
137
|
+
allTestNames.includes('mac/e2e/t_e2e.js'),
|
|
138
|
+
true,
|
|
139
|
+
'Should include e2e test when no patterns',
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// When no patterns, all directories should be accessed
|
|
143
|
+
is(
|
|
144
|
+
accessedDirs.includes('tests/integration'),
|
|
145
|
+
true,
|
|
146
|
+
'Should access integration directory when no patterns specified',
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
is(
|
|
150
|
+
accessedDirs.includes('tests/e2e'),
|
|
151
|
+
true,
|
|
152
|
+
'Should access e2e directory when no patterns specified',
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function getAllTestNames(tests) {
|
|
157
|
+
const names = [];
|
|
158
|
+
|
|
159
|
+
function collectNames(testList) {
|
|
160
|
+
for (const test of testList) {
|
|
161
|
+
if (test.subtests) {
|
|
162
|
+
collectNames(test.subtests);
|
|
163
|
+
} else if (
|
|
164
|
+
test.name &&
|
|
165
|
+
!test.name.includes('/init') &&
|
|
166
|
+
!test.name.includes('/uninit')
|
|
167
|
+
) {
|
|
168
|
+
names.push(test.name);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
collectNames(tests);
|
|
174
|
+
return names;
|
|
175
|
+
}
|
package/tests/series/meta.js
CHANGED
|
@@ -26,6 +26,7 @@ export async function test() {
|
|
|
26
26
|
'>t_testo.js has 1 warnings(s)',
|
|
27
27
|
'>t_testo.js completed in',
|
|
28
28
|
'\x1B[38;5;243mCompleted\x1B[0m tests/',
|
|
29
|
+
'Testsuite: shutdown',
|
|
29
30
|
];
|
|
30
31
|
let expected_stderr = [];
|
|
31
32
|
|
|
@@ -77,6 +78,7 @@ export async function test() {
|
|
|
77
78
|
'>t_testo_2.js has 3 warnings(s)',
|
|
78
79
|
'>t_testo_2.js completed in',
|
|
79
80
|
'\x1B[38;5;243mCompleted\x1B[0m tests/',
|
|
81
|
+
'Testsuite: shutdown',
|
|
80
82
|
];
|
|
81
83
|
expected_stderr = [];
|
|
82
84
|
|
|
@@ -33,6 +33,7 @@ export async function test() {
|
|
|
33
33
|
'!Running: t_testo.js, path: t_testo.js',
|
|
34
34
|
'>t_testo.js completed in',
|
|
35
35
|
'\x1B[38;5;243mCompleted\x1B[0m tests/',
|
|
36
|
+
'Testsuite: shutdown',
|
|
36
37
|
],
|
|
37
38
|
[
|
|
38
39
|
'\x1B[31mFailed:\x1B[0m Server busy',
|
|
@@ -79,6 +80,7 @@ export async function test() {
|
|
|
79
80
|
'>t_testo.js has 1 warnings(s)',
|
|
80
81
|
'>t_testo.js completed in',
|
|
81
82
|
'\x1B[38;5;243mCompleted\x1B[0m tests/',
|
|
83
|
+
'Testsuite: shutdown',
|
|
82
84
|
],
|
|
83
85
|
[],
|
|
84
86
|
'no perma but intermittent',
|
|
@@ -18,6 +18,7 @@ export async function test() {
|
|
|
18
18
|
'\x1B[32mOk:\x1B[0m Successio!',
|
|
19
19
|
'>t_testo.js completed in',
|
|
20
20
|
'\x1B[38;5;243mCompleted\x1B[0m tests/',
|
|
21
|
+
'Testsuite: shutdown',
|
|
21
22
|
],
|
|
22
23
|
[],
|
|
23
24
|
'success',
|
|
@@ -53,6 +54,7 @@ export async function test() {
|
|
|
53
54
|
'\x1B[32mOk:\x1B[0m Successio!',
|
|
54
55
|
'>t_testo.js completed in',
|
|
55
56
|
'\x1B[38;5;243mCompleted\x1B[0m tests/',
|
|
57
|
+
'Testsuite: shutdown',
|
|
56
58
|
],
|
|
57
59
|
[],
|
|
58
60
|
'success #2',
|
|
@@ -31,9 +31,9 @@ export async function test() {
|
|
|
31
31
|
'\x1B[41m\x1B[37mFailed!\x1B[0m Passed: 0. Failed: 1',
|
|
32
32
|
'\x1B[38;5;243mCompleted\x1B[0m mac/',
|
|
33
33
|
'Logs are written to',
|
|
34
|
-
'Testsuite: shutdown',
|
|
35
34
|
'Elapsed:',
|
|
36
35
|
'Logs are written to',
|
|
36
|
+
'Testsuite: shutdown',
|
|
37
37
|
];
|
|
38
38
|
|
|
39
39
|
const expected_stderr = [
|
|
@@ -55,9 +55,9 @@ export async function test() {
|
|
|
55
55
|
'\x1B[102mSuccess!\x1B[0m Total: 2',
|
|
56
56
|
'\x1B[38;5;243mCompleted\x1B[0m mac/',
|
|
57
57
|
'Logs are written to',
|
|
58
|
-
'Testsuite: shutdown',
|
|
59
58
|
'Elapsed:',
|
|
60
59
|
'Logs are written to',
|
|
60
|
+
'Testsuite: shutdown',
|
|
61
61
|
],
|
|
62
62
|
[],
|
|
63
63
|
'nested',
|
|
@@ -66,9 +66,9 @@ export async function test() {
|
|
|
66
66
|
'\x1B[41m\x1B[37mFailed!\x1B[0m Passed: 0. Failed: 1',
|
|
67
67
|
'\x1B[38;5;243mCompleted\x1B[0m mac/',
|
|
68
68
|
'Logs are written to',
|
|
69
|
-
'Testsuite: shutdown',
|
|
70
69
|
'Elapsed:',
|
|
71
70
|
'Logs are written to',
|
|
71
|
+
'Testsuite: shutdown',
|
|
72
72
|
];
|
|
73
73
|
|
|
74
74
|
const expected_stderr = [
|
|
@@ -84,9 +84,9 @@ export async function test() {
|
|
|
84
84
|
'\x1B[102mSuccess!\x1B[0m Total: 1',
|
|
85
85
|
'\x1B[38;5;243mCompleted\x1B[0m mac/',
|
|
86
86
|
'Logs are written to',
|
|
87
|
-
'Testsuite: shutdown',
|
|
88
87
|
'Elapsed:',
|
|
89
88
|
'Logs are written to',
|
|
89
|
+
'Testsuite: shutdown',
|
|
90
90
|
];
|
|
91
91
|
|
|
92
92
|
const expected_stderr = [
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { is_test_output, success } from '../../base/test.js';
|
|
2
|
+
import { log } from '../../../logging/logging.js';
|
|
3
|
+
import { MockSeries } from '../mock_series.js';
|
|
4
|
+
|
|
5
|
+
// Mock servicer that logs to console for output validation
|
|
6
|
+
class MockServicer {
|
|
7
|
+
constructor(type) {
|
|
8
|
+
this.type = type;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async start(service) {
|
|
12
|
+
log(`MockServicer:${this.type} starting ${service}`);
|
|
13
|
+
return { started: service, type: this.type };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async stop(service) {
|
|
17
|
+
log(`MockServicer:${this.type} stopping ${service}`);
|
|
18
|
+
return { stopped: service, type: this.type };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async shutdown() {
|
|
22
|
+
log(`MockServicer:${this.type} shutdown`);
|
|
23
|
+
return { shutdown: true, type: this.type };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async ontest() {
|
|
27
|
+
// Optional: log test notifications
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Extended MockSeries that uses our logging servicer
|
|
33
|
+
class MockSeriesWithServicer extends MockSeries {
|
|
34
|
+
createServicer(type) {
|
|
35
|
+
return new MockServicer(type || 'default');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function test() {
|
|
40
|
+
const ts = {
|
|
41
|
+
'tests': {
|
|
42
|
+
meta: {
|
|
43
|
+
servicer: 'docker',
|
|
44
|
+
services: ['mysql', 'redis'],
|
|
45
|
+
},
|
|
46
|
+
files: ['t_example.js'],
|
|
47
|
+
},
|
|
48
|
+
'tests/t_example.js': {
|
|
49
|
+
test() {
|
|
50
|
+
success('Servicer test example works');
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
await is_test_output(
|
|
56
|
+
() => MockSeriesWithServicer.run([], { ts }),
|
|
57
|
+
[
|
|
58
|
+
'Settings: no temporary storage dir',
|
|
59
|
+
'Settings: logging into /tmp',
|
|
60
|
+
'Settings: chrome webdrivers',
|
|
61
|
+
'\x1B[38;5;99mStarted\x1B[0m mac/',
|
|
62
|
+
'!Running: mac/init, path: tests/meta.js',
|
|
63
|
+
'MockServicer:docker starting mysql',
|
|
64
|
+
'MockServicer:docker starting redis',
|
|
65
|
+
'>mac/init completed in',
|
|
66
|
+
'!Running: mac/t_example.js, path: tests/t_example.js',
|
|
67
|
+
'\x1B[32mOk:\x1B[0m Servicer test example works',
|
|
68
|
+
'>mac/t_example.js completed in',
|
|
69
|
+
'!Running: mac/uninit, path: tests/meta.js',
|
|
70
|
+
'MockServicer:docker stopping redis',
|
|
71
|
+
'MockServicer:docker stopping mysql',
|
|
72
|
+
'MockServicer:docker shutdown',
|
|
73
|
+
'>mac/uninit completed in',
|
|
74
|
+
'\x1B[102mSuccess!\x1B[0m Total: 1',
|
|
75
|
+
'\x1B[38;5;243mCompleted\x1B[0m mac/',
|
|
76
|
+
'Logs are written to',
|
|
77
|
+
'Elapsed:',
|
|
78
|
+
'Logs are written to',
|
|
79
|
+
'Testsuite: shutdown'
|
|
80
|
+
],
|
|
81
|
+
[],
|
|
82
|
+
'servicer lifecycle',
|
|
83
|
+
);
|
|
84
|
+
}
|