@testspectra/cli 1.1.7 → 1.1.8-rc.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 (251) hide show
  1. package/bin/.testspectra-runner.hash +1 -1
  2. package/bin/testspectra-runner +0 -0
  3. package/demo-app/assets/index-BhlW-eXG.css +1 -0
  4. package/demo-app/assets/index-DOtRypCa.js +154 -0
  5. package/demo-app/index.html +2 -2
  6. package/dist/.tsbuildinfo +1 -1
  7. package/dist/commands/__tests__/run-e2e.test.js +254 -13
  8. package/dist/commands/__tests__/run.test.js +92 -16
  9. package/dist/commands/demo.js +17 -7
  10. package/dist/commands/init.d.ts +1 -1
  11. package/dist/commands/init.js +6 -1
  12. package/dist/commands/lint.d.ts +5 -0
  13. package/dist/commands/lint.js +55 -0
  14. package/dist/commands/refactor.d.ts +2 -1
  15. package/dist/commands/refactor.js +129 -35
  16. package/dist/commands/run.d.ts +2 -3
  17. package/dist/commands/run.js +93 -28
  18. package/dist/commands/skills.d.ts +9 -0
  19. package/dist/commands/skills.js +28 -0
  20. package/dist/commands/sync-types.js +1 -0
  21. package/dist/commands/test.d.ts +17 -0
  22. package/dist/commands/test.js +76 -0
  23. package/dist/commands/watch.js +9 -3
  24. package/dist/config/loader.js +1 -1
  25. package/dist/config/schema.d.ts +5 -114
  26. package/dist/config/schema.js +1 -17
  27. package/dist/generator/__tests__/tsconfig-isolation.test.js +6 -2
  28. package/dist/generator/__tests__/type-generator.test.js +1 -1
  29. package/dist/generator/tsconfig-generator.js +44 -16
  30. package/dist/generator/type-generator.d.ts +24 -1
  31. package/dist/generator/type-generator.js +104 -8
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.js +65 -29
  34. package/dist/linter/__tests__/anonymous-export.test.js +184 -0
  35. package/dist/linter/__tests__/component-test-imports.test.d.ts +1 -0
  36. package/dist/linter/__tests__/component-test-imports.test.js +115 -0
  37. package/dist/linter/__tests__/shared-lib-boundary.test.d.ts +1 -0
  38. package/dist/linter/__tests__/shared-lib-boundary.test.js +270 -0
  39. package/dist/linter/__tests__/spec-schema.test.d.ts +1 -0
  40. package/dist/linter/__tests__/spec-schema.test.js +369 -0
  41. package/dist/linter/__tests__/step-parity.test.d.ts +1 -0
  42. package/dist/linter/__tests__/step-parity.test.js +372 -0
  43. package/dist/linter/discovery.d.ts +30 -0
  44. package/dist/linter/discovery.js +249 -0
  45. package/dist/linter/extractor.d.ts +67 -0
  46. package/dist/linter/extractor.js +245 -0
  47. package/dist/linter/index.d.ts +7 -0
  48. package/dist/linter/index.js +7 -0
  49. package/dist/linter/parser.d.ts +24 -0
  50. package/dist/linter/parser.js +219 -0
  51. package/dist/linter/schemas/spec.schema.d.ts +83 -0
  52. package/dist/linter/schemas/spec.schema.js +150 -0
  53. package/dist/linter/schemas/suite.schema.d.ts +59 -0
  54. package/dist/linter/schemas/suite.schema.js +83 -0
  55. package/dist/linter/spec-linter.d.ts +23 -0
  56. package/dist/linter/spec-linter.js +630 -0
  57. package/dist/linter/types.d.ts +28 -0
  58. package/dist/linter/types.js +1 -0
  59. package/dist/refactor/__tests__/refactor-engine.test.js +698 -0
  60. package/dist/refactor/refactor-engine.d.ts +25 -0
  61. package/dist/refactor/refactor-engine.js +374 -42
  62. package/dist/reporter/semantic-formatter.js +17 -2
  63. package/dist/reporter/types.d.ts +1 -1
  64. package/dist/runner/bridge.d.ts +1 -1
  65. package/dist/runner/bridge.js +34 -21
  66. package/dist/runner/reporter.d.ts +2 -0
  67. package/dist/runner/reporter.js +11 -3
  68. package/dist/utils/__tests__/api-server.test.d.ts +1 -0
  69. package/dist/utils/__tests__/api-server.test.js +62 -0
  70. package/dist/utils/__tests__/demo-server.test.d.ts +1 -0
  71. package/dist/utils/__tests__/demo-server.test.js +35 -0
  72. package/dist/utils/api-server.d.ts +19 -0
  73. package/dist/utils/api-server.js +179 -0
  74. package/dist/utils/demo-server.d.ts +5 -0
  75. package/dist/utils/demo-server.js +8 -1
  76. package/package.json +29 -25
  77. package/templates/default/CLAUDE.md +5 -0
  78. package/templates/default/package.json +3 -3
  79. package/templates/default/page-objects/AuthPage/mobile.ts +5 -0
  80. package/templates/default/page-objects/AuthPage/web.ts +10 -0
  81. package/templates/default/page-objects/MatchersPage/mobile.ts +26 -2
  82. package/templates/default/page-objects/MatchersPage/web.ts +8 -2
  83. package/templates/default/page-objects/NavigationPage/mobile.ts +1 -1
  84. package/templates/default/page-objects/NavigationPage/web.ts +1 -1
  85. package/templates/default/page-objects/PlaygroundPage/mobile.ts +12 -6
  86. package/templates/default/page-objects/PlaygroundPage/web.ts +2 -2
  87. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/mobile.test.ts +45 -3
  88. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/spec.md +7 -0
  89. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/web.test.ts +8 -4
  90. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/android.test.ts +3 -0
  91. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/common.test.ts +3 -0
  92. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/mobile.test.ts +13 -2
  93. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/spec.md +7 -0
  94. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/web.test.ts +6 -4
  95. package/templates/default/specs/ApiInterception/TC-0012-direct-and-late-response/common.test.ts +30 -0
  96. package/templates/default/specs/ApiInterception/TC-0012-direct-and-late-response/spec.md +22 -0
  97. package/templates/default/specs/ApiInterception/TC-0013-real-network-call-recorded/common.test.ts +27 -0
  98. package/templates/default/specs/ApiInterception/TC-0013-real-network-call-recorded/spec.md +20 -0
  99. package/templates/default/specs/ApiInterception/TC-0015-mock-server-sent-events/spec.md +24 -0
  100. package/templates/default/specs/ApiInterception/TC-0015-mock-server-sent-events/web.test.ts +26 -0
  101. package/templates/default/specs/ApiInterception/TC-0016-bypass-websocket-with-app-level-mock/spec.md +37 -0
  102. package/templates/default/specs/ApiInterception/TC-0016-bypass-websocket-with-app-level-mock/web.test.ts +21 -0
  103. package/templates/default/specs/ApiInterception/TC-0017-bypass-captcha-with-test-mode-flag/spec.md +29 -0
  104. package/templates/default/specs/ApiInterception/TC-0017-bypass-captcha-with-test-mode-flag/web.test.ts +16 -0
  105. package/templates/default/specs/ApiInterception/suite.md +1 -0
  106. package/templates/default/specs/ApiSeeding/TC-0014-seed-and-cleanup-via-hooks/common.test.ts +30 -0
  107. package/templates/default/specs/ApiSeeding/TC-0014-seed-and-cleanup-via-hooks/spec.md +23 -0
  108. package/templates/default/specs/ApiSeeding/hooks/after/common.hook.ts +16 -0
  109. package/templates/default/specs/ApiSeeding/hooks/before/common.hook.ts +28 -0
  110. package/templates/default/specs/ApiSeeding/suite.md +9 -0
  111. package/templates/default/specs/Authentication/TC-0021-seed-authenticated-session/mobile.test.ts +7 -0
  112. package/templates/default/specs/Authentication/TC-0021-seed-authenticated-session/spec.md +19 -0
  113. package/templates/default/specs/Authentication/TC-0021-seed-authenticated-session/web.test.ts +9 -0
  114. package/templates/default/specs/Authentication/suite.md +9 -0
  115. package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +1 -1
  116. package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/spec.md +5 -0
  117. package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +1 -1
  118. package/templates/default/specs/BrowserContext/TC-0022-history-navigation/mobile.test.ts +17 -0
  119. package/templates/default/specs/BrowserContext/TC-0022-history-navigation/spec.md +28 -0
  120. package/templates/default/specs/BrowserContext/TC-0022-history-navigation/web.test.ts +26 -0
  121. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/common.test.ts +26 -0
  122. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/spec.md +7 -0
  123. package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +1 -1
  124. package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/spec.md +5 -0
  125. package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +1 -1
  126. package/templates/default/specs/ContentMatchers/TC-0020-scoped-element-access/common.test.ts +14 -0
  127. package/templates/default/specs/ContentMatchers/TC-0020-scoped-element-access/spec.md +21 -0
  128. package/templates/default/specs/DeepLink/TC-0018-navigate-via-deep-link/mobile.test.ts +28 -0
  129. package/templates/default/specs/DeepLink/TC-0018-navigate-via-deep-link/spec.md +29 -0
  130. package/templates/default/specs/DeepLink/suite.md +9 -0
  131. package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +1 -1
  132. package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/spec.md +5 -0
  133. package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +1 -1
  134. package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +1 -1
  135. package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/spec.md +7 -0
  136. package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +1 -1
  137. package/templates/default/specs/ElementMatchers/suite.md +2 -1
  138. package/templates/default/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/common.test.ts +5 -0
  139. package/templates/default/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/spec.md +16 -0
  140. package/templates/default/specs/EnvironmentConfig/suite.md +9 -0
  141. package/templates/default/specs/PermissionRationale/TC-0010-camera-permission-allow/mobile.test.ts +26 -0
  142. package/templates/default/specs/PermissionRationale/TC-0010-camera-permission-allow/spec.md +22 -0
  143. package/templates/default/specs/PermissionRationale/TC-0011-camera-permission-deny/mobile.test.ts +13 -0
  144. package/templates/default/specs/PermissionRationale/TC-0011-camera-permission-deny/spec.md +20 -0
  145. package/templates/default/specs/PermissionRationale/suite.md +9 -0
  146. package/templates/default/specs/Playground/TC-0001-form-controls/mobile.test.ts +1 -1
  147. package/templates/default/specs/Playground/TC-0001-form-controls/spec.md +6 -0
  148. package/templates/default/specs/Playground/TC-0001-form-controls/web.test.ts +1 -1
  149. package/templates/default/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +1 -1
  150. package/templates/default/specs/Playground/TC-0002-toggle-elements/spec.md +6 -0
  151. package/templates/default/specs/Playground/TC-0002-toggle-elements/web.test.ts +1 -1
  152. package/templates/default/spectra.config.ts +1 -17
  153. package/templates/default/support/actions/fillCredentials/mobile.action.ts +3 -3
  154. package/templates/default/support/actions/fillCredentials/web.action.ts +1 -1
  155. package/templates/default/support/actions/seedSession/mobile.action.ts +9 -0
  156. package/templates/default/support/actions/seedSession/web.action.ts +13 -0
  157. package/templates/default/support/steps/togglePlaygroundStates/mobile.step.ts +1 -1
  158. package/templates/default/support/steps/togglePlaygroundStates/web.step.ts +1 -1
  159. package/templates/default/support/steps/verifyPlaygroundState/mobile.step.ts +1 -1
  160. package/templates/default/support/steps/verifyPlaygroundState/web.step.ts +1 -1
  161. package/templates/nx/.nx/workspace-data/70094CFD-E89B-57A1-9619-2FC5F4963C54.db +0 -0
  162. package/templates/nx/.nx/workspace-data/70094CFD-E89B-57A1-9619-2FC5F4963C54.db-shm +0 -0
  163. package/templates/nx/.nx/workspace-data/70094CFD-E89B-57A1-9619-2FC5F4963C54.db-wal +0 -0
  164. package/templates/nx/.nx/workspace-data/d/daemon.log +5388 -168
  165. package/templates/nx/.nx/workspace-data/d/server-process.json +3 -0
  166. package/templates/nx/.nx/workspace-data/file-map.json +464 -0
  167. package/templates/nx/.nx/workspace-data/lockfile.hash +1 -0
  168. package/templates/nx/.nx/workspace-data/nx_files.nxt +0 -0
  169. package/templates/nx/.nx/workspace-data/parsed-lock-file.json +13485 -0
  170. package/templates/nx/.nx/workspace-data/project-graph.json +14389 -0
  171. package/templates/nx/package.json +3 -3
  172. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/mobile.test.ts +25 -1
  173. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/web.test.ts +2 -2
  174. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/mobile.test.ts +22 -1
  175. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/web.test.ts +2 -2
  176. package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +1 -1
  177. package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +1 -1
  178. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +1 -1
  179. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +1 -1
  180. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +1 -1
  181. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +1 -1
  182. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +1 -1
  183. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +1 -1
  184. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +1 -1
  185. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +1 -1
  186. package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/common.test.ts +5 -0
  187. package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/spec.md +16 -0
  188. package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/suite.md +9 -0
  189. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0001-form-controls/mobile.test.ts +1 -1
  190. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0001-form-controls/web.test.ts +1 -1
  191. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +1 -1
  192. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0002-toggle-elements/web.test.ts +1 -1
  193. package/templates/nx/shared/testing/page-objects/MatchersPage/mobile.ts +1 -1
  194. package/templates/nx/shared/testing/page-objects/MatchersPage/web.ts +83 -29
  195. package/templates/nx/shared/testing/page-objects/NavigationPage/mobile.ts +1 -1
  196. package/templates/nx/shared/testing/page-objects/NavigationPage/web.ts +1 -1
  197. package/templates/nx/shared/testing/page-objects/PlaygroundPage/mobile.ts +1 -1
  198. package/templates/nx/shared/testing/page-objects/PlaygroundPage/web.ts +2 -2
  199. package/templates/nx/shared/testing/support/actions/fillCredentials/mobile.action.ts +1 -1
  200. package/templates/nx/shared/testing/support/actions/fillCredentials/web.action.ts +1 -1
  201. package/templates/nx/shared/testing/support/steps/togglePlaygroundStates/mobile.step.ts +1 -1
  202. package/templates/nx/shared/testing/support/steps/togglePlaygroundStates/web.step.ts +1 -1
  203. package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/mobile.step.ts +1 -1
  204. package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/web.step.ts +1 -1
  205. package/templates/nx/spectra.config.ts +1 -17
  206. package/templates/react-component/.cursorrules +17 -0
  207. package/templates/react-component/.vscode/extensions.json +5 -0
  208. package/templates/react-component/CLAUDE.md +14 -0
  209. package/templates/react-component/README.md +69 -0
  210. package/templates/react-component/fixtures/component-mock.json +12 -0
  211. package/templates/react-component/global-hooks/after/web.hook.ts +3 -0
  212. package/templates/react-component/global-hooks/before/web.hook.ts +3 -0
  213. package/templates/react-component/package.json +27 -0
  214. package/templates/react-component/page-objects/BadgeComponent/web.ts +23 -0
  215. package/templates/react-component/page-objects/ButtonComponent/web.ts +23 -0
  216. package/templates/react-component/page-objects/InputComponent/web.ts +13 -0
  217. package/templates/react-component/specs/BadgeComponent/TC-0002-badge-severities-and-dot/spec.md +18 -0
  218. package/templates/react-component/specs/BadgeComponent/TC-0002-badge-severities-and-dot/web.test.tsx +11 -0
  219. package/templates/react-component/specs/BadgeComponent/TC-0006-badge-success-with-dot/spec.md +18 -0
  220. package/templates/react-component/specs/BadgeComponent/TC-0006-badge-success-with-dot/web.test.tsx +10 -0
  221. package/templates/react-component/specs/BadgeComponent/TC-0007-badge-by-severity-lookup/spec.md +18 -0
  222. package/templates/react-component/specs/BadgeComponent/TC-0007-badge-by-severity-lookup/web.test.tsx +16 -0
  223. package/templates/react-component/specs/BadgeComponent/suite.md +12 -0
  224. package/templates/react-component/specs/ButtonComponent/TC-0001-button-rendering-and-click/spec.md +19 -0
  225. package/templates/react-component/specs/ButtonComponent/TC-0001-button-rendering-and-click/web.test.tsx +28 -0
  226. package/templates/react-component/specs/ButtonComponent/TC-0004-disabled-button-not-clickable/spec.md +19 -0
  227. package/templates/react-component/specs/ButtonComponent/TC-0004-disabled-button-not-clickable/web.test.tsx +22 -0
  228. package/templates/react-component/specs/ButtonComponent/TC-0005-button-renders-icon/spec.md +18 -0
  229. package/templates/react-component/specs/ButtonComponent/TC-0005-button-renders-icon/web.test.tsx +8 -0
  230. package/templates/react-component/specs/ButtonComponent/suite.md +12 -0
  231. package/templates/react-component/specs/InputComponent/TC-0003-input-typing-and-clear/spec.md +20 -0
  232. package/templates/react-component/specs/InputComponent/TC-0003-input-typing-and-clear/web.test.tsx +28 -0
  233. package/templates/react-component/specs/InputComponent/TC-0008-disabled-input-not-editable/spec.md +18 -0
  234. package/templates/react-component/specs/InputComponent/TC-0008-disabled-input-not-editable/web.test.tsx +9 -0
  235. package/templates/react-component/specs/InputComponent/suite.md +12 -0
  236. package/templates/react-component/spectra.config.ts +27 -0
  237. package/templates/react-component/src/components/Badge/Badge.tsx +60 -0
  238. package/templates/react-component/src/components/Button/Button.tsx +57 -0
  239. package/templates/react-component/src/components/Input/Input.tsx +41 -0
  240. package/templates/react-component/src/test-utils.tsx +23 -0
  241. package/templates/react-component/support/actions/fillInputField/web.action.ts +9 -0
  242. package/templates/react-component/support/steps/verifyButtonState/web.step.ts +12 -0
  243. package/templates/react-component/tsconfig.json +8 -0
  244. package/demo-app/assets/index-DPfv5_EF.js +0 -116
  245. package/demo-app/assets/index-gIwu2EMV.css +0 -1
  246. package/dist/commands/__tests__/cloud-run.test.js +0 -93
  247. package/dist/commands/cloud-run.d.ts +0 -13
  248. package/dist/commands/cloud-run.js +0 -120
  249. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +0 -17
  250. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +0 -17
  251. /package/dist/{commands/__tests__/cloud-run.test.d.ts → linter/__tests__/anonymous-export.test.d.ts} +0 -0
