@testspectra/cli 1.0.70 → 1.1.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.
Files changed (277) hide show
  1. package/LICENSE.md +48 -0
  2. package/README.md +36 -270
  3. package/bin/.testspectra-runner.hash +1 -0
  4. package/bin/spectra.js +1 -1
  5. package/bin/testspectra-runner +0 -0
  6. package/demo-app/assets/index-DPfv5_EF.js +116 -0
  7. package/demo-app/assets/index-gIwu2EMV.css +1 -0
  8. package/demo-app/index.html +2 -2
  9. package/dist/.tsbuildinfo +1 -0
  10. package/dist/commands/__tests__/cloud-run.test.d.ts +1 -0
  11. package/dist/commands/__tests__/cloud-run.test.js +93 -0
  12. package/dist/commands/__tests__/doctor.test.d.ts +1 -0
  13. package/dist/commands/__tests__/doctor.test.js +39 -0
  14. package/dist/commands/__tests__/init.test.d.ts +1 -0
  15. package/dist/commands/__tests__/init.test.js +148 -0
  16. package/dist/commands/__tests__/license.test.d.ts +1 -0
  17. package/dist/commands/__tests__/license.test.js +13 -0
  18. package/dist/commands/__tests__/refactor.test.d.ts +1 -0
  19. package/dist/commands/__tests__/refactor.test.js +64 -0
  20. package/dist/commands/__tests__/run-e2e.test.d.ts +1 -0
  21. package/dist/commands/__tests__/run-e2e.test.js +181 -0
  22. package/dist/commands/__tests__/run.test.d.ts +1 -0
  23. package/dist/commands/__tests__/run.test.js +197 -0
  24. package/dist/commands/__tests__/watch.test.d.ts +1 -0
  25. package/dist/commands/__tests__/watch.test.js +155 -0
  26. package/dist/commands/add.js +86 -85
  27. package/dist/commands/cloud-run.d.ts +11 -0
  28. package/dist/commands/cloud-run.js +118 -0
  29. package/dist/commands/demo.js +7 -7
  30. package/dist/commands/devices.d.ts +14 -2
  31. package/dist/commands/devices.js +44 -34
  32. package/dist/commands/doctor.d.ts +3 -1
  33. package/dist/commands/doctor.js +43 -264
  34. package/dist/commands/init.d.ts +1 -1
  35. package/dist/commands/init.js +206 -196
  36. package/dist/commands/install.d.ts +4 -0
  37. package/dist/commands/install.js +59 -0
  38. package/dist/commands/license.d.ts +4 -0
  39. package/dist/commands/license.js +30 -0
  40. package/dist/commands/refactor.d.ts +8 -0
  41. package/dist/commands/refactor.js +78 -0
  42. package/dist/commands/run.d.ts +22 -1
  43. package/dist/commands/run.js +252 -109
  44. package/dist/commands/sync-types.d.ts +4 -0
  45. package/dist/commands/sync-types.js +14 -0
  46. package/dist/commands/update.js +39 -43
  47. package/dist/commands/watch.d.ts +6 -0
  48. package/dist/commands/watch.js +47 -43
  49. package/dist/config/loader.d.ts +1 -1
  50. package/dist/config/loader.js +40 -25
  51. package/dist/config/schema.d.ts +117 -49
  52. package/dist/config/schema.js +41 -34
  53. package/dist/generator/__tests__/tsconfig-isolation.test.d.ts +1 -0
  54. package/dist/generator/__tests__/tsconfig-isolation.test.js +278 -0
  55. package/dist/generator/__tests__/type-generator.test.d.ts +1 -0
  56. package/dist/generator/__tests__/type-generator.test.js +386 -0
  57. package/dist/generator/index.d.ts +2 -0
  58. package/dist/generator/index.js +2 -0
  59. package/dist/generator/tsconfig-generator.d.ts +27 -0
  60. package/dist/generator/tsconfig-generator.js +391 -0
  61. package/dist/generator/type-generator.d.ts +36 -0
  62. package/dist/generator/type-generator.js +644 -0
  63. package/dist/index.d.ts +9 -5
  64. package/dist/index.js +124 -51
  65. package/dist/lifecycle/__tests__/lifecycle-engine.test.d.ts +1 -0
  66. package/dist/lifecycle/__tests__/lifecycle-engine.test.js +290 -0
  67. package/dist/lifecycle/hook-discovery.d.ts +24 -0
  68. package/dist/lifecycle/hook-discovery.js +60 -0
  69. package/dist/lifecycle/hook-dispatcher.d.ts +34 -0
  70. package/dist/lifecycle/hook-dispatcher.js +190 -0
  71. package/dist/lifecycle/index.d.ts +3 -0
  72. package/dist/lifecycle/index.js +3 -0
  73. package/dist/lifecycle/parallel-grouping.d.ts +27 -0
  74. package/dist/lifecycle/parallel-grouping.js +151 -0
  75. package/dist/mobile/__tests__/android-device-e2e.test.d.ts +1 -0
  76. package/dist/mobile/__tests__/android-device-e2e.test.js +53 -0
  77. package/dist/mobile/__tests__/device-pool.test.d.ts +1 -0
  78. package/dist/mobile/__tests__/device-pool.test.js +97 -0
  79. package/dist/mobile/device-pool.d.ts +23 -0
  80. package/dist/mobile/device-pool.js +1 -0
  81. package/dist/mobile/index.d.ts +1 -0
  82. package/dist/mobile/index.js +1 -0
  83. package/dist/refactor/__tests__/refactor-engine.test.d.ts +1 -0
  84. package/dist/refactor/__tests__/refactor-engine.test.js +175 -0
  85. package/dist/refactor/index.d.ts +1 -0
  86. package/dist/refactor/index.js +1 -0
  87. package/dist/refactor/refactor-engine.d.ts +25 -0
  88. package/dist/refactor/refactor-engine.js +255 -0
  89. package/dist/reporter/__tests__/semantic-formatter.test.d.ts +1 -0
  90. package/dist/reporter/__tests__/semantic-formatter.test.js +73 -0
  91. package/dist/reporter/semantic-formatter.d.ts +6 -0
  92. package/dist/reporter/semantic-formatter.js +191 -0
  93. package/dist/reporter/summary-view.d.ts +12 -0
  94. package/dist/reporter/summary-view.js +19 -0
  95. package/dist/reporter/terminal-stream.d.ts +32 -0
  96. package/dist/reporter/terminal-stream.js +82 -0
  97. package/dist/reporter/types.d.ts +2 -0
  98. package/dist/reporter/types.js +1 -0
  99. package/dist/runner/bridge.d.ts +10 -5
  100. package/dist/runner/bridge.js +69 -44
  101. package/dist/runner/reporter.d.ts +30 -2
  102. package/dist/runner/reporter.js +419 -13
  103. package/dist/server/demo.js +43 -44
  104. package/dist/types/generator.d.ts +1 -17
  105. package/dist/types/generator.js +1 -443
  106. package/dist/utils/demo-server.js +38 -35
  107. package/package.json +20 -12
  108. package/templates/default/CLAUDE.md +7 -5
  109. package/templates/default/fixtures/apiData.json +24 -0
  110. package/templates/default/package.json +13 -4
  111. package/templates/default/page-objects/MatchersPage/mobile.ts +41 -16
  112. package/templates/default/page-objects/MatchersPage/web.ts +14 -0
  113. package/templates/default/page-objects/NavigationPage/mobile.ts +10 -1
  114. package/templates/default/page-objects/PlaygroundPage/mobile.ts +27 -17
  115. package/templates/default/page-objects/PlaygroundPage/web.ts +2 -0
  116. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/mobile.test.ts +11 -0
  117. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/spec.md +12 -0
  118. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/web.test.ts +27 -0
  119. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/mobile.test.ts +16 -0
  120. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/spec.md +12 -0
  121. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/web.test.ts +24 -0
  122. package/templates/default/specs/ApiInterception/suite.md +9 -0
  123. package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +7 -1
  124. package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +17 -3
  125. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +15 -1
  126. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +14 -4
  127. package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +9 -1
  128. package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +8 -3
  129. package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +9 -1
  130. package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +9 -3
  131. package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +27 -1
  132. package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +27 -6
  133. package/templates/default/specs/Playground/TC-0001-form-controls/mobile.test.ts +4 -1
  134. package/templates/default/specs/Playground/TC-0001-form-controls/web.test.ts +3 -3
  135. package/templates/default/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +4 -1
  136. package/templates/default/specs/Playground/TC-0002-toggle-elements/web.test.ts +2 -2
  137. package/templates/default/spectra.config.ts +21 -14
  138. package/templates/default/support/actions/fillCredentials/mobile.action.ts +2 -2
  139. package/templates/default/support/steps/togglePlaygroundStates/mobile.step.ts +2 -0
  140. package/templates/default/support/steps/togglePlaygroundStates/web.step.ts +2 -2
  141. package/templates/default/support/steps/verifyPlaygroundState/mobile.step.ts +3 -1
  142. package/templates/default/support/steps/verifyPlaygroundState/web.step.ts +3 -3
  143. package/templates/default/tsconfig.json +3 -1
  144. package/templates/nx/.nx/workspace-data/d/daemon.log +168 -0
  145. package/templates/nx/CLAUDE.md +2 -2
  146. package/templates/nx/package.json +7 -5
  147. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/mobile.test.ts +3 -0
  148. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/spec.md +12 -0
  149. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/web.test.ts +27 -0
  150. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/mobile.test.ts +3 -0
  151. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/spec.md +12 -0
  152. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/web.test.ts +24 -0
  153. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/suite.md +9 -0
  154. package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +17 -3
  155. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +14 -4
  156. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +8 -3
  157. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +9 -3
  158. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +27 -6
  159. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0001-form-controls/web.test.ts +3 -3
  160. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0002-toggle-elements/web.test.ts +2 -2
  161. package/templates/nx/pnpm-lock.yaml +6663 -0
  162. package/templates/nx/pnpm-workspace.yaml +2 -1
  163. package/templates/nx/shared/testing/fixtures/apiData.json +24 -0
  164. package/templates/nx/shared/testing/page-objects/MatchersPage/mobile.ts +12 -0
  165. package/templates/nx/shared/testing/page-objects/MatchersPage/web.ts +14 -0
  166. package/templates/nx/shared/testing/page-objects/PlaygroundPage/web.ts +2 -0
  167. package/templates/nx/shared/testing/project.json +19 -0
  168. package/templates/nx/shared/testing/support/steps/togglePlaygroundStates/web.step.ts +2 -2
  169. package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/mobile.step.ts +1 -1
  170. package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/web.step.ts +3 -3
  171. package/templates/nx/spectra.config.ts +19 -12
  172. package/templates/nx/tsconfig.json +3 -1
  173. package/demo-app/assets/index-DAUlrHTr.css +0 -1
  174. package/demo-app/assets/index-DN2Kb0A8.js +0 -100
  175. package/dist/index.cjs +0 -101
  176. package/dist/plugin.cjs +0 -575
  177. package/dist/plugin.d.ts +0 -16
  178. package/dist/plugin.js +0 -184
  179. package/dist/step/index.d.ts +0 -6
  180. package/dist/step/index.js +0 -6
  181. package/dist/step/matchers.d.ts +0 -14
  182. package/dist/step/matchers.js +0 -114
  183. package/dist/step/proto.d.ts +0 -46
  184. package/dist/step/proto.js +0 -114
  185. package/dist/step/runner/collection.d.ts +0 -13
  186. package/dist/step/runner/collection.js +0 -51
  187. package/dist/step/runner/single.d.ts +0 -21
  188. package/dist/step/runner/single.js +0 -138
  189. package/dist/step/spectra.d.ts +0 -34
  190. package/dist/step/spectra.js +0 -156
  191. package/dist/step/types.d.ts +0 -32
  192. package/dist/step/types.js +0 -5
  193. package/templates/default/tsconfig.spectra.android.json +0 -46
  194. package/templates/default/tsconfig.spectra.ios.json +0 -46
  195. package/templates/default/tsconfig.spectra.json +0 -22
  196. package/templates/default/tsconfig.spectra.web.json +0 -53
  197. package/templates/nx/fixtures/playgroundData.json +0 -7
  198. package/templates/nx/global-hooks/after/mobile.hook.ts +0 -3
  199. package/templates/nx/global-hooks/after/web.hook.ts +0 -3
  200. package/templates/nx/global-hooks/before/mobile.hook.ts +0 -3
  201. package/templates/nx/global-hooks/before/web.hook.ts +0 -3
  202. package/templates/nx/page-objects/MatchersPage/mobile.ts +0 -21
  203. package/templates/nx/page-objects/MatchersPage/web.ts +0 -23
  204. package/templates/nx/page-objects/NavigationPage/mobile.ts +0 -5
  205. package/templates/nx/page-objects/NavigationPage/web.ts +0 -8
  206. package/templates/nx/page-objects/PlaygroundPage/mobile.ts +0 -26
  207. package/templates/nx/page-objects/PlaygroundPage/web.ts +0 -29
  208. package/templates/nx/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +0 -3
  209. package/templates/nx/specs/BrowserContext/TC-0007-title-and-navigation/spec.md +0 -12
  210. package/templates/nx/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +0 -5
  211. package/templates/nx/specs/BrowserContext/suite.md +0 -9
  212. package/templates/nx/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +0 -3
  213. package/templates/nx/specs/ContentMatchers/TC-0005-text-and-values/spec.md +0 -12
  214. package/templates/nx/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +0 -7
  215. package/templates/nx/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +0 -3
  216. package/templates/nx/specs/ContentMatchers/TC-0006-collections-and-empty/spec.md +0 -12
  217. package/templates/nx/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +0 -6
  218. package/templates/nx/specs/ContentMatchers/suite.md +0 -9
  219. package/templates/nx/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +0 -3
  220. package/templates/nx/specs/ElementMatchers/TC-0003-visibility-and-dom/spec.md +0 -12
  221. package/templates/nx/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +0 -5
  222. package/templates/nx/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +0 -3
  223. package/templates/nx/specs/ElementMatchers/TC-0004-states-and-attributes/spec.md +0 -12
  224. package/templates/nx/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +0 -8
  225. package/templates/nx/specs/ElementMatchers/hooks/after/mobile.hook.ts +0 -1
  226. package/templates/nx/specs/ElementMatchers/hooks/after/web.hook.ts +0 -1
  227. package/templates/nx/specs/ElementMatchers/hooks/afterEach/mobile.hook.ts +0 -1
  228. package/templates/nx/specs/ElementMatchers/hooks/afterEach/web.hook.ts +0 -1
  229. package/templates/nx/specs/ElementMatchers/hooks/before/mobile.hook.ts +0 -1
  230. package/templates/nx/specs/ElementMatchers/hooks/before/web.hook.ts +0 -1
  231. package/templates/nx/specs/ElementMatchers/hooks/beforeEach/mobile.hook.ts +0 -1
  232. package/templates/nx/specs/ElementMatchers/hooks/beforeEach/web.hook.ts +0 -1
  233. package/templates/nx/specs/ElementMatchers/suite.md +0 -9
  234. package/templates/nx/specs/Playground/TC-0001-form-controls/mobile.test.ts +0 -3
  235. package/templates/nx/specs/Playground/TC-0001-form-controls/spec.md +0 -12
  236. package/templates/nx/specs/Playground/TC-0001-form-controls/web.test.ts +0 -6
  237. package/templates/nx/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +0 -3
  238. package/templates/nx/specs/Playground/TC-0002-toggle-elements/spec.md +0 -12
  239. package/templates/nx/specs/Playground/TC-0002-toggle-elements/web.test.ts +0 -6
  240. package/templates/nx/specs/Playground/hooks/after/mobile.hook.ts +0 -1
  241. package/templates/nx/specs/Playground/hooks/after/web.hook.ts +0 -1
  242. package/templates/nx/specs/Playground/hooks/afterEach/mobile.hook.ts +0 -1
  243. package/templates/nx/specs/Playground/hooks/afterEach/web.hook.ts +0 -1
  244. package/templates/nx/specs/Playground/hooks/before/mobile.hook.ts +0 -1
  245. package/templates/nx/specs/Playground/hooks/before/web.hook.ts +0 -1
  246. package/templates/nx/specs/Playground/hooks/beforeEach/mobile.hook.ts +0 -1
  247. package/templates/nx/specs/Playground/hooks/beforeEach/web.hook.ts +0 -1
  248. package/templates/nx/specs/Playground/suite.md +0 -9
  249. package/templates/nx/support/actions/fillCredentials/mobile.action.ts +0 -4
  250. package/templates/nx/support/actions/fillCredentials/web.action.ts +0 -4
  251. package/templates/nx/support/steps/togglePlaygroundStates/mobile.step.ts +0 -3
  252. package/templates/nx/support/steps/togglePlaygroundStates/step.md +0 -7
  253. package/templates/nx/support/steps/togglePlaygroundStates/web.step.ts +0 -5
  254. package/templates/nx/support/steps/verifyPlaygroundState/mobile.step.ts +0 -4
  255. package/templates/nx/support/steps/verifyPlaygroundState/step.md +0 -7
  256. package/templates/nx/support/steps/verifyPlaygroundState/web.step.ts +0 -6
  257. package/templates/nx/tsconfig.spectra.android.json +0 -39
  258. package/templates/nx/tsconfig.spectra.ios.json +0 -39
  259. package/templates/nx/tsconfig.spectra.json +0 -25
  260. package/templates/nx/tsconfig.spectra.shared.json +0 -25
  261. package/templates/nx/tsconfig.spectra.web.json +0 -45
  262. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/after/mobile.hook.ts +0 -0
  263. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/after/web.hook.ts +0 -0
  264. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/afterEach/mobile.hook.ts +0 -0
  265. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/afterEach/web.hook.ts +0 -0
  266. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/before/mobile.hook.ts +0 -0
  267. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/before/web.hook.ts +0 -0
  268. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/beforeEach/mobile.hook.ts +0 -0
  269. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/beforeEach/web.hook.ts +0 -0
  270. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/after/mobile.hook.ts +0 -0
  271. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/after/web.hook.ts +0 -0
  272. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/afterEach/mobile.hook.ts +0 -0
  273. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/afterEach/web.hook.ts +0 -0
  274. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/before/mobile.hook.ts +0 -0
  275. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/before/web.hook.ts +0 -0
  276. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/beforeEach/mobile.hook.ts +0 -0
  277. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/beforeEach/web.hook.ts +0 -0
