@testspectra/cli 1.0.70 → 1.1.0-rc.0

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 (365) hide show
  1. package/LICENSE.md +48 -0
  2. package/README.md +36 -270
  3. package/bin/spectra.js +1 -1
  4. package/bin/testspectra-runner +0 -0
  5. package/demo-app/assets/index-BGllUp7o.js +140 -0
  6. package/demo-app/assets/index-BhlW-eXG.css +1 -0
  7. package/demo-app/index.html +2 -2
  8. package/dist/.tsbuildinfo +1 -0
  9. package/dist/commands/__tests__/doctor.test.d.ts +1 -0
  10. package/dist/commands/__tests__/doctor.test.js +39 -0
  11. package/dist/commands/__tests__/init.test.d.ts +1 -0
  12. package/dist/commands/__tests__/init.test.js +148 -0
  13. package/dist/commands/__tests__/license.test.d.ts +1 -0
  14. package/dist/commands/__tests__/license.test.js +13 -0
  15. package/dist/commands/__tests__/refactor.test.d.ts +1 -0
  16. package/dist/commands/__tests__/refactor.test.js +64 -0
  17. package/dist/commands/__tests__/run-e2e.test.d.ts +1 -0
  18. package/dist/commands/__tests__/run-e2e.test.js +422 -0
  19. package/dist/commands/__tests__/run.test.d.ts +1 -0
  20. package/dist/commands/__tests__/run.test.js +277 -0
  21. package/dist/commands/__tests__/watch.test.d.ts +1 -0
  22. package/dist/commands/__tests__/watch.test.js +155 -0
  23. package/dist/commands/add.js +86 -85
  24. package/dist/commands/demo.js +21 -11
  25. package/dist/commands/devices.d.ts +14 -2
  26. package/dist/commands/devices.js +44 -34
  27. package/dist/commands/doctor.d.ts +3 -1
  28. package/dist/commands/doctor.js +43 -264
  29. package/dist/commands/init.d.ts +1 -1
  30. package/dist/commands/init.js +206 -196
  31. package/dist/commands/install.d.ts +4 -0
  32. package/dist/commands/install.js +59 -0
  33. package/dist/commands/license.d.ts +4 -0
  34. package/dist/commands/license.js +30 -0
  35. package/dist/commands/lint.d.ts +5 -0
  36. package/dist/commands/lint.js +55 -0
  37. package/dist/commands/refactor.d.ts +9 -0
  38. package/dist/commands/refactor.js +172 -0
  39. package/dist/commands/run.d.ts +23 -2
  40. package/dist/commands/run.js +321 -111
  41. package/dist/commands/skills.d.ts +9 -0
  42. package/dist/commands/skills.js +28 -0
  43. package/dist/commands/sync-types.d.ts +4 -0
  44. package/dist/commands/sync-types.js +14 -0
  45. package/dist/commands/update.js +39 -43
  46. package/dist/commands/watch.d.ts +6 -0
  47. package/dist/commands/watch.js +46 -43
  48. package/dist/config/loader.d.ts +1 -1
  49. package/dist/config/loader.js +40 -25
  50. package/dist/config/schema.d.ts +117 -54
  51. package/dist/config/schema.js +41 -35
  52. package/dist/generator/__tests__/tsconfig-isolation.test.d.ts +1 -0
  53. package/dist/generator/__tests__/tsconfig-isolation.test.js +278 -0
  54. package/dist/generator/__tests__/type-generator.test.d.ts +1 -0
  55. package/dist/generator/__tests__/type-generator.test.js +386 -0
  56. package/dist/generator/index.d.ts +2 -0
  57. package/dist/generator/index.js +2 -0
  58. package/dist/generator/tsconfig-generator.d.ts +27 -0
  59. package/dist/generator/tsconfig-generator.js +384 -0
  60. package/dist/generator/type-generator.d.ts +36 -0
  61. package/dist/generator/type-generator.js +644 -0
  62. package/dist/index.d.ts +9 -5
  63. package/dist/index.js +151 -51
  64. package/dist/lifecycle/__tests__/lifecycle-engine.test.d.ts +1 -0
  65. package/dist/lifecycle/__tests__/lifecycle-engine.test.js +290 -0
  66. package/dist/lifecycle/hook-discovery.d.ts +24 -0
  67. package/dist/lifecycle/hook-discovery.js +60 -0
  68. package/dist/lifecycle/hook-dispatcher.d.ts +34 -0
  69. package/dist/lifecycle/hook-dispatcher.js +190 -0
  70. package/dist/lifecycle/index.d.ts +3 -0
  71. package/dist/lifecycle/index.js +3 -0
  72. package/dist/lifecycle/parallel-grouping.d.ts +27 -0
  73. package/dist/lifecycle/parallel-grouping.js +151 -0
  74. package/dist/linter/__tests__/anonymous-export.test.d.ts +1 -0
  75. package/dist/linter/__tests__/anonymous-export.test.js +184 -0
  76. package/dist/linter/__tests__/shared-lib-boundary.test.d.ts +1 -0
  77. package/dist/linter/__tests__/shared-lib-boundary.test.js +270 -0
  78. package/dist/linter/__tests__/spec-schema.test.d.ts +1 -0
  79. package/dist/linter/__tests__/spec-schema.test.js +369 -0
  80. package/dist/linter/__tests__/step-parity.test.d.ts +1 -0
  81. package/dist/linter/__tests__/step-parity.test.js +372 -0
  82. package/dist/linter/discovery.d.ts +30 -0
  83. package/dist/linter/discovery.js +249 -0
  84. package/dist/linter/extractor.d.ts +66 -0
  85. package/dist/linter/extractor.js +235 -0
  86. package/dist/linter/index.d.ts +7 -0
  87. package/dist/linter/index.js +7 -0
  88. package/dist/linter/parser.d.ts +24 -0
  89. package/dist/linter/parser.js +219 -0
  90. package/dist/linter/schemas/spec.schema.d.ts +83 -0
  91. package/dist/linter/schemas/spec.schema.js +150 -0
  92. package/dist/linter/schemas/suite.schema.d.ts +59 -0
  93. package/dist/linter/schemas/suite.schema.js +83 -0
  94. package/dist/linter/spec-linter.d.ts +23 -0
  95. package/dist/linter/spec-linter.js +595 -0
  96. package/dist/linter/types.d.ts +28 -0
  97. package/dist/linter/types.js +1 -0
  98. package/dist/mobile/__tests__/android-device-e2e.test.d.ts +1 -0
  99. package/dist/mobile/__tests__/android-device-e2e.test.js +53 -0
  100. package/dist/mobile/__tests__/device-pool.test.d.ts +1 -0
  101. package/dist/mobile/__tests__/device-pool.test.js +97 -0
  102. package/dist/mobile/device-pool.d.ts +23 -0
  103. package/dist/mobile/device-pool.js +1 -0
  104. package/dist/mobile/index.d.ts +1 -0
  105. package/dist/mobile/index.js +1 -0
  106. package/dist/refactor/__tests__/refactor-engine.test.d.ts +1 -0
  107. package/dist/refactor/__tests__/refactor-engine.test.js +873 -0
  108. package/dist/refactor/index.d.ts +1 -0
  109. package/dist/refactor/index.js +1 -0
  110. package/dist/refactor/refactor-engine.d.ts +50 -0
  111. package/dist/refactor/refactor-engine.js +587 -0
  112. package/dist/reporter/__tests__/semantic-formatter.test.d.ts +1 -0
  113. package/dist/reporter/__tests__/semantic-formatter.test.js +73 -0
  114. package/dist/reporter/semantic-formatter.d.ts +6 -0
  115. package/dist/reporter/semantic-formatter.js +191 -0
  116. package/dist/reporter/summary-view.d.ts +12 -0
  117. package/dist/reporter/summary-view.js +19 -0
  118. package/dist/reporter/terminal-stream.d.ts +32 -0
  119. package/dist/reporter/terminal-stream.js +82 -0
  120. package/dist/reporter/types.d.ts +2 -0
  121. package/dist/reporter/types.js +1 -0
  122. package/dist/runner/bridge.d.ts +10 -5
  123. package/dist/runner/bridge.js +101 -45
  124. package/dist/runner/reporter.d.ts +32 -2
  125. package/dist/runner/reporter.js +423 -13
  126. package/dist/server/demo.js +43 -44
  127. package/dist/types/generator.d.ts +1 -17
  128. package/dist/types/generator.js +1 -443
  129. package/dist/utils/__tests__/api-server.test.d.ts +1 -0
  130. package/dist/utils/__tests__/api-server.test.js +62 -0
  131. package/dist/utils/__tests__/demo-server.test.d.ts +1 -0
  132. package/dist/utils/__tests__/demo-server.test.js +35 -0
  133. package/dist/utils/api-server.d.ts +19 -0
  134. package/dist/utils/api-server.js +134 -0
  135. package/dist/utils/demo-server.d.ts +5 -0
  136. package/dist/utils/demo-server.js +46 -36
  137. package/package.json +24 -13
  138. package/templates/default/CLAUDE.md +12 -5
  139. package/templates/default/fixtures/apiData.json +24 -0
  140. package/templates/default/package.json +12 -3
  141. package/templates/default/page-objects/MatchersPage/mobile.ts +53 -17
  142. package/templates/default/page-objects/MatchersPage/web.ts +17 -2
  143. package/templates/default/page-objects/NavigationPage/mobile.ts +11 -2
  144. package/templates/default/page-objects/NavigationPage/web.ts +1 -1
  145. package/templates/default/page-objects/PlaygroundPage/mobile.ts +28 -18
  146. package/templates/default/page-objects/PlaygroundPage/web.ts +4 -2
  147. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/mobile.test.ts +53 -0
  148. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/spec.md +19 -0
  149. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/web.test.ts +31 -0
  150. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/android.test.ts +3 -0
  151. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/common.test.ts +3 -0
  152. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/mobile.test.ts +27 -0
  153. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/spec.md +19 -0
  154. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/web.test.ts +26 -0
  155. package/templates/default/specs/ApiInterception/TC-0012-direct-and-late-response/common.test.ts +33 -0
  156. package/templates/default/specs/ApiInterception/TC-0012-direct-and-late-response/spec.md +22 -0
  157. package/templates/default/specs/ApiInterception/TC-0013-real-network-call-recorded/common.test.ts +27 -0
  158. package/templates/default/specs/ApiInterception/TC-0013-real-network-call-recorded/spec.md +20 -0
  159. package/templates/default/specs/ApiInterception/TC-0015-mock-server-sent-events/spec.md +24 -0
  160. package/templates/default/specs/ApiInterception/TC-0015-mock-server-sent-events/web.test.ts +26 -0
  161. package/templates/default/specs/ApiInterception/TC-0016-bypass-websocket-with-app-level-mock/spec.md +37 -0
  162. package/templates/default/specs/ApiInterception/TC-0016-bypass-websocket-with-app-level-mock/web.test.ts +21 -0
  163. package/templates/default/specs/ApiInterception/TC-0017-bypass-captcha-with-test-mode-flag/spec.md +29 -0
  164. package/templates/default/specs/ApiInterception/TC-0017-bypass-captcha-with-test-mode-flag/web.test.ts +16 -0
  165. package/templates/default/specs/ApiInterception/suite.md +10 -0
  166. package/templates/default/specs/ApiSeeding/TC-0014-seed-and-cleanup-via-hooks/common.test.ts +30 -0
  167. package/templates/default/specs/ApiSeeding/TC-0014-seed-and-cleanup-via-hooks/spec.md +23 -0
  168. package/templates/default/specs/ApiSeeding/hooks/after/common.hook.ts +16 -0
  169. package/templates/default/specs/ApiSeeding/hooks/before/common.hook.ts +28 -0
  170. package/templates/default/specs/ApiSeeding/suite.md +9 -0
  171. package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +7 -1
  172. package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/spec.md +5 -0
  173. package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +17 -3
  174. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/common.test.ts +26 -0
  175. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/spec.md +7 -0
  176. package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +9 -1
  177. package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/spec.md +5 -0
  178. package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +9 -4
  179. package/templates/default/specs/DeepLink/TC-0018-navigate-via-deep-link/mobile.test.ts +28 -0
  180. package/templates/default/specs/DeepLink/TC-0018-navigate-via-deep-link/spec.md +29 -0
  181. package/templates/default/specs/DeepLink/suite.md +9 -0
  182. package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +9 -1
  183. package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/spec.md +5 -0
  184. package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +9 -3
  185. package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +27 -1
  186. package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/spec.md +7 -0
  187. package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +27 -6
  188. package/templates/default/specs/ElementMatchers/suite.md +2 -1
  189. package/templates/default/specs/PermissionRationale/TC-0010-camera-permission-allow/mobile.test.ts +26 -0
  190. package/templates/default/specs/PermissionRationale/TC-0010-camera-permission-allow/spec.md +22 -0
  191. package/templates/default/specs/PermissionRationale/TC-0011-camera-permission-deny/mobile.test.ts +13 -0
  192. package/templates/default/specs/PermissionRationale/TC-0011-camera-permission-deny/spec.md +20 -0
  193. package/templates/default/specs/PermissionRationale/suite.md +9 -0
  194. package/templates/default/specs/Playground/TC-0001-form-controls/mobile.test.ts +4 -1
  195. package/templates/default/specs/Playground/TC-0001-form-controls/spec.md +6 -0
  196. package/templates/default/specs/Playground/TC-0001-form-controls/web.test.ts +4 -4
  197. package/templates/default/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +4 -1
  198. package/templates/default/specs/Playground/TC-0002-toggle-elements/spec.md +6 -0
  199. package/templates/default/specs/Playground/TC-0002-toggle-elements/web.test.ts +3 -3
  200. package/templates/default/spectra.config.ts +21 -15
  201. package/templates/default/support/actions/fillCredentials/mobile.action.ts +3 -3
  202. package/templates/default/support/actions/fillCredentials/web.action.ts +1 -1
  203. package/templates/default/support/steps/togglePlaygroundStates/mobile.step.ts +3 -1
  204. package/templates/default/support/steps/togglePlaygroundStates/web.step.ts +3 -3
  205. package/templates/default/support/steps/verifyPlaygroundState/mobile.step.ts +4 -2
  206. package/templates/default/support/steps/verifyPlaygroundState/web.step.ts +4 -4
  207. package/templates/default/tsconfig.json +3 -1
  208. package/templates/nx/.nx/workspace-data/70094CFD-E89B-57A1-9619-2FC5F4963C54.db +0 -0
  209. package/templates/nx/.nx/workspace-data/70094CFD-E89B-57A1-9619-2FC5F4963C54.db-shm +0 -0
  210. package/templates/nx/.nx/workspace-data/70094CFD-E89B-57A1-9619-2FC5F4963C54.db-wal +0 -0
  211. package/templates/nx/.nx/workspace-data/d/daemon.log +4306 -0
  212. package/templates/nx/.nx/workspace-data/d/server-process.json +3 -0
  213. package/templates/nx/.nx/workspace-data/file-map.json +452 -0
  214. package/templates/nx/.nx/workspace-data/lockfile.hash +1 -0
  215. package/templates/nx/.nx/workspace-data/nx_files.nxt +0 -0
  216. package/templates/nx/.nx/workspace-data/parsed-lock-file.json +13485 -0
  217. package/templates/nx/.nx/workspace-data/project-graph.json +14389 -0
  218. package/templates/nx/CLAUDE.md +2 -2
  219. package/templates/nx/package.json +6 -4
  220. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/mobile.test.ts +27 -0
  221. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/spec.md +12 -0
  222. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/web.test.ts +27 -0
  223. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/mobile.test.ts +24 -0
  224. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/spec.md +12 -0
  225. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/web.test.ts +24 -0
  226. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/suite.md +9 -0
  227. package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +1 -1
  228. package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +17 -3
  229. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +1 -1
  230. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +15 -5
  231. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +1 -1
  232. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +9 -4
  233. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +1 -1
  234. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +9 -3
  235. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +1 -1
  236. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +27 -6
  237. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0001-form-controls/mobile.test.ts +1 -1
  238. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0001-form-controls/web.test.ts +4 -4
  239. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +1 -1
  240. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0002-toggle-elements/web.test.ts +3 -3
  241. package/templates/nx/pnpm-lock.yaml +6663 -0
  242. package/templates/nx/pnpm-workspace.yaml +2 -1
  243. package/templates/nx/shared/testing/fixtures/apiData.json +24 -0
  244. package/templates/nx/shared/testing/page-objects/MatchersPage/mobile.ts +13 -1
  245. package/templates/nx/shared/testing/page-objects/MatchersPage/web.ts +85 -17
  246. package/templates/nx/shared/testing/page-objects/NavigationPage/mobile.ts +1 -1
  247. package/templates/nx/shared/testing/page-objects/NavigationPage/web.ts +1 -1
  248. package/templates/nx/shared/testing/page-objects/PlaygroundPage/mobile.ts +1 -1
  249. package/templates/nx/shared/testing/page-objects/PlaygroundPage/web.ts +4 -2
  250. package/templates/nx/shared/testing/project.json +19 -0
  251. package/templates/nx/shared/testing/support/actions/fillCredentials/mobile.action.ts +1 -1
  252. package/templates/nx/shared/testing/support/actions/fillCredentials/web.action.ts +1 -1
  253. package/templates/nx/shared/testing/support/steps/togglePlaygroundStates/mobile.step.ts +1 -1
  254. package/templates/nx/shared/testing/support/steps/togglePlaygroundStates/web.step.ts +3 -3
  255. package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/mobile.step.ts +2 -2
  256. package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/web.step.ts +4 -4
  257. package/templates/nx/spectra.config.ts +19 -13
  258. package/templates/nx/tsconfig.json +3 -1
  259. package/demo-app/assets/index-DAUlrHTr.css +0 -1
  260. package/demo-app/assets/index-DN2Kb0A8.js +0 -100
  261. package/dist/index.cjs +0 -101
  262. package/dist/plugin.cjs +0 -575
  263. package/dist/plugin.d.ts +0 -16
  264. package/dist/plugin.js +0 -184
  265. package/dist/step/index.d.ts +0 -6
  266. package/dist/step/index.js +0 -6
  267. package/dist/step/matchers.d.ts +0 -14
  268. package/dist/step/matchers.js +0 -114
  269. package/dist/step/proto.d.ts +0 -46
  270. package/dist/step/proto.js +0 -114
  271. package/dist/step/runner/collection.d.ts +0 -13
  272. package/dist/step/runner/collection.js +0 -51
  273. package/dist/step/runner/single.d.ts +0 -21
  274. package/dist/step/runner/single.js +0 -138
  275. package/dist/step/spectra.d.ts +0 -34
  276. package/dist/step/spectra.js +0 -156
  277. package/dist/step/types.d.ts +0 -32
  278. package/dist/step/types.js +0 -5
  279. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +0 -3
  280. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +0 -7
  281. package/templates/default/tsconfig.spectra.android.json +0 -46
  282. package/templates/default/tsconfig.spectra.ios.json +0 -46
  283. package/templates/default/tsconfig.spectra.json +0 -22
  284. package/templates/default/tsconfig.spectra.web.json +0 -53
  285. package/templates/nx/fixtures/playgroundData.json +0 -7
  286. package/templates/nx/global-hooks/after/mobile.hook.ts +0 -3
  287. package/templates/nx/global-hooks/after/web.hook.ts +0 -3
  288. package/templates/nx/global-hooks/before/mobile.hook.ts +0 -3
  289. package/templates/nx/global-hooks/before/web.hook.ts +0 -3
  290. package/templates/nx/page-objects/MatchersPage/mobile.ts +0 -21
  291. package/templates/nx/page-objects/MatchersPage/web.ts +0 -23
  292. package/templates/nx/page-objects/NavigationPage/mobile.ts +0 -5
  293. package/templates/nx/page-objects/NavigationPage/web.ts +0 -8
  294. package/templates/nx/page-objects/PlaygroundPage/mobile.ts +0 -26
  295. package/templates/nx/page-objects/PlaygroundPage/web.ts +0 -29
  296. package/templates/nx/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +0 -3
  297. package/templates/nx/specs/BrowserContext/TC-0007-title-and-navigation/spec.md +0 -12
  298. package/templates/nx/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +0 -5
  299. package/templates/nx/specs/BrowserContext/suite.md +0 -9
  300. package/templates/nx/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +0 -3
  301. package/templates/nx/specs/ContentMatchers/TC-0005-text-and-values/spec.md +0 -12
  302. package/templates/nx/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +0 -7
  303. package/templates/nx/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +0 -3
  304. package/templates/nx/specs/ContentMatchers/TC-0006-collections-and-empty/spec.md +0 -12
  305. package/templates/nx/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +0 -6
  306. package/templates/nx/specs/ContentMatchers/suite.md +0 -9
  307. package/templates/nx/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +0 -3
  308. package/templates/nx/specs/ElementMatchers/TC-0003-visibility-and-dom/spec.md +0 -12
  309. package/templates/nx/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +0 -5
  310. package/templates/nx/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +0 -3
  311. package/templates/nx/specs/ElementMatchers/TC-0004-states-and-attributes/spec.md +0 -12
  312. package/templates/nx/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +0 -8
  313. package/templates/nx/specs/ElementMatchers/hooks/after/mobile.hook.ts +0 -1
  314. package/templates/nx/specs/ElementMatchers/hooks/after/web.hook.ts +0 -1
  315. package/templates/nx/specs/ElementMatchers/hooks/afterEach/mobile.hook.ts +0 -1
  316. package/templates/nx/specs/ElementMatchers/hooks/afterEach/web.hook.ts +0 -1
  317. package/templates/nx/specs/ElementMatchers/hooks/before/mobile.hook.ts +0 -1
  318. package/templates/nx/specs/ElementMatchers/hooks/before/web.hook.ts +0 -1
  319. package/templates/nx/specs/ElementMatchers/hooks/beforeEach/mobile.hook.ts +0 -1
  320. package/templates/nx/specs/ElementMatchers/hooks/beforeEach/web.hook.ts +0 -1
  321. package/templates/nx/specs/ElementMatchers/suite.md +0 -9
  322. package/templates/nx/specs/Playground/TC-0001-form-controls/mobile.test.ts +0 -3
  323. package/templates/nx/specs/Playground/TC-0001-form-controls/spec.md +0 -12
  324. package/templates/nx/specs/Playground/TC-0001-form-controls/web.test.ts +0 -6
  325. package/templates/nx/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +0 -3
  326. package/templates/nx/specs/Playground/TC-0002-toggle-elements/spec.md +0 -12
  327. package/templates/nx/specs/Playground/TC-0002-toggle-elements/web.test.ts +0 -6
  328. package/templates/nx/specs/Playground/hooks/after/mobile.hook.ts +0 -1
  329. package/templates/nx/specs/Playground/hooks/after/web.hook.ts +0 -1
  330. package/templates/nx/specs/Playground/hooks/afterEach/mobile.hook.ts +0 -1
  331. package/templates/nx/specs/Playground/hooks/afterEach/web.hook.ts +0 -1
  332. package/templates/nx/specs/Playground/hooks/before/mobile.hook.ts +0 -1
  333. package/templates/nx/specs/Playground/hooks/before/web.hook.ts +0 -1
  334. package/templates/nx/specs/Playground/hooks/beforeEach/mobile.hook.ts +0 -1
  335. package/templates/nx/specs/Playground/hooks/beforeEach/web.hook.ts +0 -1
  336. package/templates/nx/specs/Playground/suite.md +0 -9
  337. package/templates/nx/support/actions/fillCredentials/mobile.action.ts +0 -4
  338. package/templates/nx/support/actions/fillCredentials/web.action.ts +0 -4
  339. package/templates/nx/support/steps/togglePlaygroundStates/mobile.step.ts +0 -3
  340. package/templates/nx/support/steps/togglePlaygroundStates/step.md +0 -7
  341. package/templates/nx/support/steps/togglePlaygroundStates/web.step.ts +0 -5
  342. package/templates/nx/support/steps/verifyPlaygroundState/mobile.step.ts +0 -4
  343. package/templates/nx/support/steps/verifyPlaygroundState/step.md +0 -7
  344. package/templates/nx/support/steps/verifyPlaygroundState/web.step.ts +0 -6
  345. package/templates/nx/tsconfig.spectra.android.json +0 -39
  346. package/templates/nx/tsconfig.spectra.ios.json +0 -39
  347. package/templates/nx/tsconfig.spectra.json +0 -25
  348. package/templates/nx/tsconfig.spectra.shared.json +0 -25
  349. package/templates/nx/tsconfig.spectra.web.json +0 -45
  350. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/after/mobile.hook.ts +0 -0
  351. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/after/web.hook.ts +0 -0
  352. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/afterEach/mobile.hook.ts +0 -0
  353. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/afterEach/web.hook.ts +0 -0
  354. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/before/mobile.hook.ts +0 -0
  355. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/before/web.hook.ts +0 -0
  356. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/beforeEach/mobile.hook.ts +0 -0
  357. /package/templates/{nx/specs/BrowserContext → default/specs/ApiInterception}/hooks/beforeEach/web.hook.ts +0 -0
  358. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/after/mobile.hook.ts +0 -0
  359. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/after/web.hook.ts +0 -0
  360. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/afterEach/mobile.hook.ts +0 -0
  361. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/afterEach/web.hook.ts +0 -0
  362. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/before/mobile.hook.ts +0 -0
  363. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/before/web.hook.ts +0 -0
  364. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/beforeEach/mobile.hook.ts +0 -0
  365. /package/templates/nx/{specs/ContentMatchers → packages/matchers/e2e/specs/ApiInterception}/hooks/beforeEach/web.hook.ts +0 -0