@@ -1,93 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { cloudRunCommand, parseTimeoutMs } from '../cloud-run.js';
3
- const ORIGINAL_ENV = { ...process.env };
4
- function mockFetchSequence(responses) {
5
- let call = 0;
6
- return vi.fn(async (_url, _init) => {
7
- const res = responses[Math.min(call, responses.length - 1)];
8
- call += 1;
9
- return {
10
- ok: res.ok,
11
- status: res.status ?? (res.ok ? 200 : 500),
12
- statusText: 'error',
13
- json: async () => res.json,
14
- };
15
- });
16
- }
17
- describe('cloudRunCommand (docs/v2/cloud/git-spec-standards-and-workflow.md)', () => {
18
- beforeEach(() => {
19
- process.env = { ...ORIGINAL_ENV, SPECTRA_URL: 'https://cloud.test', SPECTRA_TOKEN: 'gitea-pat-123' };
20
- process.exitCode = undefined;
21
- vi.useFakeTimers();
22
- });
23
- afterEach(() => {
24
- process.env = { ...ORIGINAL_ENV };
25
- vi.restoreAllMocks();
26
- vi.useRealTimers();
27
- });
28
- it('fails fast without SPECTRA_URL/SPECTRA_TOKEN', async () => {
29
- delete process.env.SPECTRA_URL;
30
- delete process.env.SPECTRA_TOKEN;
31
- const fetchSpy = vi.fn();
32
- vi.stubGlobal('fetch', fetchSpy);
33
- await cloudRunCommand({ project: 'org/repo', branch: 'main' });
34
- expect(process.exitCode).toBe(1);
35
- expect(fetchSpy).not.toHaveBeenCalled();
36
- });
37
- it('triggers and returns immediately with --no-wait', async () => {
38
- const fetchSpy = mockFetchSequence([{ ok: true, json: { job_id: 'job-1', status: 'queued' } }]);
39
- vi.stubGlobal('fetch', fetchSpy);
40
- await cloudRunCommand({ project: 'org/repo', branch: 'main', wait: false });
41
- expect(fetchSpy).toHaveBeenCalledTimes(1);
42
- const [url, init] = fetchSpy.mock.calls[0];
43
- expect(url).toBe('https://cloud.test/api/v1/runs/trigger');
44
- const headers = init.headers;
45
- expect(headers.Authorization).toBe('Bearer gitea-pat-123');
46
- expect(JSON.parse(init.body)).toMatchObject({ project_id: 'org/repo', branch: 'main', platform: 'web' });
47
- expect(process.exitCode).toBeUndefined();
48
- });
49
- it('exits 0 when the job reaches done', async () => {
50
- const fetchSpy = mockFetchSequence([
51
- { ok: true, json: { job_id: 'job-2', status: 'queued' } },
52
- { ok: true, json: { status: 'done', run_id: 'run-2', started_at: null, completed_at: null, error_log: null } },
53
- ]);
54
- vi.stubGlobal('fetch', fetchSpy);
55
- const promise = cloudRunCommand({ project: 'org/repo', branch: 'main' });
56
- await vi.advanceTimersByTimeAsync(5000);
57
- await promise;
58
- expect(process.exitCode).toBe(0);
59
- });
60
- it('exits 1 when the job reaches failed', async () => {
61
- const fetchSpy = mockFetchSequence([
62
- { ok: true, json: { job_id: 'job-3', status: 'queued' } },
63
- {
64
- ok: true,
65
- json: { status: 'failed', run_id: 'run-3', started_at: null, completed_at: null, error_log: 'boom' },
66
- },
67
- ]);
68
- vi.stubGlobal('fetch', fetchSpy);
69
- const promise = cloudRunCommand({ project: 'org/repo', branch: 'main' });
70
- await vi.advanceTimersByTimeAsync(5000);
71
- await promise;
72
- expect(process.exitCode).toBe(1);
73
- });
74
- it('exits 1 when the trigger request itself fails', async () => {
75
- const fetchSpy = mockFetchSequence([{ ok: false, status: 401, json: { error: 'Invalid PAT' } }]);
76
- vi.stubGlobal('fetch', fetchSpy);
77
- await cloudRunCommand({ project: 'org/repo', branch: 'main' });
78
- expect(process.exitCode).toBe(1);
79
- });
80
- });
81
- describe('parseTimeoutMs', () => {
82
- it('parses seconds, minutes, and hours', () => {
83
- expect(parseTimeoutMs('30s')).toBe(30_000);
84
- expect(parseTimeoutMs('30m')).toBe(30 * 60_000);
85
- expect(parseTimeoutMs('2h')).toBe(2 * 3_600_000);
86
- });
87
- it('defaults to minutes when no unit is given', () => {
88
- expect(parseTimeoutMs('10')).toBe(10 * 60_000);
89
- });
90
- it('falls back to 30m for unparseable input', () => {
91
- expect(parseTimeoutMs('nonsense')).toBe(30 * 60_000);
92
- });
93
- });
@@ -1,13 +0,0 @@
1
- export interface CloudRunOptions {
2
- project: string;
3
- projectName?: string;
4
- branch?: string;
5
- commit?: string;
6
- platform?: string;
7
- wait?: boolean;
8
- timeout?: string;
9
- demo?: boolean;
10
- baseUrl?: string;
11
- }
12
- export declare function parseTimeoutMs(timeout: string): number;
13
- export declare function cloudRunCommand(options: CloudRunOptions): Promise<void>;
@@ -1,120 +0,0 @@
1
- import { execFileSync } from 'child_process';
2
- import chalk from 'chalk';
3
- import ora from 'ora';
4
- const POLL_INTERVAL_MS = 5000;
5
- const DEFAULT_TIMEOUT = '30m';
6
- function detectGitRef(...args) {
7
- try {
8
- return execFileSync('git', args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim() || undefined;
9
- }
10
- catch {
11
- return undefined;
12
- }
13
- }
14
- export function parseTimeoutMs(timeout) {
15
- const match = /^(\d+)(s|m|h)?$/.exec(timeout.trim());
16
- if (!match)
17
- return 30 * 60 * 1000;
18
- const value = Number(match[1]);
19
- const unit = match[2] ?? 'm';
20
- const multiplier = unit === 's' ? 1000 : unit === 'h' ? 3_600_000 : 60_000;
21
- return value * multiplier;
22
- }
23
- // Same credential path as the trigger endpoint expects: a Gitea PAT, not the
24
- // dashboard's OAuth2 session — a CI runner can't complete a browser redirect.
25
- // See docs/v2/cloud/git-spec-standards-and-workflow.md.
26
- function requireEnv(name) {
27
- const value = process.env[name];
28
- if (!value) {
29
- console.error(chalk.red(`Missing required environment variable: ${name}`));
30
- console.error(chalk.gray('Set it as a CI secret — see docs/v2/cloud/git-spec-standards-and-workflow.md'));
31
- }
32
- return value;
33
- }
34
- export async function cloudRunCommand(options) {
35
- const spectraUrl = requireEnv('SPECTRA_URL')?.replace(/\/$/, '');
36
- const spectraToken = requireEnv('SPECTRA_TOKEN');
37
- if (!spectraUrl || !spectraToken) {
38
- process.exitCode = 1;
39
- return;
40
- }
41
- const branch = options.branch ?? detectGitRef('rev-parse', '--abbrev-ref', 'HEAD');
42
- if (!branch) {
43
- console.error(chalk.red('Could not determine branch: pass --branch or run inside a git repository.'));
44
- process.exitCode = 1;
45
- return;
46
- }
47
- const commit = options.commit ?? detectGitRef('rev-parse', 'HEAD');
48
- const platform = options.platform ?? 'web';
49
- const wait = options.wait !== false;
50
- const timeout = options.timeout ?? DEFAULT_TIMEOUT;
51
- const spinner = ora(`Triggering cloud run for ${chalk.bold(options.project)}@${branch}...`).start();
52
- let trigger;
53
- try {
54
- const res = await fetch(`${spectraUrl}/api/v1/runs/trigger`, {
55
- method: 'POST',
56
- headers: {
57
- 'Content-Type': 'application/json',
58
- Authorization: `Bearer ${spectraToken}`,
59
- },
60
- body: JSON.stringify({
61
- project_id: options.project,
62
- project_name: options.projectName ?? options.project,
63
- branch,
64
- commit_hash: commit,
65
- platform,
66
- demo: options.demo ?? false,
67
- base_url: options.baseUrl,
68
- }),
69
- });
70
- if (!res.ok) {
71
- const body = await res.json().catch(() => ({ error: res.statusText }));
72
- throw new Error(body.error ?? `HTTP ${res.status}`);
73
- }
74
- trigger = (await res.json());
75
- }
76
- catch (err) {
77
- spinner.fail(chalk.red(`Failed to trigger cloud run: ${err.message}`));
78
- process.exitCode = 1;
79
- return;
80
- }
81
- spinner.succeed(`Cloud run queued: ${chalk.cyan(trigger.job_id)}`);
82
- if (!wait) {
83
- console.log(chalk.gray(`Not waiting for result. Poll ${spectraUrl}/api/v1/jobs/${trigger.job_id}/status yourself.`));
84
- return;
85
- }
86
- await waitForJob(spectraUrl, spectraToken, trigger.job_id, timeout);
87
- }
88
- async function waitForJob(spectraUrl, spectraToken, jobId, timeout) {
89
- const spinner = ora('Waiting for run to finish...').start();
90
- const deadline = Date.now() + parseTimeoutMs(timeout);
91
- while (Date.now() < deadline) {
92
- await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
93
- let job;
94
- try {
95
- const res = await fetch(`${spectraUrl}/api/v1/jobs/${jobId}/status`, {
96
- headers: { Authorization: `Bearer ${spectraToken}` },
97
- });
98
- if (!res.ok)
99
- throw new Error(`HTTP ${res.status}`);
100
- job = (await res.json());
101
- }
102
- catch (err) {
103
- spinner.text = chalk.yellow(`Poll failed, retrying: ${err.message}`);
104
- continue;
105
- }
106
- if (job.status === 'done') {
107
- spinner.succeed(chalk.green(`Run passed (run_id: ${job.run_id})`));
108
- process.exitCode = 0;
109
- return;
110
- }
111
- if (job.status === 'failed') {
112
- spinner.fail(chalk.red(`Run failed (run_id: ${job.run_id})${job.error_log ? `: ${job.error_log}` : ''}`));
113
- process.exitCode = 1;
114
- return;
115
- }
116
- spinner.text = `Run status: ${job.status}`;
117
- }
118
- spinner.fail(chalk.red(`Timed out after ${timeout} waiting for the run to finish.`));
119
- process.exitCode = 1;
120
- }
@@ -1,17 +0,0 @@
1
- it("should verify text and value matchers on Mobile", async () => {
2
- await MatchersPage.open("text");
3
-
4
- // Text assertions (positive and negative)
5
- await MatchersPage.exactText.shouldHaveText(Fixture.playgroundData.welcomeText);
6
- await MatchersPage.exactText.shouldNotHaveText("Unexpected Text");
7
-
8
- await MatchersPage.partialText.shouldContainText("Welcome");
9
- await MatchersPage.partialText.shouldNotContainText("Goodbye");
10
-
11
- // Value assertions (positive and negative)
12
- await MatchersPage.emailInput.shouldHaveValue(Fixture.playgroundData.defaultEmail);
13
- await MatchersPage.emailInput.shouldNotHaveValue("wrong.user@testspectra.dev");
14
-
15
- await MatchersPage.tokenInput.shouldContainValue("JWT_");
16
- await MatchersPage.tokenInput.shouldNotContainValue("EXPIRED_SESSION");
17
- });
@@ -1,17 +0,0 @@
1
- it("should verify text and value matchers on Web", async () => {
2
- await MatchersPage.open("text");
3
-
4
- // Text assertions (positive and negative)
5
- await MatchersPage.exactText.shouldHaveText(Fixture.playgroundData.welcomeText);
6
- await MatchersPage.exactText.shouldNotHaveText("Unexpected Text");
7
-
8
- await MatchersPage.partialText.shouldContainText("Welcome");
9
- await MatchersPage.partialText.shouldNotContainText("Goodbye");
10
-
11
- // Value assertions (positive and negative)
12
- await MatchersPage.emailInput.shouldHaveValue(Fixture.playgroundData.defaultEmail);
13
- await MatchersPage.emailInput.shouldNotHaveValue("wrong.user@testspectra.dev");
14
-
15
- await MatchersPage.tokenInput.shouldContainValue("JWT_");
16
- await MatchersPage.tokenInput.shouldNotContainValue("EXPIRED_SESSION");
17
- });