@@ -1,26 +1,425 @@
1
+ import chalk from 'chalk';
2
+ import { formatAction, formatAssertion } from '../reporter/semantic-formatter.js';
3
+ function stripAnsi(str) {
4
+ return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, '');
5
+ }
6
+ function mapActionArgs(key, arr) {
7
+ if (!Array.isArray(arr)) {
8
+ return typeof arr === 'object' && arr !== null ? arr : {};
9
+ }
10
+ switch (key) {
11
+ case 'type':
12
+ return { text: arr[0] };
13
+ case 'select':
14
+ case 'selectOption':
15
+ return { option: arr[0] };
16
+ case 'dragDrop':
17
+ return { dest: arr[0] };
18
+ case 'longPress':
19
+ return { durationMs: arr[0] };
20
+ case 'navigate':
21
+ return { url: arr[0] };
22
+ case 'setViewport':
23
+ return { width: arr[0], height: arr[1] };
24
+ case 'wait':
25
+ return { ms: arr[0] };
26
+ case 'pressKey':
27
+ return { key: arr[0] };
28
+ case 'scroll':
29
+ return { direction: arr[0], pixels: arr[1] };
30
+ case 'swipe':
31
+ return { direction: arr[0], distance: arr[1] };
32
+ case 'intercept':
33
+ return { method: arr[0], url: arr[1] };
34
+ default:
35
+ return {};
36
+ }
37
+ }
38
+ function mapAssertionArgs(key, arr) {
39
+ if (!Array.isArray(arr)) {
40
+ return typeof arr === 'object' && arr !== null ? arr : { expected: arr };
41
+ }
42
+ if (key === 'have.attr' || key === 'not.have.attr') {
43
+ return arr.length >= 2 ? { name: arr[0], value: arr[1], expected: arr[0] } : { name: arr[0], expected: arr[0] };
44
+ }
45
+ if (key === 'have.css' || key === 'not.have.css') {
46
+ return { name: arr[0], property: arr[0], value: arr[1], expected: arr[0] };
47
+ }
48
+ if (arr.length >= 2) {
49
+ return { name: arr[0], value: arr[1], expected: arr[0] };
50
+ }
51
+ return {
52
+ expected: arr[0],
53
+ name: arr[0],
54
+ text: arr[0],
55
+ value: arr[0],
56
+ title: arr[0],
57
+ url: arr[0],
58
+ length: arr[0],
59
+ min: arr[0],
60
+ max: arr[0],
61
+ };
62
+ }
63
+ function parseAndFormat(cmdText) {
64
+ try {
65
+ const payload = JSON.parse(cmdText);
66
+ const target = typeof payload.target === 'object' && payload.target !== null
67
+ ? payload.target.selector || payload.target.name || payload.target.target || payload.target
68
+ : payload.target;
69
+ if (payload.type === 'action') {
70
+ return formatAction(payload.key, target, mapActionArgs(payload.key, payload.args || []));
71
+ }
72
+ else if (payload.type === 'assertion' || payload.type === 'browser') {
73
+ return formatAssertion(payload.key, target, mapAssertionArgs(payload.key, payload.args || []));
74
+ }
75
+ // Native Orchestrator payload format ({ test, action, selector, target, ... })
76
+ if (payload.action) {
77
+ const action = payload.action;
78
+ const t = payload.selector || payload.target;
79
+ switch (action) {
80
+ case 'navigate':
81
+ return formatAction('navigate', undefined, {
82
+ url: t || payload.url || payload.value || 'http://localhost:5173',
83
+ });
84
+ case 'click':
85
+ return formatAction('click', t);
86
+ case 'double_click':
87
+ case 'doubleClick':
88
+ return formatAction('doubleClick', t);
89
+ case 'right_click':
90
+ case 'rightClick':
91
+ return formatAction('rightClick', t);
92
+ case 'type':
93
+ case 'type_text':
94
+ case 'set_value':
95
+ return formatAction('type', t, { text: payload.text || payload.value });
96
+ case 'clear':
97
+ return formatAction('clear', t);
98
+ case 'hover':
99
+ return formatAction('hover', t);
100
+ case 'scroll_into_view':
101
+ case 'scrollIntoView':
102
+ return formatAction('scrollIntoView', t);
103
+ case 'should_be_visible':
104
+ return formatAssertion('be.visible', t);
105
+ case 'should_not_be_visible':
106
+ return formatAssertion('not.be.visible', t);
107
+ case 'should_exist':
108
+ return formatAssertion('exist', t);
109
+ case 'should_not_exist':
110
+ return formatAssertion('not.exist', t);
111
+ case 'should_be_enabled':
112
+ return formatAssertion('be.enabled', t);
113
+ case 'should_be_disabled':
114
+ return formatAssertion('be.disabled', t);
115
+ case 'should_be_clickable':
116
+ return formatAssertion('be.clickable', t);
117
+ case 'should_have_text':
118
+ return formatAssertion('have.text', t, { expected: payload.expected || payload.text || payload.value });
119
+ case 'should_contain_text':
120
+ return formatAssertion('contain.text', t, {
121
+ expected: payload.expected || payload.text || payload.value,
122
+ });
123
+ case 'should_have_value':
124
+ return formatAssertion('have.value', t, { expected: payload.expected || payload.value });
125
+ case 'should_contain_value':
126
+ return formatAssertion('contain.value', t, { expected: payload.expected || payload.value });
127
+ case 'should_have_length':
128
+ return formatAssertion('have.length', t, {
129
+ expected: payload.expected || payload.length || payload.value,
130
+ });
131
+ case 'should_have_title':
132
+ return formatAssertion('have.title', undefined, {
133
+ expected: payload.expected || payload.value || t || 'TestSpectra',
134
+ });
135
+ case 'should_be_empty':
136
+ return formatAssertion('be.empty', t);
137
+ case 'should_not_be_empty':
138
+ return formatAssertion('not.be.empty', t);
139
+ default:
140
+ return `Execute step "${action}" on ${t || 'target'}`;
141
+ }
142
+ }
143
+ return cmdText;
144
+ }
145
+ catch {
146
+ return cmdText;
147
+ }
148
+ }
1
149
  export class Reporter {
2
150
  logs = [];
3
151
  networkEvents = [];
152
+ pendingTests = new Map();
153
+ workerToTest = new Map();
154
+ passedCount = 0;
155
+ failedCount = 0;
156
+ isInteractive;
157
+ lastRenderedLines = 0;
158
+ spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
159
+ spinnerIndex = 0;
160
+ spinnerTimer = null;
161
+ constructor() {
162
+ this.isInteractive = Boolean(process.stdout.isTTY && !process.env.CI && process.env.NODE_ENV !== 'test' && !process.env.VITEST);
163
+ if (this.isInteractive) {
164
+ this.spinnerTimer = setInterval(() => {
165
+ this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
166
+ this.renderActiveSlots();
167
+ }, 80);
168
+ }
169
+ }
170
+ clearActiveSlots() {
171
+ if (!this.isInteractive || this.lastRenderedLines === 0)
172
+ return;
173
+ try {
174
+ process.stdout.write(`\x1b[${this.lastRenderedLines}A\x1b[0J`);
175
+ }
176
+ catch { }
177
+ this.lastRenderedLines = 0;
178
+ }
179
+ renderActiveSlots() {
180
+ if (!this.isInteractive)
181
+ return;
182
+ const active = Array.from(this.pendingTests.values());
183
+ if (active.length === 0) {
184
+ this.clearActiveSlots();
185
+ return;
186
+ }
187
+ this.clearActiveSlots();
188
+ const frame = chalk.cyan(this.spinnerFrames[this.spinnerIndex]);
189
+ let linesCount = 0;
190
+ for (const tc of active) {
191
+ const workerBadge = tc.workerId ? chalk.gray(`[Worker ${tc.workerId}] `) : '';
192
+ const titleShort = tc.title.length > 55 ? tc.title.slice(0, 52) + '...' : tc.title;
193
+ const elapsed = Date.now() - tc.startTime;
194
+ const line1 = ` ${frame} ${workerBadge}${chalk.white.bold(titleShort)} ${chalk.gray(`(${elapsed}ms)`)}`;
195
+ const stepText = tc.currentStep ? chalk.dim(` ↳ ${tc.currentStep}`) : '';
196
+ process.stdout.write(line1 + '\n');
197
+ linesCount++;
198
+ if (stepText) {
199
+ process.stdout.write(stepText + '\n');
200
+ linesCount++;
201
+ }
202
+ }
203
+ this.lastRenderedLines = linesCount;
204
+ }
205
+ resolveTestCase(testTitle, workerId) {
206
+ if (testTitle && this.pendingTests.has(testTitle)) {
207
+ return this.pendingTests.get(testTitle);
208
+ }
209
+ if (workerId !== undefined && this.workerToTest.has(workerId)) {
210
+ const title = this.workerToTest.get(workerId);
211
+ if (title && this.pendingTests.has(title)) {
212
+ return this.pendingTests.get(title);
213
+ }
214
+ }
215
+ if (this.pendingTests.size === 1) {
216
+ return this.pendingTests.values().next().value;
217
+ }
218
+ return Array.from(this.pendingTests.values()).pop();
219
+ }
4
220
  addLog(log) {
5
221
  this.logs.push(log);
6
- const time = `\x1b[90m${log.timestamp}\x1b[0m`;
7
- let prefix = `[${log.level}]`;
8
- if (log.level === "SUCCESS" || log.level === "PASSED") {
9
- prefix = `\x1b[32m${prefix}\x1b[0m`;
222
+ const raw = stripAnsi(log.message || '').trim();
223
+ if (!raw)
224
+ return;
225
+ // Filter out WDIO framework internal noise
226
+ if (raw.includes('RUNNING in chrome') ||
227
+ raw.includes('PASSED in chrome') ||
228
+ raw.includes('FAILED in chrome') ||
229
+ raw.includes('[NetworkRecorder]') ||
230
+ raw.includes('"spec" Reporter:') ||
231
+ raw.includes('"DotReporter" Reporter:') ||
232
+ raw.includes('SilentReporter') ||
233
+ raw.startsWith('---') ||
234
+ raw === '.' ||
235
+ raw.includes('Session ID:') ||
236
+ raw.includes('Running: chrome') ||
237
+ raw.includes('[chrome') ||
238
+ raw.includes('[firefox') ||
239
+ raw.includes('[safari') ||
240
+ raw.includes('[edge') ||
241
+ raw.includes('(root)') ||
242
+ raw.includes('passing (') ||
243
+ raw.includes('failing (') ||
244
+ raw.includes('Spec Files:') ||
245
+ (raw.includes('Execution of') && raw.includes('workers started')) ||
246
+ raw.includes('Spawning WDIO execution') ||
247
+ raw.includes('WARN webdriver:') ||
248
+ raw.includes('WebDriverError: unknown error: net::ERR_CONNECTION_REFUSED') ||
249
+ raw.includes('when running "url" with method "POST"') ||
250
+ raw.includes('Session info: chrome=')) {
251
+ return;
252
+ }
253
+ // 1. Test started -> initialize test buffer & worker slot
254
+ if (raw.startsWith('[TESTSPECTRA_TEST_START]')) {
255
+ const content = raw.replace('[TESTSPECTRA_TEST_START]', '').trim();
256
+ let title = content;
257
+ let workerId;
258
+ try {
259
+ const parsed = JSON.parse(content);
260
+ if (parsed.title) {
261
+ title = parsed.title;
262
+ workerId = parsed.workerId;
263
+ }
264
+ }
265
+ catch { }
266
+ const pending = {
267
+ title,
268
+ workerId,
269
+ steps: [],
270
+ currentStep: 'Running suite...',
271
+ startTime: Date.now(),
272
+ };
273
+ this.pendingTests.set(title, pending);
274
+ if (workerId !== undefined) {
275
+ this.workerToTest.set(workerId, title);
276
+ }
277
+ this.renderActiveSlots();
278
+ return;
279
+ }
280
+ // 2. Step in-progress / start
281
+ if (raw.startsWith('[TESTSPECTRA_STEP_START]')) {
282
+ const fullText = raw.replace('[TESTSPECTRA_STEP_START]', '').trim();
283
+ let testTitle = '';
284
+ let workerId;
285
+ try {
286
+ const payload = JSON.parse(fullText);
287
+ testTitle = payload.test || payload.title || '';
288
+ workerId = payload.workerId;
289
+ }
290
+ catch { }
291
+ const formatted = parseAndFormat(fullText);
292
+ const testCase = this.resolveTestCase(testTitle, workerId);
293
+ if (testCase) {
294
+ testCase.currentStep = formatted;
295
+ this.renderActiveSlots();
296
+ }
297
+ return;
10
298
  }
11
- else if (log.level === "ERROR" || log.level === "FAILED") {
12
- prefix = `\x1b[31m${prefix}\x1b[0m`;
299
+ // 3. Step passed -> record step to matching test case
300
+ if (raw.startsWith('[TESTSPECTRA_STEP_PASS]')) {
301
+ const fullText = raw.replace('[TESTSPECTRA_STEP_PASS]', '').trim();
302
+ const match = fullText.match(/\(([^)]+)ms\)$/);
303
+ const duration = match ? parseInt(match[1], 10) : 0;
304
+ const cmdText = fullText.replace(/\s*\([^)]+\)$/, '').trim();
305
+ const formatted = parseAndFormat(cmdText);
306
+ let testTitle = '';
307
+ let workerId;
308
+ try {
309
+ const payload = JSON.parse(cmdText);
310
+ testTitle = payload.test || payload.title || '';
311
+ workerId = payload.workerId;
312
+ }
313
+ catch { }
314
+ const testCase = this.resolveTestCase(testTitle, workerId);
315
+ if (testCase) {
316
+ testCase.steps.push({ text: formatted, duration, passed: true });
317
+ testCase.currentStep = formatted;
318
+ this.renderActiveSlots();
319
+ }
320
+ return;
13
321
  }
14
- else if (log.level === "WARN" || log.level === "WARNING") {
15
- prefix = `\x1b[33m${prefix}\x1b[0m`;
322
+ // 4. Step failed -> record failed step to matching test case
323
+ if (raw.startsWith('[TESTSPECTRA_STEP_FAIL]')) {
324
+ const fullText = raw.replace('[TESTSPECTRA_STEP_FAIL]', '').trim();
325
+ const match = fullText.match(/\(([^)]+)ms\)$/);
326
+ const duration = match ? parseInt(match[1], 10) : 0;
327
+ const cmdText = fullText.replace(/\s*\([^)]+\)$/, '').trim();
328
+ const formatted = parseAndFormat(cmdText);
329
+ let testTitle = '';
330
+ let workerId;
331
+ try {
332
+ const payload = JSON.parse(cmdText);
333
+ testTitle = payload.test || payload.title || '';
334
+ workerId = payload.workerId;
335
+ }
336
+ catch { }
337
+ const testCase = this.resolveTestCase(testTitle, workerId);
338
+ if (testCase) {
339
+ testCase.steps.push({ text: formatted, duration, passed: false });
340
+ testCase.currentStep = formatted;
341
+ this.renderActiveSlots();
342
+ }
343
+ return;
16
344
  }
17
- else if (log.level === "INFO") {
18
- prefix = `\x1b[36m${prefix}\x1b[0m`;
345
+ // 5. Test error detail
346
+ if (raw.startsWith('[TESTSPECTRA_TEST_ERROR]')) {
347
+ const err = raw.replace('[TESTSPECTRA_TEST_ERROR]', '').trim();
348
+ const latest = Array.from(this.pendingTests.values()).pop();
349
+ if (latest) {
350
+ latest.errorMsg = err;
351
+ }
352
+ else {
353
+ console.log(` \x1b[38;2;251;191;36m↳ Error:\x1b[0m \x1b[38;2;248;113;113m${err}\x1b[0m`);
354
+ }
355
+ return;
19
356
  }
20
- else {
21
- prefix = `\x1b[90m${prefix}\x1b[0m`;
357
+ // 6. Test passed completely -> flush atomic test block to permanent history
358
+ if (raw.startsWith('[TESTSPECTRA_TEST_PASS]')) {
359
+ const fullText = raw.replace('[TESTSPECTRA_TEST_PASS]', '').trim();
360
+ const match = fullText.match(/\(([^)]+)ms\)$/);
361
+ const duration = match ? parseInt(match[1], 10) : 0;
362
+ const title = fullText.replace(/\s*\([^)]+\)$/, '').trim();
363
+ this.passedCount++;
364
+ const testCase = this.pendingTests.get(title) || this.resolveTestCase(title);
365
+ const steps = testCase?.steps || [];
366
+ const workerId = testCase?.workerId;
367
+ this.pendingTests.delete(title);
368
+ if (workerId !== undefined) {
369
+ this.workerToTest.delete(workerId);
370
+ }
371
+ this.clearActiveSlots();
372
+ console.log(`${chalk.hex('#34d399')('✓')} ${chalk.white.bold(title)} ${chalk.gray(`(${duration}ms)`)}`);
373
+ for (const step of steps) {
374
+ console.log(` ${chalk.green('✔')} ${step.text} ${chalk.gray(`(${step.duration}ms)`)}`);
375
+ }
376
+ console.log('');
377
+ this.renderActiveSlots();
378
+ return;
379
+ }
380
+ // 7. Test failed completely -> flush atomic failed test block to permanent history
381
+ if (raw.startsWith('[TESTSPECTRA_TEST_FAIL]')) {
382
+ const fullText = raw.replace('[TESTSPECTRA_TEST_FAIL]', '').trim();
383
+ const match = fullText.match(/\(([^)]+)ms\)$/);
384
+ const duration = match ? parseInt(match[1], 10) : 0;
385
+ const title = fullText.replace(/\s*\([^)]+\)$/, '').trim();
386
+ this.failedCount++;
387
+ const testCase = this.pendingTests.get(title) || this.resolveTestCase(title);
388
+ const steps = testCase?.steps || [];
389
+ const errorMsg = testCase?.errorMsg;
390
+ const workerId = testCase?.workerId;
391
+ this.pendingTests.delete(title);
392
+ if (workerId !== undefined) {
393
+ this.workerToTest.delete(workerId);
394
+ }
395
+ this.clearActiveSlots();
396
+ if (errorMsg) {
397
+ console.log(` \x1b[38;2;251;191;36m↳ Error:\x1b[0m \x1b[38;2;248;113;113m${errorMsg}\x1b[0m`);
398
+ }
399
+ console.log(`${chalk.hex('#f87171')('✗')} ${chalk.white.bold(title)} ${chalk.gray(`(${duration}ms)`)}`);
400
+ for (const step of steps) {
401
+ if (step.passed) {
402
+ console.log(` ${chalk.green('✔')} ${step.text} ${chalk.gray(`(${step.duration}ms)`)}`);
403
+ }
404
+ else {
405
+ console.log(` ${chalk.red('✖')} ${chalk.red(step.text)} ${chalk.gray(`(${step.duration}ms)`)}`);
406
+ }
407
+ }
408
+ console.log('');
409
+ this.renderActiveSlots();
410
+ return;
411
+ }
412
+ // Generic errors & warnings
413
+ if (log.level === 'ERROR' || log.level === 'FAILED') {
414
+ this.clearActiveSlots();
415
+ console.log(` \x1b[38;2;248;113;113m${log.message}\x1b[0m`);
416
+ this.renderActiveSlots();
417
+ }
418
+ else if (log.level === 'WARN' || log.level === 'WARNING') {
419
+ this.clearActiveSlots();
420
+ console.log(` \x1b[38;2;251;191;36m${log.message}\x1b[0m`);
421
+ this.renderActiveSlots();
22
422
  }