@@ -0,0 +1,73 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { formatAction, formatAssertion } from '../semantic-formatter.js';
3
+ describe('semantic-formatter', () => {
4
+ describe('formatAction', () => {
5
+ it('formats click', () => expect(formatAction('click', 'LoginPage.submitButton')).toBe('Click on element "LoginPage.submitButton"'));
6
+ it('formats doubleClick', () => expect(formatAction('doubleClick', 'targetBtn')).toBe('Double-click on element "targetBtn"'));
7
+ it('formats rightClick', () => expect(formatAction('rightClick', 'targetBtn')).toBe('Right-click on element "targetBtn"'));
8
+ it('formats type', () => expect(formatAction('type', 'LoginPage.emailInput', { text: 'admin@testspectra.dev' })).toBe('Type "admin@testspectra.dev" into element "LoginPage.emailInput"'));
9
+ it('formats clear', () => expect(formatAction('clear', 'input')).toBe('Clear text in element "input"'));
10
+ it('formats select', () => expect(formatAction('select', 'dropdown', { option: 'Option A' })).toBe('Select option "Option A" in element "dropdown"'));
11
+ it('formats hover', () => expect(formatAction('hover', 'menu')).toBe('Hover over element "menu"'));
12
+ it('formats dragDrop', () => expect(formatAction('dragDrop', 'source', { dest: 'dest' })).toBe('Drag element "source" and drop onto element "dest"'));
13
+ it('formats scrollIntoView', () => expect(formatAction('scrollIntoView', 'footer')).toBe('Scroll element "footer" into view'));
14
+ it('formats longPress', () => expect(formatAction('longPress', 'btn', { durationMs: 1500 })).toBe('Long-press on element "btn" for 1500ms'));
15
+ it('formats waitForElement', () => expect(formatAction('waitForElement', 'modal')).toBe('Wait for element "modal" to be displayed'));
16
+ it('formats navigate', () => expect(formatAction('navigate', undefined, { url: '/login' })).toBe('Navigate to "/login"'));
17
+ it('formats back', () => expect(formatAction('back')).toBe('Navigate back in browser'));
18
+ it('formats forward', () => expect(formatAction('forward')).toBe('Navigate forward in browser'));
19
+ it('formats refresh', () => expect(formatAction('refresh')).toBe('Refresh current page'));
20
+ it('formats setViewport', () => expect(formatAction('setViewport', undefined, { width: 1920, height: 1080 })).toBe('Set viewport to 1920x1080'));
21
+ it('formats wait', () => expect(formatAction('wait', undefined, { ms: 1000 })).toBe('Wait for 1000ms'));
22
+ it('formats pressKey', () => expect(formatAction('pressKey', undefined, { key: 'Enter' })).toBe('Press keyboard key "Enter"'));
23
+ it('formats scroll', () => expect(formatAction('scroll', undefined, { direction: 'down', pixels: 400 })).toBe('Scroll down by 400px'));
24
+ it('formats swipe', () => expect(formatAction('swipe', undefined, { direction: 'left', distance: 300 })).toBe('Swipe left by 300px'));
25
+ it('formats intercept', () => expect(formatAction('intercept', undefined, { method: 'GET', url: '/api/data' })).toBe('Intercept GET "/api/data" mock rule registered'));
26
+ it('formats clearCookies', () => expect(formatAction('clearCookies')).toBe('Clear all browser cookies'));
27
+ it('formats clearLocalStorage', () => expect(formatAction('clearLocalStorage')).toBe('Clear browser localStorage'));
28
+ });
29
+ describe('formatAssertion', () => {
30
+ // 38 assertions
31
+ it('formats be.visible', () => expect(formatAssertion('be.visible', 'DashboardPage.header')).toBe('Expect element "DashboardPage.header" to be visible'));
32
+ it('formats not.be.visible', () => expect(formatAssertion('not.be.visible', 'DashboardPage.header')).toBe('Expect element "DashboardPage.header" not to be visible'));
33
+ it('formats exist', () => expect(formatAssertion('exist', 'DashboardPage.header')).toBe('Expect element "DashboardPage.header" to exist in DOM'));
34
+ it('formats not.exist', () => expect(formatAssertion('not.exist', 'DashboardPage.header')).toBe('Expect element "DashboardPage.header" not to exist in DOM'));
35
+ it('formats be.clickable', () => expect(formatAssertion('be.clickable', 'btn')).toBe('Expect element "btn" to be clickable'));
36
+ it('formats not.be.clickable', () => expect(formatAssertion('not.be.clickable', 'btn')).toBe('Expect element "btn" not to be clickable'));
37
+ it('formats be.enabled', () => expect(formatAssertion('be.enabled', 'btn')).toBe('Expect element "btn" to be enabled'));
38
+ it('formats be.disabled', () => expect(formatAssertion('be.disabled', 'btn')).toBe('Expect element "btn" to be disabled'));
39
+ it('formats be.checked', () => expect(formatAssertion('be.checked', 'checkbox')).toBe('Expect element "checkbox" to be checked'));
40
+ it('formats not.be.checked', () => expect(formatAssertion('not.be.checked', 'checkbox')).toBe('Expect element "checkbox" not to be checked'));
41
+ it('formats be.selected', () => expect(formatAssertion('be.selected', 'radio')).toBe('Expect element "radio" to be selected'));
42
+ it('formats not.be.selected', () => expect(formatAssertion('not.be.selected', 'radio')).toBe('Expect element "radio" not to be selected'));
43
+ it('formats be.focused', () => expect(formatAssertion('be.focused', 'input')).toBe('Expect element "input" to be focused'));
44
+ it('formats not.be.focused', () => expect(formatAssertion('not.be.focused', 'input')).toBe('Expect element "input" not to be focused'));
45
+ it('formats have.text', () => expect(formatAssertion('have.text', 'title', { expected: 'Hello' })).toBe('Expect element "title" to have text "Hello"'));
46
+ it('formats not.have.text', () => expect(formatAssertion('not.have.text', 'title', { expected: 'Hello' })).toBe('Expect element "title" not to have text "Hello"'));
47
+ it('formats contain.text', () => expect(formatAssertion('contain.text', 'title', { expected: 'Hello' })).toBe('Expect element "title" to contain text "Hello"'));
48
+ it('formats not.contain.text', () => expect(formatAssertion('not.contain.text', 'title', { expected: 'Hello' })).toBe('Expect element "title" not to contain text "Hello"'));
49
+ it('formats have.value', () => expect(formatAssertion('have.value', 'input', { expected: 'admin' })).toBe('Expect element "input" to have value "admin"'));
50
+ it('formats not.have.value', () => expect(formatAssertion('not.have.value', 'input', { expected: 'admin' })).toBe('Expect element "input" not to have value "admin"'));
51
+ it('formats contain.value', () => expect(formatAssertion('contain.value', 'input', { expected: 'min' })).toBe('Expect element "input" to contain value "min"'));
52
+ it('formats not.contain.value', () => expect(formatAssertion('not.contain.value', 'input', { expected: 'min' })).toBe('Expect element "input" not to contain value "min"'));
53
+ it('formats have.attr', () => expect(formatAssertion('have.attr', 'img', { name: 'alt', value: 'logo' })).toBe('Expect element "img" to have attribute "alt" = "logo"'));
54
+ it('formats not.have.attr', () => expect(formatAssertion('not.have.attr', 'img', { name: 'alt' })).toBe('Expect element "img" not to have attribute "alt"'));
55
+ it('formats have.class', () => expect(formatAssertion('have.class', 'div', { expected: 'active' })).toBe('Expect element "div" to have class "active"'));
56
+ it('formats not.have.class', () => expect(formatAssertion('not.have.class', 'div', { expected: 'active' })).toBe('Expect element "div" not to have class "active"'));
57
+ it('formats have.css', () => expect(formatAssertion('have.css', 'div', { name: 'color', value: 'red' })).toBe('Expect element "div" to have CSS "color" = "red"'));
58
+ it('formats not.have.css', () => expect(formatAssertion('not.have.css', 'div', { name: 'color', value: 'red' })).toBe('Expect element "div" not to have CSS "color" = "red"'));
59
+ it('formats have.length', () => expect(formatAssertion('have.length', 'DashboardPage.statCards', { expected: 4 })).toBe('Expect collection "DashboardPage.statCards" count to equal 4'));
60
+ it('formats not.have.length', () => expect(formatAssertion('not.have.length', 'cards', { expected: 4 })).toBe('Expect collection "cards" count not to equal 4'));
61
+ it('formats have.length.greaterThan', () => expect(formatAssertion('have.length.greaterThan', 'cards', { expected: 2 })).toBe('Expect collection "cards" count to be greater than 2'));
62
+ it('formats have.length.lessThan', () => expect(formatAssertion('have.length.lessThan', 'cards', { expected: 10 })).toBe('Expect collection "cards" count to be less than 10'));
63
+ it('formats be.empty', () => expect(formatAssertion('be.empty', 'cards')).toBe('Expect collection "cards" to be empty'));
64
+ it('formats not.be.empty', () => expect(formatAssertion('not.be.empty', 'cards')).toBe('Expect collection "cards" not to be empty'));
65
+ it('formats shouldHaveUrl', () => expect(formatAssertion('shouldHaveUrl', undefined, { expected: '/home' })).toBe('Expect browser URL to be "/home"'));
66
+ it('formats shouldContainUrl', () => expect(formatAssertion('shouldContainUrl', undefined, { expected: '/home' })).toBe('Expect browser URL to contain "/home"'));
67
+ it('formats shouldHaveTitle', () => expect(formatAssertion('shouldHaveTitle', undefined, { expected: 'Home' })).toBe('Expect browser title to be "Home"'));
68
+ it('formats shouldContainTitle', () => expect(formatAssertion('shouldContainTitle', undefined, { expected: 'Home' })).toBe('Expect browser title to contain "Home"'));
69
+ it('formats shouldBeLoaded', () => expect(formatAssertion('shouldBeLoaded', undefined)).toBe('Expect page to be fully loaded'));
70
+ it('formats shouldBePageLoaded', () => expect(formatAssertion('shouldBePageLoaded', undefined)).toBe('Expect page to be fully loaded'));
71
+ it('formats shouldHaveNoConsoleErrors', () => expect(formatAssertion('shouldHaveNoConsoleErrors', undefined)).toBe('Expect browser console to have no errors'));
72
+ });
73
+ });
@@ -0,0 +1,6 @@
1
+ import { ActionKey, AssertionKey } from './types.js';
2
+ /**
3
+ * Transforms raw matcher assertions and element commands into grammatically correct English sentences.
4
+ */
5
+ export declare function formatAction(actionKey: ActionKey | string, target?: any, args?: Record<string, any>): string;
6
+ export declare function formatAssertion(assertionKey: AssertionKey | string, target?: any, args?: Record<string, any>): string;
@@ -0,0 +1,191 @@
1
+ function extractTargetString(target) {
2
+ if (!target)
3
+ return '';
4
+ if (typeof target === 'string')
5
+ return target;
6
+ if (typeof target === 'object') {
7
+ if (typeof target.selector === 'string')
8
+ return target.selector;
9
+ if (typeof target.name === 'string')
10
+ return target.name;
11
+ if (typeof target.target === 'string')
12
+ return target.target;
13
+ }
14
+ return String(target);
15
+ }
16
+ function formatElementTarget(target) {
17
+ const sel = extractTargetString(target);
18
+ if (!sel)
19
+ return 'element {target}';
20
+ if (sel.startsWith('element "') || sel.startsWith('collection "')) {
21
+ return sel;
22
+ }
23
+ return `element "${sel}"`;
24
+ }
25
+ function formatCollectionTarget(target) {
26
+ const sel = extractTargetString(target);
27
+ if (!sel)
28
+ return 'collection "{selector}"';
29
+ if (sel.startsWith('collection "')) {
30
+ return sel;
31
+ }
32
+ return `collection "${sel}"`;
33
+ }
34
+ /**
35
+ * Transforms raw matcher assertions and element commands into grammatically correct English sentences.
36
+ */
37
+ export function formatAction(actionKey, target, args = {}) {
38
+ const el = formatElementTarget(target);
39
+ switch (actionKey) {
40
+ case 'click':
41
+ return `Click on ${el}`;
42
+ case 'doubleClick':
43
+ return `Double-click on ${el}`;
44
+ case 'rightClick':
45
+ return `Right-click on ${el}`;
46
+ case 'type':
47
+ return `Type "${args.text ?? args.value ?? '{text}'}" into ${el}`;
48
+ case 'clear':
49
+ return `Clear text in ${el}`;
50
+ case 'select':
51
+ case 'selectOption':
52
+ return `Select option "${args.option ?? args.value ?? args.text ?? '{option}'}" in ${el}`;
53
+ case 'hover':
54
+ return `Hover over ${el}`;
55
+ case 'dragDrop':
56
+ const dest = args.dest || args.destination ? formatElementTarget(args.dest || args.destination) : 'element {dest}';
57
+ return `Drag ${el} and drop onto ${dest}`;
58
+ case 'scrollIntoView':
59
+ return `Scroll ${el} into view`;
60
+ case 'longPress':
61
+ return `Long-press on ${el} for ${args.durationMs ?? args.ms ?? args.duration ?? '{durationMs}'}ms`;
62
+ case 'waitForElement':
63
+ return `Wait for ${el} to be displayed`;
64
+ case 'navigate':
65
+ return `Navigate to "${args.url ?? '{url}'}"`;
66
+ case 'back':
67
+ return `Navigate back in browser`;
68
+ case 'forward':
69
+ return `Navigate forward in browser`;
70
+ case 'refresh':
71
+ return `Refresh current page`;
72
+ case 'setViewport':
73
+ return `Set viewport to ${args.width ?? '{width}'}x${args.height ?? '{height}'}`;
74
+ case 'wait':
75
+ return `Wait for ${args.ms ?? args.durationMs ?? '{ms}'}ms`;
76
+ case 'pressKey':
77
+ return `Press keyboard key "${args.key ?? args.value ?? '{key}'}"`;
78
+ case 'scroll':
79
+ return `Scroll ${args.direction ?? '{direction}'} by ${args.pixels ?? '{pixels}'}px`;
80
+ case 'swipe':
81
+ return `Swipe ${args.direction ?? '{direction}'} by ${args.distance ?? '{distance}'}px`;
82
+ case 'intercept':
83
+ return `Intercept ${args.method ?? '{method}'} "${args.url ?? '{url}'}" mock rule registered`;
84
+ case 'clearCookies':
85
+ return `Clear all browser cookies`;
86
+ case 'clearLocalStorage':
87
+ return `Clear browser localStorage`;
88
+ default:
89
+ return `Perform ${actionKey} on ${el}`;
90
+ }
91
+ }
92
+ export function formatAssertion(assertionKey, target, args = {}) {
93
+ const el = formatElementTarget(target);
94
+ const col = formatCollectionTarget(target);
95
+ switch (assertionKey) {
96
+ case 'be.visible':
97
+ return `Expect ${el} to be visible`;
98
+ case 'not.be.visible':
99
+ return `Expect ${el} not to be visible`;
100
+ case 'exist':
101
+ return `Expect ${el} to exist in DOM`;
102
+ case 'not.exist':
103
+ return `Expect ${el} not to exist in DOM`;
104
+ case 'be.clickable':
105
+ return `Expect ${el} to be clickable`;
106
+ case 'not.be.clickable':
107
+ return `Expect ${el} not to be clickable`;
108
+ case 'be.enabled':
109
+ return `Expect ${el} to be enabled`;
110
+ case 'be.disabled':
111
+ return `Expect ${el} to be disabled`;
112
+ case 'be.checked':
113
+ return `Expect ${el} to be checked`;
114
+ case 'not.be.checked':
115
+ return `Expect ${el} not to be checked`;
116
+ case 'be.selected':
117
+ return `Expect ${el} to be selected`;
118
+ case 'not.be.selected':
119
+ return `Expect ${el} not to be selected`;
120
+ case 'be.focused':
121
+ return `Expect ${el} to be focused`;
122
+ case 'not.be.focused':
123
+ return `Expect ${el} not to be focused`;
124
+ case 'have.text':
125
+ return `Expect ${el} to have text "${args.expected ?? args.text ?? '{str}'}"`;
126
+ case 'not.have.text':
127
+ return `Expect ${el} not to have text "${args.expected ?? args.text ?? '{str}'}"`;
128
+ case 'contain.text':
129
+ return `Expect ${el} to contain text "${args.expected ?? args.text ?? '{sub}'}"`;
130
+ case 'not.contain.text':
131
+ return `Expect ${el} not to contain text "${args.expected ?? args.text ?? '{s}'}"`;
132
+ case 'have.value':
133
+ return `Expect ${el} to have value "${args.expected ?? args.value ?? '{val}'}"`;
134
+ case 'not.have.value':
135
+ return `Expect ${el} not to have value "${args.expected ?? args.value ?? '{val}'}"`;
136
+ case 'contain.value':
137
+ return `Expect ${el} to contain value "${args.expected ?? args.value ?? '{s}'}"`;
138
+ case 'not.contain.value':
139
+ return `Expect ${el} not to contain value "${args.expected ?? args.value ?? '{s}'}"`;
140
+ case 'have.attr':
141
+ return args.value !== undefined
142
+ ? `Expect ${el} to have attribute "${args.name ?? args.expected ?? '{k}'}" = "${args.value}"`
143
+ : `Expect ${el} to have attribute "${args.name ?? args.expected ?? '{k}'}"`;
144
+ case 'not.have.attr':
145
+ return `Expect ${el} not to have attribute "${args.name ?? args.expected ?? '{k}'}"`;
146
+ case 'have.class':
147
+ return `Expect ${el} to have class "${args.expected ?? args.className ?? '{cls}'}"`;
148
+ case 'not.have.class':
149
+ return `Expect ${el} not to have class "${args.expected ?? args.className ?? '{cls}'}"`;
150
+ case 'have.css':
151
+ return `Expect ${el} to have CSS "${args.name ?? args.property ?? '{prop}'}" = "${args.value ?? '{val}'}"`;
152
+ case 'not.have.css':
153
+ return `Expect ${el} not to have CSS "${args.name ?? args.property ?? '{p}'}" = "${args.value ?? '{v}'}"`;
154
+ // Collections
155
+ case 'have.length':
156
+ return `Expect ${col} count to equal ${args.expected ?? args.length ?? '{n}'}`;
157
+ case 'not.have.length':
158
+ return `Expect ${col} count not to equal ${args.expected ?? args.length ?? '{n}'}`;
159
+ case 'have.length.greaterThan':
160
+ return `Expect ${col} count to be greater than ${args.expected ?? args.min ?? '{n}'}`;
161
+ case 'have.length.lessThan':
162
+ return `Expect ${col} count to be less than ${args.expected ?? args.max ?? '{n}'}`;
163
+ case 'be.empty':
164
+ return `Expect ${col} to be empty`;
165
+ case 'not.be.empty':
166
+ return `Expect ${col} not to be empty`;
167
+ // Browser Context
168
+ case 'have.url':
169
+ case 'shouldHaveUrl':
170
+ return `Expect browser URL to be "${args.expected ?? args.url ?? '{url}'}"`;
171
+ case 'contain.url':
172
+ case 'shouldContainUrl':
173
+ return `Expect browser URL to contain "${args.expected ?? args.url ?? '{url}'}"`;
174
+ case 'have.title':
175
+ case 'shouldHaveTitle':
176
+ return `Expect browser title to be "${args.expected ?? args.title ?? '{title}'}"`;
177
+ case 'contain.title':
178
+ case 'shouldContainTitle':
179
+ return `Expect browser title to contain "${args.expected ?? args.title ?? '{title}'}"`;
180
+ case 'be.loaded':
181
+ case 'shouldBeLoaded':
182
+ case 'be.pageLoaded':
183
+ case 'shouldBePageLoaded':
184
+ return `Expect page to be fully loaded`;
185
+ case 'have.noConsoleErrors':
186
+ case 'shouldHaveNoConsoleErrors':
187
+ return `Expect browser console to have no errors`;
188
+ default:
189
+ return `Expect ${el} to match ${assertionKey}`;
190
+ }
191
+ }
@@ -0,0 +1,12 @@
1
+ export interface ExecutionSummary {
2
+ totalSuites: number;
3
+ totalTests: number;
4
+ passedCount: number;
5
+ failedCount: number;
6
+ durationMs: number;
7
+ reportLocation: string;
8
+ }
9
+ /**
10
+ * Renders the final execution summary box.
11
+ */
12
+ export declare function renderSummaryView(summary: ExecutionSummary): void;
@@ -0,0 +1,19 @@
1
+ import chalk from 'chalk';
2
+ /**
3
+ * Renders the final execution summary box.
4
+ */
5
+ export function renderSummaryView(summary) {
6
+ const { totalSuites, totalTests, passedCount, failedCount, durationMs, reportLocation } = summary;
7
+ const durationSec = (durationMs / 1000).toFixed(2);
8
+ console.log();
9
+ console.log(chalk.bold('TestSpectra Execution Summary'));
10
+ console.log(chalk.gray('────────────────────────────────────────'));
11
+ console.log(`Suites: ${chalk.bold(totalSuites)}`);
12
+ console.log(`Tests: ${chalk.bold(totalTests)} total, ` +
13
+ `${passedCount > 0 ? chalk.green.bold(`${passedCount} passed`) : '0 passed'}, ` +
14
+ `${failedCount > 0 ? chalk.red.bold(`${failedCount} failed`) : '0 failed'}`);
15
+ console.log(`Duration: ${durationSec}s`);
16
+ console.log(`Report: ${chalk.cyan(reportLocation)}`);
17
+ console.log(chalk.gray('────────────────────────────────────────'));
18
+ console.log();
19
+ }
@@ -0,0 +1,32 @@
1
+ export declare class TerminalStream {
2
+ private spinner;
3
+ private currentTestTitle;
4
+ private stepCount;
5
+ constructor();
6
+ /**
7
+ * Starts a new test case, logging the pending bullet and test title.
8
+ */
9
+ startTest(title: string): void;
10
+ /**
11
+ * Begins a new step, rendering an active spinner on the terminal with 2 spaces indentation.
12
+ */
13
+ startStep(text: string): void;
14
+ /**
15
+ * Marks the current step as passed, updating the spinner to a green checkmark
16
+ * and appending the duration in gray with 2 spaces indentation.
17
+ */
18
+ passStep(text: string, durationMs: number): void;
19
+ /**
20
+ * Marks the current step as failed, updating the spinner to a red cross,
21
+ * coloring the text red, appending the duration, and optionally logging the error with 2 spaces indentation.
22
+ */
23
+ failStep(text: string, durationMs: number, errorMsg?: string): void;
24
+ /**
25
+ * Concludes the active test case as passed, overwriting the initial "●" line with "✓" and duration in-place.
26
+ */
27
+ passTest(title: string, durationMs: number): void;
28
+ /**
29
+ * Concludes the active test case as failed, overwriting the initial "●" line with "✗" and duration in-place.
30
+ */
31
+ failTest(title: string, durationMs: number): void;
32
+ }
@@ -0,0 +1,82 @@
1
+ import ora from 'ora';
2
+ import chalk from 'chalk';
3
+ export class TerminalStream {
4
+ spinner;
5
+ currentTestTitle = '';
6
+ stepCount = 0;
7
+ constructor() {
8
+ this.spinner = ora({
9
+ spinner: 'dots',
10
+ color: 'cyan',
11
+ prefixText: ' ',
12
+ });
13
+ }
14
+ /**
15
+ * Starts a new test case, logging the pending bullet and test title.
16
+ */
17
+ startTest(title) {
18
+ if (this.spinner.isSpinning) {
19
+ this.spinner.stop();
20
+ }
21
+ this.currentTestTitle = title;
22
+ this.stepCount = 0;
23
+ console.log(`${chalk.hex('#2dd4bf')('●')} ${chalk.white.bold(title)}`);
24
+ }
25
+ /**
26
+ * Begins a new step, rendering an active spinner on the terminal with 2 spaces indentation.
27
+ */
28
+ startStep(text) {
29
+ if (this.spinner.isSpinning) {
30
+ this.spinner.stop();
31
+ }
32
+ this.spinner.start(text);
33
+ }
34
+ /**
35
+ * Marks the current step as passed, updating the spinner to a green checkmark
36
+ * and appending the duration in gray with 2 spaces indentation.
37
+ */
38
+ passStep(text, durationMs) {
39
+ const durationStr = chalk.gray(`(${durationMs}ms)`);
40
+ this.spinner.succeed(`${text} ${durationStr}`);
41
+ this.stepCount++;
42
+ }
43
+ /**
44
+ * Marks the current step as failed, updating the spinner to a red cross,
45
+ * coloring the text red, appending the duration, and optionally logging the error with 2 spaces indentation.
46
+ */
47
+ failStep(text, durationMs, errorMsg) {
48
+ const durationStr = chalk.gray(`(${durationMs}ms)`);
49
+ this.spinner.fail(`${chalk.red(text)} ${durationStr}`);
50
+ this.stepCount++;
51
+ if (errorMsg) {
52
+ console.error(chalk.red(` ↳ ${errorMsg}`));
53
+ this.stepCount++;
54
+ }
55
+ }
56
+ /**
57
+ * Concludes the active test case as passed, overwriting the initial "●" line with "✓" and duration in-place.
58
+ */
59
+ passTest(title, durationMs) {
60
+ if (this.spinner.isSpinning) {
61
+ this.spinner.stop();
62
+ }
63
+ const testTitle = title || this.currentTestTitle;
64
+ const durationStr = chalk.gray(`(${durationMs}ms)`);
65
+ const completedHeader = `${chalk.hex('#34d399')('✓')} ${chalk.white.bold(testTitle)} ${durationStr}`;
66
+ const linesToMoveUp = this.stepCount + 1;
67
+ process.stdout.write(`\x1b[${linesToMoveUp}A\r\x1b[2K${completedHeader}\x1b[${linesToMoveUp}B\r\n`);
68
+ }
69
+ /**
70
+ * Concludes the active test case as failed, overwriting the initial "●" line with "✗" and duration in-place.
71
+ */
72
+ failTest(title, durationMs) {
73
+ if (this.spinner.isSpinning) {
74
+ this.spinner.stop();
75
+ }
76
+ const testTitle = title || this.currentTestTitle;
77
+ const durationStr = chalk.gray(`(${durationMs}ms)`);
78
+ const completedHeader = `${chalk.hex('#f87171')('✗')} ${chalk.white.bold(testTitle)} ${durationStr}`;
79
+ const linesToMoveUp = this.stepCount + 1;
80
+ process.stdout.write(`\x1b[${linesToMoveUp}A\r\x1b[2K${completedHeader}\x1b[${linesToMoveUp}B\r\n`);
81
+ }
82
+ }
@@ -0,0 +1,2 @@
1
+ export type ActionKey = 'click' | 'doubleClick' | 'rightClick' | 'type' | 'clear' | 'select' | 'hover' | 'dragDrop' | 'scrollIntoView' | 'longPress' | 'waitForElement' | 'navigate' | 'back' | 'forward' | 'refresh' | 'setViewport' | 'wait' | 'pressKey' | 'scroll' | 'swipe' | 'intercept' | 'clearCookies' | 'clearLocalStorage';
2
+ export type AssertionKey = 'be.visible' | 'not.be.visible' | 'exist' | 'not.exist' | 'be.clickable' | 'not.be.clickable' | 'be.enabled' | 'be.disabled' | 'be.checked' | 'not.be.checked' | 'be.selected' | 'not.be.selected' | 'be.focused' | 'not.be.focused' | 'have.text' | 'not.have.text' | 'contain.text' | 'not.contain.text' | 'have.value' | 'not.have.value' | 'contain.value' | 'not.contain.value' | 'have.attr' | 'not.have.attr' | 'have.class' | 'not.have.class' | 'have.css' | 'not.have.css' | 'have.length' | 'not.have.length' | 'have.length.greaterThan' | 'have.length.lessThan' | 'be.empty' | 'not.be.empty' | 'shouldHaveUrl' | 'shouldContainUrl' | 'shouldHaveTitle' | 'shouldContainTitle' | 'shouldBeLoaded' | 'shouldBePageLoaded' | 'shouldHaveNoConsoleErrors' | 'have.url' | 'contain.url' | 'have.title' | 'contain.title' | 'be.loaded' | 'be.pageLoaded' | 'have.noConsoleErrors';
@@ -0,0 +1 @@
1
+ export {};
@@ -1,18 +1,23 @@
1
- import { ConfigData } from "../config/schema.js";
2
- import { Reporter, TestRunResult } from "./reporter.js";
1
+ import { ConfigData } from '../config/schema.js';
2
+ import { Reporter, TestRunResult } from './reporter.js';
3
3
  export interface RunOptions {
4
4
  baseDir: string;
5
5
  appDataPath: string;
6
- platform: "web" | "android" | "ios" | "common";
7
- suite: string;
8
- testCases: Array<{
6
+ platform: 'web' | 'android' | 'ios' | 'common' | 'mobile';
7
+ suite?: string;
8
+ testCases?: Array<{
9
9
  id: string;
10
10
  title: string;
11
11
  executionOrder?: number;
12
12
  }>;
13
13
  config: ConfigData;
14
14
  targetDevice?: string;
15
+ licenseKey?: string;
15
16
  outputJsonPath?: string;
17
+ specs?: string[];
18
+ concurrency?: number;
19
+ failedOnly?: boolean;
20
+ failedTarget?: string;
16
21
  }
17
22
  export declare class RustCoreBridge {
18
23
  static resolveBinaryPath(): string;