@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,37 +1,47 @@
1
- import { execSync } from "child_process";
2
- export async function devicesCommand(options) {
3
- const target = options.target || "all";
4
- console.log(`\x1b[36m[TestSpectra Devices]\x1b[0m Listing connected test targets (scope: ${target})...\n`);
5
- if (target === "all" || target === "android") {
6
- console.log("\x1b[1mAndroid Devices (ADB):\x1b[0m");
7
- try {
8
- const adbOutput = execSync("adb devices -l", { stdio: "pipe" }).toString();
9
- const lines = adbOutput.split("\n").slice(1);
10
- let found = false;
11
- for (const line of lines) {
12
- if (line.trim()) {
13
- found = true;
14
- console.log(` \x1b[32m•\x1b[0m ${line.trim()}`);
15
- }
1
+ import { execFileSync, spawn } from 'child_process';
2
+ import path from 'path';
3
+ import { RustCoreBridge } from '../runner/bridge.js';
4
+ function getRunnerEnv() {
5
+ const home = process.env.HOME || process.env.USERPROFILE || '';
6
+ const globalDriversDir = path.join(home, '.testspectra', 'drivers');
7
+ return {
8
+ ...process.env,
9
+ TEST_SPECTRA_DRIVER_CACHE: globalDriversDir,
10
+ };
11
+ }
12
+ export async function getConnectedDevices(cwd = process.cwd()) {
13
+ const binPath = RustCoreBridge.resolveBinaryPath();
14
+ const stdout = execFileSync(binPath, ['devices', '--json'], {
15
+ cwd,
16
+ env: getRunnerEnv(),
17
+ encoding: 'utf8',
18
+ stdio: ['ignore', 'pipe', 'pipe'],
19
+ });
20
+ return JSON.parse(stdout.trim());
21
+ }
22
+ export async function devicesCommand(options = {}) {
23
+ const cwd = process.cwd();
24
+ const binPath = RustCoreBridge.resolveBinaryPath();
25
+ if (options.json) {
26
+ const devices = await getConnectedDevices(cwd);
27
+ console.log(JSON.stringify(devices, null, 2));
28
+ return;
29
+ }
30
+ return new Promise((resolve, reject) => {
31
+ const child = spawn(binPath, ['devices'], {
32
+ cwd,
33
+ env: getRunnerEnv(),
34
+ stdio: 'inherit',
35
+ });
36
+ child.on('close', (code) => {
37
+ if (code === 0) {
38
+ resolve();
16
39
  }
17
- if (!found) {
18
- console.log(" \x1b[90mNo Android devices/emulators connected via ADB.\x1b[0m");
40
+ else {
41
+ process.exitCode = code ?? 1;
42
+ resolve();
19
43
  }
20
- }
21
- catch {
22
- console.log(" \x1b[31mADB command failed or platform-tools not in PATH.\x1b[0m");
23
- }
24
- }
25
- if (target === "all" || target === "web") {
26
- console.log("\n\x1b[1mWeb Browsers:\x1b[0m");
27
- try {
28
- const chromeVer = execSync(process.platform === "darwin"
29
- ? '"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --version'
30
- : "google-chrome --version", { stdio: "pipe" }).toString().trim();
31
- console.log(` \x1b[32m•\x1b[0m Chrome: ${chromeVer}`);
32
- }
33
- catch {
34
- console.log(" \x1b[90m• Chrome: Not installed\x1b[0m");
35
- }
36
- }
44
+ });
45
+ child.on('error', reject);
46
+ });
37
47
  }
@@ -1,11 +1,12 @@
1
1
  export interface DependencyStatus {
2
2
  name: string;
3
- category: "core" | "web" | "mobile";
3
+ category: 'core' | 'web' | 'mobile' | string;
4
4
  installed: boolean;
5
5
  version: string | null;
6
6
  required: boolean;
7
7
  required_version: string | null;
8
8
  depends_on: string[];
9
+ location?: string | null;
9
10
  }
10
11
  export interface SystemCheckResult {
11
12
  all_ready: boolean;
@@ -16,4 +17,5 @@ export declare function runSystemChecks(cwd?: string): Promise<SystemCheckResult
16
17
  export declare function doctorCommand(options?: {
17
18
  fix?: boolean;
18
19
  json?: boolean;
20
+ verbose?: boolean;
19
21
  }): Promise<void>;
@@ -1,278 +1,57 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { execSync } from "child_process";
4
- function runCommandSafe(cmd) {
5
- try {
6
- const out = execSync(cmd, { stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }).toString().trim();
7
- if (out)
8
- return out;
9
- }
10
- catch (e) {
11
- const combined = `${e.stdout?.toString() || ""} ${e.stderr?.toString() || ""}`.trim();
12
- if (combined) {
13
- const lower = combined.toLowerCase();
14
- if (!lower.includes("not found") &&
15
- !lower.includes("no such file") &&
16
- !lower.includes("cannot find") &&
17
- !lower.includes("no java runtime present") &&
18
- !lower.includes("command not found")) {
19
- return combined;
20
- }
21
- }
22
- }
23
- return null;
24
- }
25
- function checkChrome() {
26
- const home = process.env.HOME || process.env.USERPROFILE || "";
27
- const driversDir = path.join(home, ".testspectra", "drivers");
28
- if (!fs.existsSync(driversDir)) {
29
- return { installed: false, version: null };
30
- }
31
- try {
32
- const entries = fs.readdirSync(driversDir, { recursive: true });
33
- for (const entry of entries) {
34
- const entryStr = String(entry);
35
- if (entryStr.endsWith("Google Chrome for Testing") ||
36
- entryStr.endsWith("chrome") ||
37
- entryStr.endsWith("chrome.exe")) {
38
- const fullPath = path.join(driversDir, entryStr);
39
- if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
40
- const out = runCommandSafe(`"${fullPath}" --version`);
41
- if (out) {
42
- return { installed: true, version: `${out.split("\n")[0].trim()} (Chrome for Testing)` };
43
- }
44
- // Binary exists but couldn't get version — still count as installed
45
- return { installed: true, version: "Chrome for Testing (cached)" };
46
- }
47
- }
48
- }
49
- }
50
- catch { }
51
- return { installed: false, version: null };
52
- }
53
- function checkWorkspacePackage(pkgName, startDir) {
54
- let cur = path.resolve(startDir);
55
- while (cur && cur !== path.dirname(cur)) {
56
- const pkgJsonPath = path.join(cur, "node_modules", pkgName, "package.json");
57
- if (fs.existsSync(pkgJsonPath)) {
58
- try {
59
- const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
60
- return { installed: true, version: `v${pkg.version || "installed"}` };
61
- }
62
- catch { }
63
- }
64
- // Also check root package.json devDependencies/dependencies
65
- const rootPkgPath = path.join(cur, "package.json");
66
- if (fs.existsSync(rootPkgPath)) {
67
- try {
68
- const rPkg = JSON.parse(fs.readFileSync(rootPkgPath, "utf-8"));
69
- if (rPkg.name === pkgName) {
70
- return { installed: true, version: `v${rPkg.version || "workspace"}` };
71
- }
72
- const depVer = rPkg.devDependencies?.[pkgName] || rPkg.dependencies?.[pkgName];
73
- if (depVer) {
74
- return { installed: true, version: depVer };
75
- }
76
- }
77
- catch { }
78
- }
79
- // Check subpackages if monorepo
80
- const cand1 = path.join(cur, "tools", pkgName.replace("@testspectra/", ""), "package.json");
81
- const cand2 = path.join(cur, "packages", pkgName.replace("@testspectra/", ""), "package.json");
82
- const cand3 = path.join(cur, pkgName.replace("@testspectra/", ""), "package.json");
83
- for (const cand of [cand1, cand2, cand3]) {
84
- if (fs.existsSync(cand)) {
85
- try {
86
- const pkg = JSON.parse(fs.readFileSync(cand, "utf-8"));
87
- if (pkg.name === pkgName) {
88
- return { installed: true, version: `v${pkg.version || "workspace"}` };
89
- }
90
- }
91
- catch { }
92
- }
93
- }
94
- cur = path.dirname(cur);
95
- }
96
- return { installed: false, version: null };
1
+ import { execFileSync, spawn } from 'child_process';
2
+ import path from 'path';
3
+ import { RustCoreBridge } from '../runner/bridge.js';
4
+ function getRunnerEnv() {
5
+ const home = process.env.HOME || process.env.USERPROFILE || '';
6
+ const globalDriversDir = path.join(home, '.testspectra', 'drivers');
7
+ return {
8
+ ...process.env,
9
+ TEST_SPECTRA_DRIVER_CACHE: globalDriversDir,
10
+ };
97
11
  }
98
12
  export async function runSystemChecks(cwd = process.cwd()) {
99
- const dependencies = [];
100
- // --- 1. Essential Core ---
101
- // Node.js
102
- const nodeOut = runCommandSafe("node -v");
103
- dependencies.push({
104
- name: "Node.js",
105
- category: "core",
106
- installed: !!nodeOut,
107
- version: nodeOut ? nodeOut.split("\n")[0].trim() : null,
108
- required: true,
109
- required_version: ">=18.0.0",
110
- depends_on: [],
111
- });
112
- // Bun
113
- const bunOut = runCommandSafe("bun -v");
114
- dependencies.push({
115
- name: "Bun",
116
- category: "core",
117
- installed: !!bunOut,
118
- version: bunOut ? `v${bunOut.split("\n")[0].trim()}` : null,
119
- required: false,
120
- required_version: null,
121
- depends_on: [],
122
- });
123
- // Git
124
- const gitOut = runCommandSafe("git --version");
125
- dependencies.push({
126
- name: "Git",
127
- category: "core",
128
- installed: !!gitOut,
129
- version: gitOut ? gitOut.replace("git version", "").trim() : null,
130
- required: false,
131
- required_version: null,
132
- depends_on: [],
133
- });
134
- // --- 2. Web Automation & Browsers ---
135
- // Google Chrome / Chromium
136
- const chromeCheck = checkChrome();
137
- dependencies.push({
138
- name: "Google Chrome",
139
- category: "web",
140
- installed: chromeCheck.installed,
141
- version: chromeCheck.version,
142
- required: true,
143
- required_version: "Stable / CfT",
144
- depends_on: [],
145
- });
146
- // WebDriverIO Core packages
147
- const webPackages = [
148
- { name: "WDIO CLI", pkg: "@wdio/cli", required: true },
149
- { name: "WebDriverIO Core", pkg: "webdriverio", required: true },
150
- { name: "WDIO Local Runner", pkg: "@wdio/local-runner", required: true },
151
- { name: "WDIO Globals", pkg: "@wdio/globals", required: true },
152
- { name: "WDIO Spec Reporter", pkg: "@wdio/spec-reporter", required: true },
153
- { name: "WDIO Mocha Framework", pkg: "@wdio/mocha-framework", required: true },
154
- { name: "WDIO DevTools Service", pkg: "@wdio/devtools-service", required: false },
155
- { name: "TestSpectra CLI", pkg: "@testspectra/cli", required: true },
156
- { name: "TestSpectra Matchers", pkg: "@testspectra/matchers", required: true },
157
- ];
158
- for (const wp of webPackages) {
159
- const pkgCheck = checkWorkspacePackage(wp.pkg, cwd);
160
- dependencies.push({
161
- name: wp.name,
162
- category: "web",
163
- installed: pkgCheck.installed,
164
- version: pkgCheck.version,
165
- required: wp.required,
166
- required_version: null,
167
- depends_on: ["Node.js"],
168
- });
169
- }
170
- // --- 3. Mobile Testing (Android) ---
171
- const adbOut = runCommandSafe("adb version");
172
- let adbVer = null;
173
- if (adbOut) {
174
- const m = adbOut.match(/Version\s+([\d.]+)/i) || adbOut.match(/Android Debug Bridge version\s+([\d.]+)/i);
175
- adbVer = m ? `v${m[1]}` : "Installed";
176
- }
177
- dependencies.push({
178
- name: "ADB (Android Debug Bridge)",
179
- category: "mobile",
180
- installed: !!adbOut,
181
- version: adbVer,
182
- required: false,
183
- required_version: null,
184
- depends_on: [],
185
- });
186
- const javaOut = runCommandSafe("java -version 2>&1");
187
- let javaVer = null;
188
- if (javaOut && !javaOut.toLowerCase().includes("no java runtime present") && !javaOut.toLowerCase().includes("not found")) {
189
- const m = javaOut.match(/(?:java|openjdk)\s+version\s+"([^"]+)"/i) || javaOut.match(/(?:java|openjdk)\s+([\d.]+)/i);
190
- javaVer = m ? `v${m[1]}` : "Installed";
191
- }
192
- dependencies.push({
193
- name: "Java JDK",
194
- category: "mobile",
195
- installed: !!javaVer,
196
- version: javaVer,
197
- required: false,
198
- required_version: ">=21.0.0",
199
- depends_on: [],
200
- });
201
- const appiumOut = runCommandSafe("appium -v");
202
- dependencies.push({
203
- name: "Appium",
204
- category: "mobile",
205
- installed: !!appiumOut,
206
- version: appiumOut ? `v${appiumOut.split("\n")[0].trim()}` : null,
207
- required: false,
208
- required_version: ">=2.0.0",
209
- depends_on: ["Node.js"],
13
+ const binPath = RustCoreBridge.resolveBinaryPath();
14
+ const stdout = execFileSync(binPath, ['doctor', '--json'], {
15
+ cwd,
16
+ env: getRunnerEnv(),
17
+ encoding: 'utf8',
18
+ stdio: ['ignore', 'pipe', 'pipe'],
210
19
  });
211
- const missingRequired = dependencies.filter((d) => d.required && !d.installed);
212
- const missingCount = missingRequired.length;
213
- return {
214
- all_ready: missingCount === 0,
215
- missing_count: missingCount,
216
- dependencies,
217
- };
20
+ return JSON.parse(stdout.trim());
218
21
  }
219
22
  export async function doctorCommand(options = {}) {
220
23
  const cwd = process.cwd();
221
- const result = await runSystemChecks(cwd);
24
+ const binPath = RustCoreBridge.resolveBinaryPath();
25
+ const args = ['doctor'];
222
26
  if (options.json) {
27
+ args.push('--json');
28
+ }
29
+ if (options.verbose) {
30
+ args.push('--verbose');
31
+ }
32
+ if (options.fix) {
33
+ args.push('--fix');
34
+ }
35
+ if (options.json) {
36
+ const result = await runSystemChecks(cwd);
223
37
  console.log(JSON.stringify(result, null, 2));
224
38
  return;
225
39
  }
226
- console.log("\x1b[36m┌ 🩺 TestSpectra Doctor: System & Dependency Diagnostics\x1b[0m");
227
- console.log("\x1b[36m│\x1b[0m");
228
- const categories = [
229
- { key: "core", title: "Essential Core Runtimes" },
230
- { key: "web", title: "Web Automation (WebDriverIO & Browsers)" },
231
- { key: "mobile", title: "Mobile Testing (Android & Appium)" },
232
- ];
233
- for (const cat of categories) {
234
- const items = result.dependencies.filter((d) => d.category === cat.key);
235
- if (items.length === 0)
236
- continue;
237
- console.log(`\x1b[36m│\x1b[0m \x1b[1m\x1b[34m${cat.title}\x1b[0m`);
238
- for (const item of items) {
239
- if (item.installed) {
240
- const verStr = item.version ? `\x1b[90m(${item.version})\x1b[0m` : "";
241
- console.log(`\x1b[36m│\x1b[0m \x1b[32m✓\x1b[0m ${item.name.padEnd(28)} ${verStr}`);
242
- }
243
- else if (item.required) {
244
- console.log(`\x1b[36m│\x1b[0m \x1b[31m✗\x1b[0m ${item.name.padEnd(28)} \x1b[31m[Missing - Required]\x1b[0m`);
40
+ return new Promise((resolve, reject) => {
41
+ const child = spawn(binPath, args, {
42
+ cwd,
43
+ env: getRunnerEnv(),
44
+ stdio: 'inherit',
45
+ });
46
+ child.on('close', (code) => {
47
+ if (code === 0 || options.fix) {
48
+ resolve();
245
49
  }
246
50
  else {
247
- console.log(`\x1b[36m│\x1b[0m \x1b[33m!\x1b[0m ${item.name.padEnd(28)} \x1b[90m(Not found - Optional)\x1b[0m`);
51
+ process.exitCode = code ?? 1;
52
+ resolve();
248
53
  }
249
- }
250
- console.log("\x1b[36m│\x1b[0m");
251
- }
252
- console.log("\x1b[36m└──────────────────────────────────────────────────────────\x1b[0m");
253
- if (result.all_ready) {
254
- console.log("\x1b[32m🎉 [TestSpectra] System is 100% ready for Web & Local Test Execution!\x1b[0m\n");
255
- }
256
- else {
257
- console.log(`\x1b[33m⚠️ [TestSpectra] Found ${result.missing_count} missing required dependencies.\x1b[0m`);
258
- console.log(" Run \x1b[36mspectra doctor --fix\x1b[0m or install missing tools above.\n");
259
- if (options.fix) {
260
- console.log("\x1b[36m[Doctor Fix] Attempting automated resolution...\x1b[0m");
261
- const missingPkgs = result.dependencies
262
- .filter((d) => !d.installed && d.category === "web" && d.name.startsWith("WDIO"))
263
- .map((d) => d.name);
264
- if (missingPkgs.length > 0) {
265
- console.log(`Installing workspace packages: ${missingPkgs.join(", ")}`);
266
- try {
267
- execSync("pnpm add -D @wdio/cli webdriverio @wdio/local-runner @wdio/globals @wdio/spec-reporter @wdio/mocha-framework @wdio/devtools-service", {
268
- stdio: "inherit",
269
- });
270
- console.log("\x1b[32m✓ Installed WebDriverIO packages successfully.\x1b[0m");
271
- }
272
- catch (err) {
273
- console.error("\x1b[31m✗ Failed to install packages:\x1b[0m", err.message);
274
- }
275
- }
276
- }
277
- }
54
+ });
55
+ child.on('error', reject);
56
+ });
278
57
  }
@@ -1,5 +1,5 @@
1
1
  export interface InitCommandOptions {
2
2
  force?: boolean;
3
- template?: "default" | "nx";
3
+ template?: 'default' | 'nx';
4
4
  }
5
5
  export declare function initCommand(options?: InitCommandOptions): Promise<void>;