@camperaid/watest 2.5.0 → 2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/README.md +274 -129
  2. package/bin/watest.js +36 -2
  3. package/core/base.js +10 -3
  4. package/core/core.js +43 -15
  5. package/core/deps.js +211 -0
  6. package/core/{process_args.js → process-args.js} +8 -0
  7. package/core/series.js +70 -28
  8. package/core/settings.js +28 -10
  9. package/core/system.js +68 -0
  10. package/core/util.js +1 -1
  11. package/eslint.config.js +1 -1
  12. package/index.js +15 -3
  13. package/interfaces/servicer.js +13 -3
  14. package/logging/logging.js +1 -1
  15. package/logging/logpipe.js +38 -21
  16. package/package.json +1 -1
  17. package/tests/base/{t_core.js → t-core.js} +10 -3
  18. package/tests/base/t-system.js +59 -0
  19. package/tests/base/{t_throws.js → t-throws.js} +67 -0
  20. package/tests/base/test.js +1 -2
  21. package/tests/deps/samples/nested/.watestrc.js +3 -0
  22. package/tests/deps/samples/nested/tests/meta.js +1 -0
  23. package/tests/deps/samples/nested/tests/services/meta.js +1 -0
  24. package/tests/deps/samples/nested/tests/services/ws/meta.js +1 -0
  25. package/tests/deps/samples/nested/tests/services/ws/webservice/meta.js +2 -0
  26. package/tests/deps/samples/nested/tests/services/ws/webservice/t-ws.js +3 -0
  27. package/tests/deps/samples/unified/.watestrc.js +3 -0
  28. package/tests/deps/samples/unified/tests/e2e/meta.js +4 -0
  29. package/tests/deps/samples/unified/tests/e2e/pages/meta.js +1 -0
  30. package/tests/deps/samples/unified/tests/e2e/pages/t-example.js +3 -0
  31. package/tests/deps/samples/unified/tests/e2e/t-example.js +3 -0
  32. package/tests/deps/samples/unified/tests/integration/meta.js +3 -0
  33. package/tests/deps/samples/unified/tests/lib/meta.js +0 -0
  34. package/tests/deps/samples/unified/tests/lib/t-example.js +3 -0
  35. package/tests/deps/samples/unified/tests/meta.js +8 -0
  36. package/tests/deps/samples/unified/tests/services/meta.js +3 -0
  37. package/tests/deps/samples/unified/tests/services/request/meta.js +1 -0
  38. package/tests/deps/samples/unified/tests/services/t-example.js +3 -0
  39. package/tests/deps/t-parse-cell-syntax.js +6 -0
  40. package/tests/deps/t-parse-grid-args.js +11 -0
  41. package/tests/deps/t-watest-deps.js +37 -0
  42. package/tests/deps/t-watest-grid.js +122 -0
  43. package/tests/deps/test.js +63 -0
  44. package/tests/e2e/samples/folder/package-lock.json +3 -1
  45. package/tests/e2e/samples/loader/package-lock.json +3 -1
  46. package/tests/e2e/samples/loader/tests/meta.js +1 -1
  47. package/tests/e2e/samples/{loader_mixed → loader-mixed}/package-lock.json +3 -1
  48. package/tests/e2e/samples/{loader_multiple/tests/core → loader-mixed/tests/ui}/meta.js +1 -1
  49. package/tests/e2e/samples/{loader_multiple → loader-multiple}/package-lock.json +3 -1
  50. package/tests/e2e/samples/{loader_multiple → loader-multiple}/tests/base/meta.js +1 -1
  51. package/tests/e2e/samples/{loader_mixed/tests/ui → loader-multiple/tests/core}/meta.js +1 -1
  52. package/tests/e2e/samples/single/package-lock.json +3 -1
  53. package/tests/e2e/samples/{wd_mixed → wd-mixed}/package-lock.json +3 -1
  54. package/tests/e2e/samples/{wd_single → wd-single}/package-lock.json +3 -1
  55. package/tests/e2e/{t_folder.js → t-folder.js} +3 -3
  56. package/tests/e2e/{t_loader_mixed.js → t-loader-mixed.js} +7 -7
  57. package/tests/e2e/{t_loader_multiple_patterns.js → t-loader-multiple-patterns.js} +9 -9
  58. package/tests/e2e/{t_loader_multiple.js → t-loader-multiple.js} +8 -8
  59. package/tests/e2e/{t_loader.js → t-loader.js} +4 -4
  60. package/tests/e2e/{t_single.js → t-single.js} +3 -3
  61. package/tests/e2e/{t_wd_firefox_chrome_pattern.js → t-wd-firefox-chrome-pattern.js} +8 -8
  62. package/tests/e2e/{t_wd_firefox_chrome.js → t-wd-firefox-chrome.js} +7 -7
  63. package/tests/e2e/{t_wd_firefox.js → t-wd-firefox.js} +5 -5
  64. package/tests/e2e/{t_wd_mixed_firefox_chrome.js → t-wd-mixed-firefox-chrome.js} +9 -9
  65. package/tests/e2e/{t_wd_mixed_firefox.js → t-wd-mixed-firefox.js} +7 -7
  66. package/tests/meta.js +1 -1
  67. package/tests/series/build/t-pattern-filtering.js +175 -0
  68. package/tests/series/build/{t_webdriver_services.js → t-webdriver-services.js} +1 -0
  69. package/tests/series/logging/{t_failures.js → t-failures.js} +1 -1
  70. package/tests/series/logging/{t_success.js → t-success.js} +1 -1
  71. package/tests/series/logging/{t_verify.js → t-verify.js} +2 -2
  72. package/tests/series/meta.js +1 -0
  73. package/tests/series/perform/{t_failure_notest.js → t-failure-notest.js} +1 -0
  74. package/tests/series/perform/{t_failure.js → t-failure.js} +1 -0
  75. package/tests/series/perform/{t_intermittent_global.js → t-intermittent-global.js} +1 -0
  76. package/tests/series/perform/{t_intermittent.js → t-intermittent.js} +2 -0
  77. package/tests/series/perform/{t_missing_perma.js → t-missing-perma.js} +2 -0
  78. package/tests/series/perform/{t_nested.js → t-nested.js} +1 -0
  79. package/tests/series/perform/{t_perma.js → t-perma.js} +1 -0
  80. package/tests/series/perform/{t_success.js → t-success.js} +2 -0
  81. package/tests/series/servicer/mock-servicer.js +68 -0
  82. package/tests/series/servicer/t-nested-servicer-lifecycle.js +99 -0
  83. package/tests/series/servicer/t-servicer-no-services.js +53 -0
  84. package/tests/series/servicer/t-servicer-type-switching.js +139 -0
  85. package/tests/series/servicer/t-servicer.js +51 -0
  86. package/tests/series/test.js +1 -1
  87. package/tests/test.js +2 -0
  88. package/tests/webdriver/test.js +3 -3
  89. package/webdriver/{control_driver.js → control-driver.js} +1 -1
  90. package/webdriver/{driver_base.js → driver-base.js} +3 -1
  91. package/webdriver/driver.js +1 -1
  92. package/webdriver/session.js +57 -30
  93. package/tests/base/{t_api.js → t-api.js} +0 -0
  94. package/tests/base/{t_contains.js → t-contains.js} +0 -0
  95. package/tests/base/{t_format.js → t-format.js} +0 -0
  96. package/tests/base/{t_is_object.js → t-is-object.js} +0 -0
  97. package/tests/base/{t_is_primitive.js → t-is-primitive.js} +0 -0
  98. package/tests/base/{t_is_string.js → t-is-string.js} +0 -0
  99. package/tests/base/{t_is.js → t-is.js} +0 -0
  100. package/tests/base/{t_ok.js → t-ok.js} +0 -0
  101. package/tests/base/{t_stringify.js → t-stringify.js} +0 -0
  102. package/tests/base/{t_test_.js → t-test-.js} +0 -0
  103. package/tests/e2e/samples/folder/tests/unit/{t_test.js → t-test.js} +0 -0
  104. package/tests/e2e/samples/{loader_multiple/tests/module_mock.js → loader/tests/module-mock.js} +0 -0
  105. package/tests/e2e/samples/loader/tests/{t_test.js → t-test.js} +0 -0
  106. package/tests/e2e/samples/{loader_mixed → loader-mixed}/.watestrc.js +0 -0
  107. package/tests/e2e/samples/{loader_mixed → loader-mixed}/package.json +0 -0
  108. package/tests/e2e/samples/{loader_mixed → loader-mixed}/tests/meta.js +0 -0
  109. package/tests/e2e/samples/{loader/tests/module_mock.js → loader-mixed/tests/module-mock.js} +0 -0
  110. package/tests/e2e/samples/{loader_mixed → loader-mixed}/tests/module.js +0 -0
  111. package/tests/e2e/samples/{loader_mixed/tests/ui/t_test.js → loader-mixed/tests/ui/t-test.js} +0 -0
  112. package/tests/e2e/samples/{loader_mixed/tests/unit/t_test.js → loader-mixed/tests/unit/t-test.js} +0 -0
  113. package/tests/e2e/samples/{loader_multiple → loader-multiple}/.watestrc.js +0 -0
  114. package/tests/e2e/samples/{loader_multiple → loader-multiple}/package.json +0 -0
  115. package/tests/e2e/samples/{loader_multiple/tests/base/t_btest.js → loader-multiple/tests/base/t-btest.js} +0 -0
  116. package/tests/e2e/samples/{loader_multiple/tests/core/t_ctest.js → loader-multiple/tests/core/t-ctest.js} +0 -0
  117. package/tests/e2e/samples/{loader_multiple → loader-multiple}/tests/meta.js +0 -0
  118. package/tests/e2e/samples/{loader_mixed/tests/module_mock.js → loader-multiple/tests/module-mock.js} +0 -0
  119. package/tests/e2e/samples/{loader_multiple → loader-multiple}/tests/module.js +0 -0
  120. package/tests/e2e/samples/single/tests/{t_test.js → t-test.js} +0 -0
  121. package/tests/e2e/samples/{wd_mixed → wd-mixed}/.watestrc.js +0 -0
  122. package/tests/e2e/samples/{wd_mixed → wd-mixed}/package.json +0 -0
  123. package/tests/e2e/samples/{wd_mixed → wd-mixed}/tests/meta.js +0 -0
  124. package/tests/e2e/samples/{wd_mixed → wd-mixed}/tests/ui/meta.js +0 -0
  125. package/tests/e2e/samples/{wd_mixed/tests/ui/t_test.js → wd-mixed/tests/ui/t-test.js} +0 -0
  126. package/tests/e2e/samples/{wd_mixed/tests/unit/t_test.js → wd-mixed/tests/unit/t-test.js} +0 -0
  127. package/tests/e2e/samples/{wd_single → wd-single}/.watestrc.js +0 -0
  128. package/tests/e2e/samples/{wd_single → wd-single}/package.json +0 -0
  129. package/tests/e2e/samples/{wd_single → wd-single}/tests/meta.js +0 -0
  130. package/tests/e2e/samples/{wd_single/tests/t_test.js → wd-single/tests/t-test.js} +0 -0
  131. package/tests/series/build/{t_adjust_names_webdriver.js → t-adjust-names-webdriver.js} +0 -0
  132. package/tests/series/build/{t_adjust_names.js → t-adjust-names.js} +0 -0
  133. package/tests/series/build/{t_expected_failures.js → t-expected-failures.js} +0 -0
  134. package/tests/series/build/{t_loader_mixed.js → t-loader-mixed.js} +0 -0
  135. package/tests/series/build/{t_loader.js → t-loader.js} +0 -0
  136. package/tests/series/build/{t_mixed.js → t-mixed.js} +0 -0
  137. package/tests/series/build/{t_nested.js → t-nested.js} +0 -0
  138. package/tests/series/build/{t_patterns_loader.js → t-patterns-loader.js} +0 -0
  139. package/tests/series/build/{t_patterns_webdriver.js → t-patterns-webdriver.js} +0 -0
  140. package/tests/series/build/{t_webdriver_firefox_mixed.js → t-webdriver-firefox-mixed.js} +0 -0
  141. package/tests/series/build/{t_webdriver_nested.js → t-webdriver-nested.js} +0 -0
  142. package/tests/series/build/{t_webdriver.js → t-webdriver.js} +0 -0
  143. package/tests/series/generic/{t_failures_info.js → t-failures-info.js} +0 -0
  144. package/tests/series/{mock_series.js → mock-series.js} +0 -0
  145. package/tests/series/run/{t_debunk_failure.js → t-debunk-failure.js} +1 -1
  146. package/tests/series/run/{t_debunk_success.js → t-debunk-success.js} +1 -1
  147. package/tests/series/run/{t_nested.js → t-nested.js} +1 -1
  148. package/tests/series/run/{t_verify_webdriver.js → t-verify-webdriver.js} +1 -1
  149. package/tests/series/run/{t_verify.js → t-verify.js} +1 -1
  150. /package/tests/webdriver/{t_app_driver_selectors.js → t-app-driver-selectors.js} +0 -0
  151. /package/tests/webdriver/{t_app_driver.js → t-app-driver.js} +0 -0
  152. /package/tests/webdriver/{t_attribute_all.js → t-attribute-all.js} +0 -0
  153. /package/tests/webdriver/{t_attribute.js → t-attribute.js} +0 -0
  154. /package/tests/webdriver/{t_doubleclick.js → t-doubleclick.js} +0 -0
  155. /package/tests/webdriver/{t_doubleclickat.js → t-doubleclickat.js} +0 -0
  156. /package/tests/webdriver/{t_execute.js → t-execute.js} +0 -0
  157. /package/tests/webdriver/{t_if_has_elements.js → t-if-has-elements.js} +0 -0
  158. /package/tests/webdriver/{t_if_no_elements.js → t-if-no-elements.js} +0 -0
  159. /package/tests/webdriver/{t_no_elements_or_not_visible.js → t-no-elements-or-not-visible.js} +0 -0
  160. /package/tests/webdriver/{t_properties.js → t-properties.js} +0 -0
  161. /package/tests/webdriver/{t_script.js → t-script.js} +0 -0
  162. /package/tests/webdriver/{t_select_all.js → t-select-all.js} +0 -0
  163. /package/tests/webdriver/{t_selection.js → t-selection.js} +0 -0
  164. /package/tests/webdriver/{t_text_all.js → t-text-all.js} +0 -0
  165. /package/tests/webdriver/{t_text.js → t-text.js} +0 -0
  166. /package/webdriver/{app_driver.js → app-driver.js} +0 -0