23
- console.log(`${time} ${prefix} ${log.message}`);
24
423
  }
25
424
  addNetwork(res) {
26
425
  this.networkEvents.push(res);
@@ -32,9 +431,16 @@ export class Reporter {
32
431
  return this.networkEvents;
33
432
  }
34
433
  generateResult(status, duration) {
434
+ if (this.spinnerTimer) {
435
+ clearInterval(this.spinnerTimer);
436
+ this.spinnerTimer = null;
437
+ }
438
+ this.clearActiveSlots();
35
439
  return {
36
440
  status,
37
441
  duration,
442
+ passedCount: this.passedCount,
443
+ failedCount: this.failedCount,
38
444
  logs: this.logs,
39
445
  networkResources: this.networkEvents,
40
446
  };
@@ -1,28 +1,28 @@
1
- import http from "http";
2
- import fs from "fs";
3
- import path from "path";
4
- import { fileURLToPath } from "url";
5
- import { execSync } from "child_process";
6
- import chalk from "chalk";
1
+ import http from 'http';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { execSync } from 'child_process';
6
+ import chalk from 'chalk';
7
7
  const __filename = fileURLToPath(import.meta.url);
8
8
  const __dirname = path.dirname(__filename);
9
9
  export class DemoAppServer {
10
10
  server = null;
11
11
  port = 0;
12
- url = "";
12
+ url = '';
13
13
  static findDemoAppDir(cwd) {
14
14
  // 1. Check upward from cwd
15
15
  let cur = cwd;
16
16
  while (cur !== path.dirname(cur)) {
17
- const cand = path.join(cur, "apps", "demo-web-app");
18
- if (fs.existsSync(cand) && fs.existsSync(path.join(cand, "package.json"))) {
17
+ const cand = path.join(cur, 'apps', 'demo-web-app');
18
+ if (fs.existsSync(cand) && fs.existsSync(path.join(cand, 'package.json'))) {
19
19
  return cand;
20
20
  }
21
21
  cur = path.dirname(cur);
22
22
  }
23
23
  // 2. Check relative to CLI package location
24
- const relCand = path.resolve(__dirname, "../../../apps/demo-web-app");
25
- if (fs.existsSync(relCand) && fs.existsSync(path.join(relCand, "package.json"))) {
24
+ const relCand = path.resolve(__dirname, '../../../apps/demo-web-app');
25
+ if (fs.existsSync(relCand) && fs.existsSync(path.join(relCand, 'package.json'))) {
26
26
  return relCand;
27
27
  }
28
28
  return null;
@@ -32,67 +32,66 @@ export class DemoAppServer {
32
32
  if (!demoDir) {
33
33
  throw new Error("Could not locate 'apps/demo-web-app'. Ensure you are running within the TestSpectra workspace.");
34
34
  }
35
- const distDir = path.join(demoDir, "dist");
36
- if (!fs.existsSync(distDir) || !fs.existsSync(path.join(distDir, "index.html"))) {
37
- console.log(chalk.cyan("[TestSpectra] ") +
38
- chalk.dim("Building demo web app bundle (apps/demo-web-app)..."));
39
- execSync("pnpm --filter @testspectra/demo-web-app build", {
40
- cwd: path.resolve(demoDir, "../.."),
41
- stdio: "inherit",
35
+ const distDir = path.join(demoDir, 'dist');
36
+ if (!fs.existsSync(distDir) || !fs.existsSync(path.join(distDir, 'index.html'))) {
37
+ console.log(chalk.cyan('[TestSpectra] ') + chalk.dim('Building demo web app bundle (apps/demo-web-app)...'));
38
+ execSync('pnpm --filter @testspectra/demo-web-app build', {
39
+ cwd: path.resolve(demoDir, '../..'),
40
+ stdio: 'inherit',
42
41
  });
43
42
  }
44
43
  const mimeTypes = {
45
- ".html": "text/html; charset=utf-8",
46
- ".js": "text/javascript; charset=utf-8",
47
- ".css": "text/css; charset=utf-8",
48
- ".json": "application/json",
49
- ".svg": "image/svg+xml",
50
- ".png": "image/png",
51
- ".jpg": "image/jpeg",
52
- ".jpeg": "image/jpeg",
53
- ".ico": "image/x-icon",
54
- ".woff": "font/woff",
55
- ".woff2": "font/woff2",
56
- ".ttf": "font/ttf",
44
+ '.html': 'text/html; charset=utf-8',
45
+ '.js': 'text/javascript; charset=utf-8',
46
+ '.css': 'text/css; charset=utf-8',
47
+ '.json': 'application/json',
48
+ '.svg': 'image/svg+xml',
49
+ '.png': 'image/png',
50
+ '.jpg': 'image/jpeg',
51
+ '.jpeg': 'image/jpeg',
52
+ '.ico': 'image/x-icon',
53
+ '.woff': 'font/woff',
54
+ '.woff2': 'font/woff2',
55
+ '.ttf': 'font/ttf',
57
56
  };
58
57
  return new Promise((resolve, reject) => {
59
58
  this.server = http.createServer((req, res) => {
60
- const rawUrl = req.url || "/";
61
- const cleanPath = rawUrl.split("?")[0].split("#")[0];
62
- let filePath = path.join(distDir, cleanPath === "/" ? "index.html" : cleanPath);
59
+ const rawUrl = req.url || '/';
60
+ const cleanPath = rawUrl.split('?')[0].split('#')[0];
61
+ let filePath = path.join(distDir, cleanPath === '/' ? 'index.html' : cleanPath);
63
62
  // Fallback to index.html for SPA client-side routing
64
63
  if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
65
- filePath = path.join(distDir, "index.html");
64
+ filePath = path.join(distDir, 'index.html');
66
65
  }
67
66
  const ext = path.extname(filePath).toLowerCase();
68
- const contentType = mimeTypes[ext] || "application/octet-stream";
67
+ const contentType = mimeTypes[ext] || 'application/octet-stream';
69
68
  fs.readFile(filePath, (err, content) => {
70
69
  if (err) {
71
- res.writeHead(500, { "Content-Type": "text/plain" });
72
- res.end("Internal Server Error");
70
+ res.writeHead(500, { 'Content-Type': 'text/plain' });
71
+ res.end('Internal Server Error');
73
72
  }
74
73
  else {
75
74
  res.writeHead(200, {
76
- "Content-Type": contentType,
77
- "Cache-Control": "no-cache",
78
- "Access-Control-Allow-Origin": "*",
75
+ 'Content-Type': contentType,
76
+ 'Cache-Control': 'no-cache',
77
+ 'Access-Control-Allow-Origin': '*',
79
78
  });
80
79
  res.end(content);
81
80
  }
82
81
  });
83
82
  });
84
- this.server.listen(0, "127.0.0.1", () => {
83
+ this.server.listen(0, '127.0.0.1', () => {
85
84
  const addr = this.server?.address();
86
- if (addr && typeof addr === "object") {
85
+ if (addr && typeof addr === 'object') {
87
86
  this.port = addr.port;
88
87
  this.url = `http://127.0.0.1:${this.port}`;
89
88
  resolve(this.url);
90
89
  }
91
90
  else {
92
- reject(new Error("Failed to bind demo preview server address"));
91
+ reject(new Error('Failed to bind demo preview server address'));
93
92
  }
94
93
  });
95
- this.server.on("error", reject);
94
+ this.server.on('error', reject);
96
95
  });
97
96
  }
98
97
  stop() {
@@ -1,17 +1 @@
1
- export type PlatformTarget = "web" | "android" | "ios" | "mobile" | "common";
2
- export declare class TypeGenerator {
3
- /**
4
- * Discovers all feature directories and shared library directories.
5
- * Returns a map of scope -> base directory (e.g. { "shared": ".../shared/testing", "auth": ".../packages/features/auth/e2e" })
6
- */
7
- static getEntityScopes(cwd: string): {
8
- name: string;
9
- dir: string;
10
- isShared: boolean;
11
- }[];
12
- static getPageObjectsDirsForScope(scopeDir: string, sharedDir?: string): string[];
13
- static getEntityDirsForScope(entityType: "actions" | "steps" | "fixtures", scopeDir: string, sharedDir?: string): string[];
14
- static generateDeclarationsForScope(cwd: string, outputTypesDir: string, scopeDir: string, sharedDir?: string): Record<string, string>;
15
- static generateFixturesDeclarationForScope(cwd: string, outputTypesDir: string, scopeDir: string, sharedDir?: string): string;
16
- static writeDeclarationFiles(cwd: string): void;
17
- }
1
+ export * from '../generator/type-generator.js';