@@ -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
+ }
@@ -8,6 +8,7 @@ export async function test() {
8
8
  'e2e': {
9
9
  meta: {
10
10
  webdriver: true,
11
+ servicer: 'docker',
11
12
  services: ['db'],
12
13
  },
13
14
  files: ['t_testo.js', 't_presto.js'],
@@ -14,7 +14,7 @@ import {
14
14
  running_checker,
15
15
  } from '../test.js';
16
16
 
17
- import settings from '../../../core/settings.js';
17
+ import { settings } from '../../../core/settings.js';
18
18
 
19
19
  export async function test() {
20
20
  const ts = {
@@ -11,7 +11,7 @@ import {
11
11
  running_checker,
12
12
  } from '../test.js';
13
13
 
14
- import settings from '../../../core/settings.js';
14
+ import { settings } from '../../../core/settings.js';
15
15
 
16
16
  export async function test() {
17
17
  const ts = {
@@ -6,7 +6,7 @@ import {
6
6
  stderr_format_failure,
7
7
  success,
8
8
  } from '../test.js';
9
- import settings from '../../../core/settings.js';
9
+ import { settings } from '../../../core/settings.js';
10
10
 
11
11
  const completed_in = name => got => got.startsWith(`>${name} completed in`);
12
12
 
@@ -146,7 +146,7 @@ export async function test() {
146
146
  is(
147
147
  buffers,
148
148
  [
149
- ['log', ['Testsuite: shutdown', got => got.startsWith('Elapsed:')]],
149
+ ['log', [got => got.startsWith('Elapsed:')]],
150
150
  [
151
151
  'mac/log',
152
152
  [
@@ -5,4 +5,5 @@ export var folders = [
5
5
  'run',
6
6
  'logging',
7
7
  'loader',
8
+ 'servicer',
8
9
  ];
@@ -16,6 +16,7 @@ export async function test() {
16
16
  '!Running: t_testo.js, path: t_testo.js',
17
17
  '>t_testo.js completed in',
18
18
  '\x1B[38;5;243mCompleted\x1B[0m tests/',
19
+ 'Testsuite: shutdown',
19
20
  ],
20
21
  [
21
22
  '\x1B[31mFailed:\x1B[0m Neighter failure nor success in t_testo.js',
@@ -21,6 +21,7 @@ export async function test() {
21
21
  '!Running: t_testo.js, path: t_testo.js',
22
22
  '>t_testo.js completed in',
23
23
  '\x1B[38;5;243mCompleted\x1B[0m tests/',
24
+ 'Testsuite: shutdown',
24
25
  ];
25
26
  const expected_stderr = [
26
27
  '\x1B[31mFailed:\x1B[0m Failio',
@@ -71,6 +71,7 @@ export async function test() {
71
71
  '\x1B[38;5;243mCompleted\x1B[0m unit/core',
72
72
  '\x1B[38;5;243mCompleted\x1B[0m unit',
73
73
  '\x1B[38;5;243mCompleted\x1B[0m tests/',
74
+ 'Testsuite: shutdown',
74
75
  ],
75
76
  [],
76
77
  'global intermittents',
@@ -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',
@@ -50,6 +50,7 @@ export async function test() {
50
50
  '\x1B[38;5;243mCompleted\x1B[0m unit/core',
51
51
  '\x1B[38;5;243mCompleted\x1B[0m unit',
52
52
  '\x1B[38;5;243mCompleted\x1B[0m tests/',
53
+ 'Testsuite: shutdown',
53
54
  ],
54
55
  [],
55
56
  'nested',
@@ -36,6 +36,7 @@ export async function test() {
36
36
  '>t_testo.js has 1 warnings(s)',
37
37
  '>t_testo.js completed in',
38
38
  '\x1B[38;5;243mCompleted\x1B[0m tests/',
39
+ 'Testsuite: shutdown',
39
40
  ],
40
41
  [],
41
42
  'perma',
@@ -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',
@@ -0,0 +1,68 @@
1
+ import { log } from '../../../logging/logging.js';
2
+ import { MockSeries } from '../mock-series.js';
3
+
4
+ /**
5
+ * Mock servicer for testing servicer lifecycle.
6
+ * Logs all operations for test validation.
7
+ */
8
+ class MockServicer {
9
+ constructor(type) {
10
+ this.type = type;
11
+ this.services = new Set();
12
+ }
13
+
14
+ async init(services) {
15
+ log(`MockServicer:${this.type} init`);
16
+ if (services) {
17
+ for (const service of services) {
18
+ await this.start(service);
19
+ }
20
+ }
21
+ }
22
+
23
+ async deinit(services) {
24
+ log(`MockServicer:${this.type} deinit`);
25
+ if (services) {
26
+ for (const service of [...services].reverse()) {
27
+ await this.stop(service);
28
+ }
29
+ }
30
+ }
31
+
32
+ async start(service) {
33
+ log(`MockServicer:${this.type} starting ${service}`);
34
+ this.services.add(service);
35
+ return { started: service, type: this.type };
36
+ }
37
+
38
+ async stop(service) {
39
+ log(`MockServicer:${this.type} stopping ${service}`);
40
+ this.services.delete(service);
41
+ return { stopped: service, type: this.type };
42
+ }
43
+
44
+ async shutdown() {
45
+ const servicesStr =
46
+ this.services.size > 0
47
+ ? ` (services still running: ${Array.from(this.services).join(', ')})`
48
+ : '';
49
+ log(`MockServicer:${this.type} shutdown${servicesStr}`);
50
+ return { shutdown: true, type: this.type };
51
+ }
52
+
53
+ async ontest() {
54
+ return null;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * MockSeries with servicer support.
60
+ * Creates MockServicer instances for testing.
61
+ */
62
+ class MockSeriesWithServicer extends MockSeries {
63
+ createServicer(type) {
64
+ return new MockServicer(type || 'docker');
65
+ }
66
+ }
67
+
68
+ export { MockServicer, MockSeriesWithServicer };
@@ -0,0 +1,99 @@
1
+ import { is_test_output, success } from '../../base/test.js';
2
+ import { MockSeriesWithServicer } from './mock-servicer.js';
3
+
4
+ export async function test() {
5
+ const ts = {
6
+ 'tests': {
7
+ meta: {
8
+ servicer: 'docker',
9
+ services: ['db', 'cache'],
10
+ folders: ['nested'],
11
+ },
12
+ files: ['t_parent.js'],
13
+ },
14
+ 'tests/t_parent.js': {
15
+ test() {
16
+ success('Parent test works');
17
+ },
18
+ },
19
+ 'tests/nested': {
20
+ meta: {
21
+ servicer: 'docker',
22
+ services: ['worker', 'queue'],
23
+ },
24
+ files: ['t_child.js'],
25
+ },
26
+ 'tests/nested/t_child.js': {
27
+ test() {
28
+ success('Child test works');
29
+ },
30
+ },
31
+ };
32
+
33
+ await is_test_output(
34
+ () => MockSeriesWithServicer.run([], { ts }),
35
+ [
36
+ 'Settings: no temporary storage dir',
37
+ 'Settings: logging into /tmp',
38
+ 'Settings: chrome webdrivers',
39
+ '\x1B[38;5;99mStarted\x1B[0m mac/',
40
+
41
+ // Parent folder init - starts parent services
42
+ '!Running: mac/init, path: tests/meta.js',
43
+ 'MockServicer:docker init',
44
+ 'MockServicer:docker starting db',
45
+ 'MockServicer:docker starting cache',
46
+ '>mac/init completed in',
47
+
48
+ // Parent test
49
+ '!Running: mac/t_parent.js, path: tests/t_parent.js',
50
+ '\x1B[32mOk:\x1B[0m Parent test works',
51
+ '>mac/t_parent.js completed in',
52
+
53
+ // Nested folder starts
54
+ '\x1B[38;5;99mStarted\x1B[0m mac/nested',
55
+
56
+ // Nested folder init - starts child services (parent services still running)
57
+ '!Running: mac/nested/init, path: tests/nested/meta.js',
58
+ 'MockServicer:docker init',
59
+ 'MockServicer:docker starting worker',
60
+ 'MockServicer:docker starting queue',
61
+ '>mac/nested/init completed in',
62
+
63
+ // Child test
64
+ '!Running: mac/nested/t_child.js, path: tests/nested/t_child.js',
65
+ '\x1B[32mOk:\x1B[0m Child test works',
66
+ '>mac/nested/t_child.js completed in',
67
+
68
+ // Critical: nested uninit should only stop child services, NOT shutdown servicer
69
+ '!Running: mac/nested/uninit, path: tests/nested/meta.js',
70
+ 'MockServicer:docker deinit',
71
+ 'MockServicer:docker stopping queue',
72
+ 'MockServicer:docker stopping worker',
73
+ // Should NOT see "MockServicer:docker shutdown" here!
74
+ '>mac/nested/uninit completed in',
75
+
76
+ '\x1B[38;5;243mCompleted\x1B[0m mac/nested',
77
+ 'Logs are written to',
78
+
79
+ // Parent uninit - stops parent services
80
+ '!Running: mac/uninit, path: tests/meta.js',
81
+ 'MockServicer:docker deinit',
82
+ 'MockServicer:docker stopping cache',
83
+ 'MockServicer:docker stopping db',
84
+ '>mac/uninit completed in',
85
+
86
+ '\x1B[102mSuccess!\x1B[0m Total: 2',
87
+ '\x1B[38;5;243mCompleted\x1B[0m mac/',
88
+ 'Logs are written to',
89
+ 'Elapsed:',
90
+ 'Logs are written to',
91
+
92
+ // Final shutdown should happen here with no remaining services
93
+ 'MockServicer:docker shutdown',
94
+ 'Testsuite: shutdown',
95
+ ],
96
+ [],
97
+ 'nested servicer lifecycle - no premature shutdown',
98
+ );
99
+ }
@@ -0,0 +1,53 @@
1
+ import { is_test_output, success } from '../../base/test.js';
2
+ import { MockSeriesWithServicer } from './mock-servicer.js';
3
+
4
+ /**
5
+ * Test that a folder can specify servicer type without services.
6
+ * This is useful when you want to select an environment (e.g., kubernetes)
7
+ * without starting any services.
8
+ */
9
+ export async function test() {
10
+ const ts = {
11
+ 'tests': {
12
+ meta: {
13
+ servicer: 'kubernetes', // Just select the servicer type, no services
14
+ },
15
+ files: ['t_example.js'],
16
+ },
17
+ 'tests/t_example.js': {
18
+ test() {
19
+ success('Test in kubernetes environment works');
20
+ },
21
+ },
22
+ };
23
+
24
+ await is_test_output(
25
+ () => MockSeriesWithServicer.run([], { ts }),
26
+ [
27
+ 'Settings: no temporary storage dir',
28
+ 'Settings: logging into /tmp',
29
+ 'Settings: chrome webdrivers',
30
+ '\x1B[38;5;99mStarted\x1B[0m mac/',
31
+ '!Running: mac/init, path: tests/meta.js',
32
+ 'MockServicer:kubernetes init',
33
+ // No services started - init is called with undefined/empty
34
+ '>mac/init completed in',
35
+ '!Running: mac/t_example.js, path: tests/t_example.js',
36
+ '\x1B[32mOk:\x1B[0m Test in kubernetes environment works',
37
+ '>mac/t_example.js completed in',
38
+ '!Running: mac/uninit, path: tests/meta.js',
39
+ 'MockServicer:kubernetes deinit',
40
+ // No services stopped
41
+ '>mac/uninit completed in',
42
+ '\x1B[102mSuccess!\x1B[0m Total: 1',
43
+ '\x1B[38;5;243mCompleted\x1B[0m mac/',
44
+ 'Logs are written to',
45
+ 'Elapsed:',
46
+ 'Logs are written to',
47
+ 'MockServicer:kubernetes shutdown',
48
+ 'Testsuite: shutdown',
49
+ ],
50
+ [],
51
+ 'servicer without services',
52
+ );
53
+ }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Test for Servicer Type Switching
3
+ *
4
+ * Verifies that when switching between test folders with different servicer types,
5
+ * the old servicer is properly shut down before creating the new one.
6
+ *
7
+ * This prevents port conflicts when transitioning between Kubernetes and Docker servicers.
8
+ *
9
+ * Test scenario:
10
+ * 1. Folder 1: docker servicer with services
11
+ * 2. Folder 2: kubernetes servicer with services
12
+ * 3. Folder 3: back to docker servicer with services
13
+ * Expected: docker → kubernetes (shutdown docker, create k8s) → docker (shutdown k8s, create docker)
14
+ */
15
+
16
+ import { is_test_output, success } from '../../base/test.js';
17
+ import { MockSeriesWithServicer } from './mock-servicer.js';
18
+
19
+ export async function test() {
20
+ const ts = {
21
+ 'tests': {
22
+ meta: {
23
+ folders: ['folder1', 'folder2', 'folder3'],
24
+ },
25
+ },
26
+ 'tests/folder1': {
27
+ meta: {
28
+ servicer: 'docker',
29
+ services: ['db'],
30
+ },
31
+ files: ['t_test1.js'],
32
+ },
33
+ 'tests/folder2': {
34
+ meta: {
35
+ servicer: 'kubernetes',
36
+ services: ['ws'],
37
+ },
38
+ files: ['t_test2.js'],
39
+ },
40
+ 'tests/folder3': {
41
+ meta: {
42
+ servicer: 'docker',
43
+ services: ['cache'],
44
+ },
45
+ files: ['t_test3.js'],
46
+ },
47
+ 'tests/folder1/t_test1.js': {
48
+ test() {
49
+ success('Test 1 in docker folder');
50
+ },
51
+ },
52
+ 'tests/folder2/t_test2.js': {
53
+ test() {
54
+ success('Test 2 in kubernetes folder');
55
+ },
56
+ },
57
+ 'tests/folder3/t_test3.js': {
58
+ test() {
59
+ success('Test 3 back to docker');
60
+ },
61
+ },
62
+ };
63
+
64
+ await is_test_output(
65
+ () => MockSeriesWithServicer.run([], { ts }),
66
+ [
67
+ 'Settings: no temporary storage dir',
68
+ 'Settings: logging into /tmp',
69
+ 'Settings: chrome webdrivers',
70
+ '\x1B[38;5;99mStarted\x1B[0m mac/',
71
+ '\x1B[38;5;99mStarted\x1B[0m mac/folder1',
72
+
73
+ // Folder 1: docker servicer
74
+ '!Running: mac/folder1/init, path: tests/folder1/meta.js',
75
+ 'MockServicer:docker init',
76
+ 'MockServicer:docker starting db',
77
+ '>mac/folder1/init completed in',
78
+
79
+ '!Running: mac/folder1/t_test1.js, path: tests/folder1/t_test1.js',
80
+ '\x1B[32mOk:\x1B[0m Test 1 in docker folder',
81
+ '>mac/folder1/t_test1.js completed in',
82
+
83
+ '!Running: mac/folder1/uninit, path: tests/folder1/meta.js',
84
+ 'MockServicer:docker deinit',
85
+ 'MockServicer:docker stopping db',
86
+ '>mac/folder1/uninit completed in',
87
+
88
+ '\x1B[38;5;243mCompleted\x1B[0m mac/folder1',
89
+ 'Logs are written to',
90
+ '\x1B[38;5;99mStarted\x1B[0m mac/folder2',
91
+
92
+ // Folder 2: switch to kubernetes servicer (no shutdown - servicer handles conflicts)
93
+ '!Running: mac/folder2/init, path: tests/folder2/meta.js',
94
+ 'MockServicer:kubernetes init',
95
+ 'MockServicer:kubernetes starting ws',
96
+ '>mac/folder2/init completed in',
97
+
98
+ '!Running: mac/folder2/t_test2.js, path: tests/folder2/t_test2.js',
99
+ '\x1B[32mOk:\x1B[0m Test 2 in kubernetes folder',
100
+ '>mac/folder2/t_test2.js completed in',
101
+
102
+ '!Running: mac/folder2/uninit, path: tests/folder2/meta.js',
103
+ 'MockServicer:kubernetes deinit',
104
+ 'MockServicer:kubernetes stopping ws',
105
+ '>mac/folder2/uninit completed in',
106
+
107
+ '\x1B[38;5;243mCompleted\x1B[0m mac/folder2',
108
+ 'Logs are written to',
109
+ '\x1B[38;5;99mStarted\x1B[0m mac/folder3',
110
+
111
+ // Folder 3: switch back to docker servicer (no shutdown - servicer handles conflicts)
112
+ '!Running: mac/folder3/init, path: tests/folder3/meta.js',
113
+ 'MockServicer:docker init',
114
+ 'MockServicer:docker starting cache',
115
+ '>mac/folder3/init completed in',
116
+
117
+ '!Running: mac/folder3/t_test3.js, path: tests/folder3/t_test3.js',
118
+ '\x1B[32mOk:\x1B[0m Test 3 back to docker',
119
+ '>mac/folder3/t_test3.js completed in',
120
+
121
+ '!Running: mac/folder3/uninit, path: tests/folder3/meta.js',
122
+ 'MockServicer:docker deinit',
123
+ 'MockServicer:docker stopping cache',
124
+ '>mac/folder3/uninit completed in',
125
+
126
+ '\x1B[38;5;243mCompleted\x1B[0m mac/folder3',
127
+ 'Logs are written to',
128
+ '\x1B[102mSuccess!\x1B[0m Total: 3',
129
+ '\x1B[38;5;243mCompleted\x1B[0m mac/',
130
+ 'Logs are written to',
131
+ 'Elapsed:',
132
+ 'Logs are written to',
133
+ 'MockServicer:docker shutdown',
134
+ 'Testsuite: shutdown',
135
+ ],
136
+ [],
137
+ 'servicer type switching',
138
+ );
139
+ }