@testspectra/cli 1.1.8-rc.3 → 1.1.8-rc.31

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 (243) hide show
  1. package/README.md +50 -0
  2. package/bin/spectra.js +0 -0
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/commands/__tests__/doctor-filter.test.d.ts +1 -0
  5. package/dist/commands/__tests__/doctor-filter.test.js +37 -0
  6. package/dist/commands/__tests__/run-e2e.test.js +49 -49
  7. package/dist/commands/__tests__/test-error-streaming.test.d.ts +1 -0
  8. package/dist/commands/__tests__/test-error-streaming.test.js +85 -0
  9. package/dist/commands/__tests__/test-scaffolding.test.d.ts +1 -0
  10. package/dist/commands/__tests__/test-scaffolding.test.js +32 -0
  11. package/dist/commands/__tests__/upgrade.test.d.ts +1 -0
  12. package/dist/commands/__tests__/upgrade.test.js +95 -0
  13. package/dist/commands/add.js +5 -4
  14. package/dist/commands/devices.js +1 -0
  15. package/dist/commands/docs.d.ts +4 -0
  16. package/dist/commands/docs.js +17 -0
  17. package/dist/commands/doctor.d.ts +9 -1
  18. package/dist/commands/doctor.js +17 -3
  19. package/dist/commands/init.js +7 -160
  20. package/dist/commands/install.js +5 -0
  21. package/dist/commands/license.js +1 -0
  22. package/dist/commands/run.d.ts +2 -0
  23. package/dist/commands/run.js +22 -0
  24. package/dist/commands/test.d.ts +13 -0
  25. package/dist/commands/test.js +115 -21
  26. package/dist/commands/upgrade.d.ts +12 -0
  27. package/dist/commands/upgrade.js +197 -0
  28. package/dist/config/schema.d.ts +53 -0
  29. package/dist/config/schema.js +2 -0
  30. package/dist/generator/__tests__/tsconfig-isolation.test.js +2 -1
  31. package/dist/generator/__tests__/type-generator.test.js +38 -0
  32. package/dist/generator/architecture-doc-generator.d.ts +14 -0
  33. package/dist/generator/architecture-doc-generator.js +80 -0
  34. package/dist/generator/index.d.ts +1 -0
  35. package/dist/generator/index.js +1 -0
  36. package/dist/generator/tsconfig-generator.js +1 -1
  37. package/dist/generator/type-generator.d.ts +5 -2
  38. package/dist/generator/type-generator.js +14 -17
  39. package/dist/index.js +56 -26
  40. package/dist/linter/__tests__/component-test-imports.test.js +51 -51
  41. package/dist/linter/__tests__/shared-lib-boundary.test.js +15 -15
  42. package/dist/linter/__tests__/spec-schema.test.js +167 -167
  43. package/dist/linter/discovery.d.ts +3 -3
  44. package/dist/linter/discovery.js +7 -7
  45. package/dist/linter/schemas/spec.schema.d.ts +8 -8
  46. package/dist/linter/schemas/suite.schema.d.ts +4 -4
  47. package/dist/runner/bridge.d.ts +1 -1
  48. package/dist/runner/bridge.js +101 -11
  49. package/dist/runner/reporter.d.ts +1 -0
  50. package/dist/runner/reporter.js +12 -6
  51. package/dist/utils/__tests__/dev-server-manager.test.d.ts +1 -0
  52. package/dist/utils/__tests__/dev-server-manager.test.js +72 -0
  53. package/dist/utils/background-update-check.d.ts +1 -0
  54. package/dist/utils/background-update-check.js +43 -0
  55. package/dist/utils/dependency-updates.d.ts +15 -0
  56. package/dist/utils/dependency-updates.js +107 -0
  57. package/dist/utils/dev-server-manager.d.ts +40 -0
  58. package/dist/utils/dev-server-manager.js +257 -0
  59. package/dist/utils/update-notifier.d.ts +2 -0
  60. package/dist/utils/update-notifier.js +67 -0
  61. package/package.json +36 -30
  62. package/templates/default/CLAUDE.md +16 -16
  63. package/templates/default/global-hooks/after/mobile.hook.ts +3 -3
  64. package/templates/default/global-hooks/after/web.hook.ts +3 -3
  65. package/templates/default/global-hooks/before/mobile.hook.ts +3 -3
  66. package/templates/default/global-hooks/before/web.hook.ts +3 -3
  67. package/templates/default/package.json +2 -2
  68. package/templates/default/page-objects/AuthPage/mobile.ts +5 -5
  69. package/templates/default/page-objects/AuthPage/web.ts +10 -10
  70. package/templates/default/page-objects/MatchersPage/mobile.ts +70 -70
  71. package/templates/default/page-objects/MatchersPage/web.ts +43 -43
  72. package/templates/default/page-objects/NavigationPage/mobile.ts +14 -14
  73. package/templates/default/page-objects/NavigationPage/web.ts +8 -8
  74. package/templates/default/page-objects/PlaygroundPage/mobile.ts +42 -42
  75. package/templates/default/page-objects/PlaygroundPage/web.ts +31 -31
  76. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/mobile.test.ts +53 -53
  77. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/spec.md +19 -19
  78. package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/web.test.ts +31 -31
  79. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/android.test.ts +3 -3
  80. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/common.test.ts +3 -3
  81. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/mobile.test.ts +27 -27
  82. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/spec.md +19 -19
  83. package/templates/default/specs/ApiInterception/TC-0009-post-mocking/web.test.ts +26 -26
  84. package/templates/default/specs/ApiInterception/TC-0012-direct-and-late-response/common.test.ts +30 -30
  85. package/templates/default/specs/ApiInterception/TC-0012-direct-and-late-response/spec.md +22 -22
  86. package/templates/default/specs/ApiInterception/TC-0013-real-network-call-recorded/common.test.ts +27 -27
  87. package/templates/default/specs/ApiInterception/TC-0013-real-network-call-recorded/spec.md +20 -20
  88. package/templates/default/specs/ApiInterception/TC-0015-mock-server-sent-events/spec.md +24 -24
  89. package/templates/default/specs/ApiInterception/TC-0015-mock-server-sent-events/web.test.ts +26 -26
  90. package/templates/default/specs/ApiInterception/TC-0016-bypass-websocket-with-app-level-mock/spec.md +37 -37
  91. package/templates/default/specs/ApiInterception/TC-0016-bypass-websocket-with-app-level-mock/web.test.ts +21 -21
  92. package/templates/default/specs/ApiInterception/TC-0017-bypass-captcha-with-test-mode-flag/spec.md +29 -29
  93. package/templates/default/specs/ApiInterception/TC-0017-bypass-captcha-with-test-mode-flag/web.test.ts +16 -16
  94. package/templates/default/specs/ApiInterception/suite.md +10 -10
  95. package/templates/default/specs/ApiSeeding/TC-0014-seed-and-cleanup-via-hooks/common.test.ts +30 -30
  96. package/templates/default/specs/ApiSeeding/TC-0014-seed-and-cleanup-via-hooks/spec.md +23 -23
  97. package/templates/default/specs/ApiSeeding/hooks/after/common.hook.ts +16 -16
  98. package/templates/default/specs/ApiSeeding/hooks/before/common.hook.ts +28 -28
  99. package/templates/default/specs/ApiSeeding/suite.md +9 -9
  100. package/templates/default/specs/Authentication/TC-0021-seed-authenticated-session/mobile.test.ts +7 -7
  101. package/templates/default/specs/Authentication/TC-0021-seed-authenticated-session/spec.md +19 -19
  102. package/templates/default/specs/Authentication/TC-0021-seed-authenticated-session/web.test.ts +9 -9
  103. package/templates/default/specs/Authentication/suite.md +9 -9
  104. package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +9 -9
  105. package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/spec.md +17 -17
  106. package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +19 -19
  107. package/templates/default/specs/BrowserContext/TC-0022-history-navigation/mobile.test.ts +17 -17
  108. package/templates/default/specs/BrowserContext/TC-0022-history-navigation/spec.md +28 -28
  109. package/templates/default/specs/BrowserContext/TC-0022-history-navigation/web.test.ts +26 -26
  110. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/common.test.ts +26 -26
  111. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/spec.md +19 -19
  112. package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +11 -11
  113. package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/spec.md +17 -17
  114. package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +11 -11
  115. package/templates/default/specs/ContentMatchers/TC-0020-scoped-element-access/common.test.ts +14 -14
  116. package/templates/default/specs/ContentMatchers/TC-0020-scoped-element-access/spec.md +21 -21
  117. package/templates/default/specs/DeepLink/TC-0018-navigate-via-deep-link/mobile.test.ts +28 -28
  118. package/templates/default/specs/DeepLink/TC-0018-navigate-via-deep-link/spec.md +29 -29
  119. package/templates/default/specs/DeepLink/suite.md +9 -9
  120. package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +11 -11
  121. package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/spec.md +17 -17
  122. package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +11 -11
  123. package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +29 -29
  124. package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/spec.md +19 -19
  125. package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +29 -29
  126. package/templates/default/specs/ElementMatchers/suite.md +10 -10
  127. package/templates/default/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/common.test.ts +5 -5
  128. package/templates/default/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/spec.md +16 -16
  129. package/templates/default/specs/EnvironmentConfig/suite.md +9 -9
  130. package/templates/default/specs/PermissionRationale/TC-0010-camera-permission-allow/mobile.test.ts +26 -26
  131. package/templates/default/specs/PermissionRationale/TC-0010-camera-permission-allow/spec.md +22 -22
  132. package/templates/default/specs/PermissionRationale/TC-0011-camera-permission-deny/mobile.test.ts +13 -13
  133. package/templates/default/specs/PermissionRationale/TC-0011-camera-permission-deny/spec.md +20 -20
  134. package/templates/default/specs/PermissionRationale/suite.md +9 -9
  135. package/templates/default/specs/Playground/TC-0001-form-controls/mobile.test.ts +6 -6
  136. package/templates/default/specs/Playground/TC-0001-form-controls/spec.md +18 -18
  137. package/templates/default/specs/Playground/TC-0001-form-controls/web.test.ts +6 -6
  138. package/templates/default/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +6 -6
  139. package/templates/default/specs/Playground/TC-0002-toggle-elements/spec.md +18 -18
  140. package/templates/default/specs/Playground/TC-0002-toggle-elements/web.test.ts +6 -6
  141. package/templates/default/spectra.config.ts +52 -52
  142. package/templates/default/support/actions/fillCredentials/mobile.action.ts +4 -4
  143. package/templates/default/support/actions/fillCredentials/web.action.ts +4 -4
  144. package/templates/default/support/actions/seedSession/mobile.action.ts +9 -9
  145. package/templates/default/support/actions/seedSession/web.action.ts +13 -13
  146. package/templates/default/support/steps/togglePlaygroundStates/mobile.step.ts +5 -5
  147. package/templates/default/support/steps/togglePlaygroundStates/web.step.ts +5 -5
  148. package/templates/default/support/steps/verifyPlaygroundState/mobile.step.ts +6 -6
  149. package/templates/default/support/steps/verifyPlaygroundState/web.step.ts +6 -6
  150. package/templates/docs/ARCHITECTURE.default.md +26 -0
  151. package/templates/docs/ARCHITECTURE.nx.md +119 -0
  152. package/templates/nx/.nx/workspace-data/{59842386-c7c4-44ca-b2c2-20e1700bd13d.db-shm → 70094CFD-E89B-57A1-9619-2FC5F4963C54.db-shm} +0 -0
  153. package/templates/nx/.nx/workspace-data/70094CFD-E89B-57A1-9619-2FC5F4963C54.db-wal +0 -0
  154. package/templates/nx/.nx/workspace-data/d/daemon.log +6343 -1612
  155. package/templates/nx/.nx/workspace-data/d/server-process.json +1 -1
  156. package/templates/nx/.nx/workspace-data/file-map.json +116 -130
  157. package/templates/nx/.nx/workspace-data/lockfile.hash +1 -1
  158. package/templates/nx/.nx/workspace-data/nx_files.nxt +0 -0
  159. package/templates/nx/.nx/workspace-data/parsed-lock-file.json +504 -504
  160. package/templates/nx/.nx/workspace-data/project-graph.json +560 -559
  161. package/templates/nx/.nx/workspace-data/source-maps.json +336 -0
  162. package/templates/nx/CLAUDE.md +10 -10
  163. package/templates/nx/package.json +3 -3
  164. package/templates/nx/packages/matchers/e2e/project.json +2 -2
  165. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/mobile.test.ts +27 -27
  166. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/web.test.ts +27 -27
  167. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/mobile.test.ts +24 -24
  168. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/web.test.ts +24 -24
  169. package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +3 -3
  170. package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +19 -19
  171. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +3 -3
  172. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +17 -17
  173. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +3 -3
  174. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +11 -11
  175. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +3 -3
  176. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +11 -11
  177. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +3 -3
  178. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +29 -29
  179. package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/common.test.ts +5 -5
  180. package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/spec.md +16 -16
  181. package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/suite.md +9 -9
  182. package/templates/nx/packages/playground/e2e/project.json +2 -2
  183. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0001-form-controls/mobile.test.ts +3 -3
  184. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0001-form-controls/web.test.ts +6 -6
  185. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +3 -3
  186. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0002-toggle-elements/web.test.ts +6 -6
  187. package/templates/nx/pnpm-lock.yaml +6663 -6663
  188. package/templates/nx/pnpm-workspace.yaml +9 -9
  189. package/templates/nx/shared/testing/page-objects/MatchersPage/mobile.ts +33 -33
  190. package/templates/nx/shared/testing/page-objects/MatchersPage/web.ts +91 -91
  191. package/templates/nx/shared/testing/page-objects/NavigationPage/mobile.ts +5 -5
  192. package/templates/nx/shared/testing/page-objects/NavigationPage/web.ts +8 -8
  193. package/templates/nx/shared/testing/page-objects/PlaygroundPage/mobile.ts +26 -26
  194. package/templates/nx/shared/testing/page-objects/PlaygroundPage/web.ts +31 -31
  195. package/templates/nx/shared/testing/project.json +18 -19
  196. package/templates/nx/shared/testing/support/actions/fillCredentials/mobile.action.ts +4 -4
  197. package/templates/nx/shared/testing/support/actions/fillCredentials/web.action.ts +4 -4
  198. package/templates/nx/shared/testing/support/steps/togglePlaygroundStates/mobile.step.ts +3 -3
  199. package/templates/nx/shared/testing/support/steps/togglePlaygroundStates/web.step.ts +5 -5
  200. package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/mobile.step.ts +4 -4
  201. package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/web.step.ts +6 -6
  202. package/templates/nx/spectra.config.ts +65 -52
  203. package/templates/react-component/.cursorrules +17 -17
  204. package/templates/react-component/.vscode/extensions.json +5 -5
  205. package/templates/react-component/CLAUDE.md +14 -14
  206. package/templates/react-component/README.md +69 -69
  207. package/templates/react-component/fixtures/component-mock.json +12 -12
  208. package/templates/react-component/global-hooks/after/web.hook.ts +3 -3
  209. package/templates/react-component/global-hooks/before/web.hook.ts +3 -3
  210. package/templates/react-component/package.json +27 -27
  211. package/templates/react-component/page-objects/BadgeComponent/web.ts +23 -23
  212. package/templates/react-component/page-objects/ButtonComponent/web.ts +23 -23
  213. package/templates/react-component/page-objects/InputComponent/web.ts +13 -13
  214. package/templates/react-component/specs/BadgeComponent/TC-0002-badge-severities-and-dot/spec.md +18 -18
  215. package/templates/react-component/specs/BadgeComponent/TC-0002-badge-severities-and-dot/web.test.tsx +11 -11
  216. package/templates/react-component/specs/BadgeComponent/TC-0006-badge-success-with-dot/spec.md +18 -18
  217. package/templates/react-component/specs/BadgeComponent/TC-0006-badge-success-with-dot/web.test.tsx +10 -10
  218. package/templates/react-component/specs/BadgeComponent/TC-0007-badge-by-severity-lookup/spec.md +18 -18
  219. package/templates/react-component/specs/BadgeComponent/TC-0007-badge-by-severity-lookup/web.test.tsx +16 -16
  220. package/templates/react-component/specs/BadgeComponent/suite.md +12 -12
  221. package/templates/react-component/specs/ButtonComponent/TC-0001-button-rendering-and-click/spec.md +19 -19
  222. package/templates/react-component/specs/ButtonComponent/TC-0001-button-rendering-and-click/web.test.tsx +25 -28
  223. package/templates/react-component/specs/ButtonComponent/TC-0004-disabled-button-not-clickable/spec.md +19 -19
  224. package/templates/react-component/specs/ButtonComponent/TC-0004-disabled-button-not-clickable/web.test.tsx +13 -22
  225. package/templates/react-component/specs/ButtonComponent/TC-0005-button-renders-icon/spec.md +18 -18
  226. package/templates/react-component/specs/ButtonComponent/TC-0005-button-renders-icon/web.test.tsx +8 -8
  227. package/templates/react-component/specs/ButtonComponent/suite.md +12 -12
  228. package/templates/react-component/specs/InputComponent/TC-0003-input-typing-and-clear/spec.md +20 -20
  229. package/templates/react-component/specs/InputComponent/TC-0003-input-typing-and-clear/web.test.tsx +24 -28
  230. package/templates/react-component/specs/InputComponent/TC-0008-disabled-input-not-editable/spec.md +18 -18
  231. package/templates/react-component/specs/InputComponent/TC-0008-disabled-input-not-editable/web.test.tsx +9 -9
  232. package/templates/react-component/specs/InputComponent/suite.md +12 -12
  233. package/templates/react-component/spectra.config.ts +17 -27
  234. package/templates/react-component/src/components/Badge/Badge.tsx +60 -60
  235. package/templates/react-component/src/components/Button/Button.tsx +59 -57
  236. package/templates/react-component/src/components/Input/Input.tsx +40 -41
  237. package/templates/react-component/src/test-utils.tsx +23 -23
  238. package/templates/react-component/support/actions/fillInputField/web.action.ts +9 -9
  239. package/templates/react-component/support/steps/verifyButtonState/web.step.ts +12 -12
  240. package/bin/.testspectra-runner.hash +0 -1
  241. package/bin/testspectra-runner.exe +0 -0
  242. package/templates/nx/.nx/workspace-data/59842386-c7c4-44ca-b2c2-20e1700bd13d.db-wal +0 -0
  243. /package/templates/nx/.nx/workspace-data/{59842386-c7c4-44ca-b2c2-20e1700bd13d.db → 70094CFD-E89B-57A1-9619-2FC5F4963C54.db} +0 -0
@@ -19,23 +19,23 @@ describe('Spec Schema Linter (Stage 1 & Stage 2)', () => {
19
19
  describe('Spec File Validation (spec.md)', () => {
20
20
  it('passes validation for a well-formed spec.md with frontmatter, H1 title, and Test Steps', () => {
21
21
  const specPath = path.join(tempDir, 'spec.md');
22
- fs.writeFileSync(specPath, `---
23
- id: TC-0001-valid
24
- title: Verify user authentication
25
- priority: High
26
- caseType: Positive
27
- status: ready-for-automation
28
- coverage:
29
- web: automated
30
- mobile: automated
31
- tags:
32
- - auth
33
- ---
34
-
35
- # Verify user authentication
36
-
37
- ## Test Steps
38
- 1. Open login page and submit credentials
22
+ fs.writeFileSync(specPath, `---
23
+ id: TC-0001-valid
24
+ title: Verify user authentication
25
+ priority: High
26
+ caseType: Positive
27
+ status: ready-for-automation
28
+ coverage:
29
+ web: automated
30
+ mobile: automated
31
+ tags:
32
+ - auth
33
+ ---
34
+
35
+ # Verify user authentication
36
+
37
+ ## Test Steps
38
+ 1. Open login page and submit credentials
39
39
  `);
40
40
  const result = SpecLinter.validateSpecFile(specPath);
41
41
  expect(result.diagnostics).toHaveLength(0);
@@ -43,16 +43,16 @@ tags:
43
43
  });
44
44
  it('reports testspectra/missing-frontmatter when required frontmatter attributes are missing', () => {
45
45
  const specPath = path.join(tempDir, 'spec.md');
46
- fs.writeFileSync(specPath, `---
47
- id: TC-0002-missing-attrs
48
- title: Missing priority and caseType
49
- status: draft
50
- ---
51
-
52
- # Missing priority and caseType
53
-
54
- ## Test Steps
55
- 1. Step one
46
+ fs.writeFileSync(specPath, `---
47
+ id: TC-0002-missing-attrs
48
+ title: Missing priority and caseType
49
+ status: draft
50
+ ---
51
+
52
+ # Missing priority and caseType
53
+
54
+ ## Test Steps
55
+ 1. Step one
56
56
  `);
57
57
  const result = SpecLinter.validateSpecFile(specPath);
58
58
  const codes = result.diagnostics.map((d) => d.code);
@@ -69,17 +69,17 @@ status: draft
69
69
  it('differentiates missing status (testspectra/missing-frontmatter) from invalid status value (testspectra/invalid-frontmatter-enum)', () => {
70
70
  // 1. Missing status -> testspectra/missing-frontmatter
71
71
  const missingSpecPath = path.join(tempDir, 'missing-status.spec.md');
72
- fs.writeFileSync(missingSpecPath, `---
73
- id: TC-0002-missing-status
74
- title: Missing Status Spec
75
- priority: High
76
- caseType: Positive
77
- ---
78
-
79
- # Missing Status Spec
80
-
81
- ## Test Steps
82
- 1. Step one
72
+ fs.writeFileSync(missingSpecPath, `---
73
+ id: TC-0002-missing-status
74
+ title: Missing Status Spec
75
+ priority: High
76
+ caseType: Positive
77
+ ---
78
+
79
+ # Missing Status Spec
80
+
81
+ ## Test Steps
82
+ 1. Step one
83
83
  `);
84
84
  const missingResult = SpecLinter.validateSpecFile(missingSpecPath);
85
85
  const missingStatusDiag = missingResult.diagnostics.find((d) => d.code === 'testspectra/missing-frontmatter' &&
@@ -89,18 +89,18 @@ caseType: Positive
89
89
  expect(missingResult.diagnostics.some((d) => d.code === 'testspectra/invalid-frontmatter-enum')).toBe(false);
90
90
  // 2. Invalid status -> testspectra/invalid-frontmatter-enum
91
91
  const invalidSpecPath = path.join(tempDir, 'invalid-status.spec.md');
92
- fs.writeFileSync(invalidSpecPath, `---
93
- id: TC-0002-invalid-status
94
- title: Invalid Status Spec
95
- priority: High
96
- caseType: Positive
97
- status: not-a-valid-status
98
- ---
99
-
100
- # Invalid Status Spec
101
-
102
- ## Test Steps
103
- 1. Step one
92
+ fs.writeFileSync(invalidSpecPath, `---
93
+ id: TC-0002-invalid-status
94
+ title: Invalid Status Spec
95
+ priority: High
96
+ caseType: Positive
97
+ status: not-a-valid-status
98
+ ---
99
+
100
+ # Invalid Status Spec
101
+
102
+ ## Test Steps
103
+ 1. Step one
104
104
  `);
105
105
  const invalidResult = SpecLinter.validateSpecFile(invalidSpecPath);
106
106
  const invalidStatusDiag = invalidResult.diagnostics.find((d) => d.code === 'testspectra/invalid-frontmatter-enum' &&
@@ -111,18 +111,18 @@ status: not-a-valid-status
111
111
  });
112
112
  it('reports testspectra/invalid-frontmatter-enum when enum attributes have invalid values', () => {
113
113
  const specPath = path.join(tempDir, 'spec.md');
114
- fs.writeFileSync(specPath, `---
115
- id: TC-0003-invalid-enum
116
- title: Invalid priority value
117
- priority: SuperHigh
118
- caseType: MaybePositive
119
- status: unknown-status
120
- ---
121
-
122
- # Invalid priority value
123
-
124
- ## Test Steps
125
- 1. Step one
114
+ fs.writeFileSync(specPath, `---
115
+ id: TC-0003-invalid-enum
116
+ title: Invalid priority value
117
+ priority: SuperHigh
118
+ caseType: MaybePositive
119
+ status: unknown-status
120
+ ---
121
+
122
+ # Invalid priority value
123
+
124
+ ## Test Steps
125
+ 1. Step one
126
126
  `);
127
127
  const result = SpecLinter.validateSpecFile(specPath);
128
128
  const enumErrors = result.diagnostics.filter((d) => d.code === 'testspectra/invalid-frontmatter-enum');
@@ -133,16 +133,16 @@ status: unknown-status
133
133
  });
134
134
  it('reports testspectra/missing-frontmatter when required H1 title section is missing in spec.md body', () => {
135
135
  const specPath = path.join(tempDir, 'spec.md');
136
- fs.writeFileSync(specPath, `---
137
- id: TC-0004-no-h1
138
- title: No Heading Section
139
- priority: High
140
- caseType: Positive
141
- status: draft
142
- ---
143
-
144
- ## Test Steps
145
- 1. Step without H1
136
+ fs.writeFileSync(specPath, `---
137
+ id: TC-0004-no-h1
138
+ title: No Heading Section
139
+ priority: High
140
+ caseType: Positive
141
+ status: draft
142
+ ---
143
+
144
+ ## Test Steps
145
+ 1. Step without H1
146
146
  `);
147
147
  const result = SpecLinter.validateSpecFile(specPath);
148
148
  const missingHeading = result.diagnostics.find((d) => d.code === 'testspectra/missing-frontmatter' && d.message.includes('expected top-level test title'));
@@ -151,17 +151,17 @@ status: draft
151
151
  });
152
152
  it('reports testspectra/missing-frontmatter when required ## Test Steps section is missing in spec.md body', () => {
153
153
  const specPath = path.join(tempDir, 'spec.md');
154
- fs.writeFileSync(specPath, `---
155
- id: TC-0005-no-steps
156
- title: No Steps Heading
157
- priority: High
158
- caseType: Positive
159
- status: draft
160
- ---
161
-
162
- # No Steps Heading
163
-
164
- Some narrative without Test Steps section.
154
+ fs.writeFileSync(specPath, `---
155
+ id: TC-0005-no-steps
156
+ title: No Steps Heading
157
+ priority: High
158
+ caseType: Positive
159
+ status: draft
160
+ ---
161
+
162
+ # No Steps Heading
163
+
164
+ Some narrative without Test Steps section.
165
165
  `);
166
166
  const result = SpecLinter.validateSpecFile(specPath);
167
167
  const missingSteps = result.diagnostics.find((d) => d.code === 'testspectra/missing-frontmatter' && d.message.includes('expected "## Test Steps"'));
@@ -170,20 +170,20 @@ Some narrative without Test Steps section.
170
170
  });
171
171
  it('warns when multiple H1 headings are declared in spec.md body', () => {
172
172
  const specPath = path.join(tempDir, 'spec.md');
173
- fs.writeFileSync(specPath, `---
174
- id: TC-0006-multiple-h1
175
- title: Multiple Headings
176
- priority: High
177
- caseType: Positive
178
- status: draft
179
- ---
180
-
181
- # First Title
182
-
183
- # Second Title
184
-
185
- ## Test Steps
186
- 1. Step
173
+ fs.writeFileSync(specPath, `---
174
+ id: TC-0006-multiple-h1
175
+ title: Multiple Headings
176
+ priority: High
177
+ caseType: Positive
178
+ status: draft
179
+ ---
180
+
181
+ # First Title
182
+
183
+ # Second Title
184
+
185
+ ## Test Steps
186
+ 1. Step
187
187
  `);
188
188
  const result = SpecLinter.validateSpecFile(specPath);
189
189
  const multipleH1 = result.diagnostics.find((d) => d.severity === 'warning' && d.message.includes('Multiple top-level H1 headings'));
@@ -191,10 +191,10 @@ status: draft
191
191
  });
192
192
  it('reports testspectra/parse-error on malformed YAML syntax', () => {
193
193
  const specPath = path.join(tempDir, 'spec.md');
194
- fs.writeFileSync(specPath, `---
195
- id: [broken yaml
196
- title: Test
197
- ---
194
+ fs.writeFileSync(specPath, `---
195
+ id: [broken yaml
196
+ title: Test
197
+ ---
198
198
  `);
199
199
  const result = SpecLinter.validateSpecFile(specPath);
200
200
  expect(result.diagnostics.some((d) => d.code === 'testspectra/parse-error')).toBe(true);
@@ -203,16 +203,16 @@ title: Test
203
203
  describe('Suite File Validation (suite.md)', () => {
204
204
  it('passes validation for a well-formed suite.md with H1 suite heading', () => {
205
205
  const suitePath = path.join(tempDir, 'suite.md');
206
- fs.writeFileSync(suitePath, `---
207
- id: suite-auth
208
- name: Authentication
209
- description: User authentication flows
210
- executionOrder: 1.0
211
- parallel: true
212
- status: active
213
- ---
214
-
215
- # Suite: Authentication
206
+ fs.writeFileSync(suitePath, `---
207
+ id: suite-auth
208
+ name: Authentication
209
+ description: User authentication flows
210
+ executionOrder: 1.0
211
+ parallel: true
212
+ status: active
213
+ ---
214
+
215
+ # Suite: Authentication
216
216
  `);
217
217
  const result = SpecLinter.validateSuiteFile(suitePath);
218
218
  expect(result.diagnostics).toHaveLength(0);
@@ -220,24 +220,24 @@ status: active
220
220
  });
221
221
  it('reports testspectra/missing-frontmatter when suite id or title/name is missing', () => {
222
222
  const suitePath = path.join(tempDir, 'suite.md');
223
- fs.writeFileSync(suitePath, `---
224
- description: No id and no name
225
- ---
226
-
227
- # Suite: Incomplete
223
+ fs.writeFileSync(suitePath, `---
224
+ description: No id and no name
225
+ ---
226
+
227
+ # Suite: Incomplete
228
228
  `);
229
229
  const result = SpecLinter.validateSuiteFile(suitePath);
230
230
  expect(result.diagnostics.some((d) => d.code === 'testspectra/missing-frontmatter')).toBe(true);
231
231
  });
232
232
  it('reports testspectra/invalid-frontmatter-enum when suite status has invalid enum value', () => {
233
233
  const suitePath = path.join(tempDir, 'suite.md');
234
- fs.writeFileSync(suitePath, `---
235
- id: suite-invalid-status
236
- name: Invalid Status Suite
237
- status: unknown-status
238
- ---
239
-
240
- # Suite: Invalid Status Suite
234
+ fs.writeFileSync(suitePath, `---
235
+ id: suite-invalid-status
236
+ name: Invalid Status Suite
237
+ status: unknown-status
238
+ ---
239
+
240
+ # Suite: Invalid Status Suite
241
241
  `);
242
242
  const result = SpecLinter.validateSuiteFile(suitePath);
243
243
  const enumErr = result.diagnostics.find((d) => d.code === 'testspectra/invalid-frontmatter-enum');
@@ -246,13 +246,13 @@ status: unknown-status
246
246
  });
247
247
  it('supports in-memory content override for suite.md without writing to disk', () => {
248
248
  const suitePath = path.join(tempDir, 'non-existent-suite.md');
249
- const inMemoryContent = `---
250
- id: suite-in-memory
251
- title: In Memory Suite
252
- status: active
253
- ---
254
-
255
- # Suite: In Memory Suite
249
+ const inMemoryContent = `---
250
+ id: suite-in-memory
251
+ title: In Memory Suite
252
+ status: active
253
+ ---
254
+
255
+ # Suite: In Memory Suite
256
256
  `;
257
257
  const result = SpecLinter.validateSuiteFile(suitePath, inMemoryContent);
258
258
  expect(result.diagnostics).toHaveLength(0);
@@ -260,12 +260,12 @@ status: active
260
260
  });
261
261
  it('reports testspectra/missing-frontmatter when suite H1 title heading is missing', () => {
262
262
  const suitePath = path.join(tempDir, 'suite.md');
263
- fs.writeFileSync(suitePath, `---
264
- id: suite-no-heading
265
- name: No Heading
266
- ---
267
-
268
- Body without H1 suite heading.
263
+ fs.writeFileSync(suitePath, `---
264
+ id: suite-no-heading
265
+ name: No Heading
266
+ ---
267
+
268
+ Body without H1 suite heading.
269
269
  `);
270
270
  const result = SpecLinter.validateSuiteFile(suitePath);
271
271
  const headingErr = result.diagnostics.find((d) => d.code === 'testspectra/missing-frontmatter' && d.message.includes('expected top-level suite title'));
@@ -278,18 +278,18 @@ Body without H1 suite heading.
278
278
  const tc2Dir = path.join(tempDir, 'TC-2');
279
279
  fs.mkdirSync(tc1Dir, { recursive: true });
280
280
  fs.mkdirSync(tc2Dir, { recursive: true });
281
- const specContent = `---
282
- id: TC-DUPLICATE-001
283
- title: Duplicate test case
284
- priority: High
285
- caseType: Positive
286
- status: automated
287
- ---
288
-
289
- # Duplicate test case
290
-
291
- ## Test Steps
292
- 1. Duplicate step
281
+ const specContent = `---
282
+ id: TC-DUPLICATE-001
283
+ title: Duplicate test case
284
+ priority: High
285
+ caseType: Positive
286
+ status: automated
287
+ ---
288
+
289
+ # Duplicate test case
290
+
291
+ ## Test Steps
292
+ 1. Duplicate step
293
293
  `;
294
294
  fs.writeFileSync(path.join(tc1Dir, 'spec.md'), specContent);
295
295
  fs.writeFileSync(path.join(tc2Dir, 'spec.md'), specContent);
@@ -303,26 +303,26 @@ status: automated
303
303
  const validSuiteDir = path.join(tempDir, 'ValidSuite');
304
304
  const validTcDir = path.join(validSuiteDir, 'TC-001');
305
305
  fs.mkdirSync(validTcDir, { recursive: true });
306
- fs.writeFileSync(path.join(validSuiteDir, 'suite.md'), `---
307
- id: suite-valid
308
- name: Valid Suite
309
- status: active
310
- ---
311
-
312
- # Suite: Valid Suite
306
+ fs.writeFileSync(path.join(validSuiteDir, 'suite.md'), `---
307
+ id: suite-valid
308
+ name: Valid Suite
309
+ status: active
310
+ ---
311
+
312
+ # Suite: Valid Suite
313
313
  `);
314
- fs.writeFileSync(path.join(validTcDir, 'spec.md'), `---
315
- id: TC-VALID-001
316
- title: Valid Test Case
317
- priority: High
318
- caseType: Positive
319
- status: automated
320
- ---
321
-
322
- # Valid Test Case
323
-
324
- ## Test Steps
325
- 1. Open page
314
+ fs.writeFileSync(path.join(validTcDir, 'spec.md'), `---
315
+ id: TC-VALID-001
316
+ title: Valid Test Case
317
+ priority: High
318
+ caseType: Positive
319
+ status: automated
320
+ ---
321
+
322
+ # Valid Test Case
323
+
324
+ ## Test Steps
325
+ 1. Open page
326
326
  `);
327
327
  fs.writeFileSync(path.join(validTcDir, 'web.test.ts'), `it('Valid Test Case', async () => {});\n`);
328
328
  const result = SpecLinter.validateWorkspace(tempDir);
@@ -4,14 +4,14 @@ export interface WorkspaceAssets {
4
4
  fixtures: Set<string>;
5
5
  }
6
6
  /**
7
- * Scans a workspace directory for all `project.json` files that have both
8
- * "scope:shared" and "type:shared" tags, and returns their parent folder paths.
7
+ * Scans a workspace directory for all `project.json` files that have the
8
+ * "testspectra:shared" tag, and returns their parent folder paths.
9
9
  */
10
10
  export declare function findSharedLibraryRoots(workspaceDir: string): string[];
11
11
  /**
12
12
  * Resolves the root directory of a shared testing library if the file path is inside one.
13
13
  * Determines shared library status based on `project.json` containing
14
- * both "scope:shared" and "type:shared" tags in ancestor directories,
14
+ * the "testspectra:shared" tag in ancestor directories,
15
15
  * taking the parent folder of that `project.json` as the shared library root.
16
16
  */
17
17
  export declare function getSharedLibraryRoot(filePath: string, workspaceDir?: string): string | null;
@@ -1,8 +1,9 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
+ import { ConfigLoader } from '../config/loader.js';
3
4
  /**
4
- * Scans a workspace directory for all `project.json` files that have both
5
- * "scope:shared" and "type:shared" tags, and returns their parent folder paths.
5
+ * Scans a workspace directory for all `project.json` files that have the
6
+ * "testspectra:shared" tag, and returns their parent folder paths.
6
7
  */
7
8
  export function findSharedLibraryRoots(workspaceDir) {
8
9
  const sharedRoots = [];
@@ -23,7 +24,7 @@ export function findSharedLibraryRoots(workspaceDir) {
23
24
  const raw = fs.readFileSync(path.join(dir, entry.name), 'utf-8');
24
25
  const parsed = JSON.parse(raw);
25
26
  const tags = Array.isArray(parsed.tags) ? parsed.tags : [];
26
- if (tags.includes('scope:shared') && tags.includes('type:shared')) {
27
+ if (tags.includes('testspectra:shared')) {
27
28
  sharedRoots.push(dir);
28
29
  }
29
30
  }
@@ -39,7 +40,7 @@ export function findSharedLibraryRoots(workspaceDir) {
39
40
  /**
40
41
  * Resolves the root directory of a shared testing library if the file path is inside one.
41
42
  * Determines shared library status based on `project.json` containing
42
- * both "scope:shared" and "type:shared" tags in ancestor directories,
43
+ * the "testspectra:shared" tag in ancestor directories,
43
44
  * taking the parent folder of that `project.json` as the shared library root.
44
45
  */
45
46
  export function getSharedLibraryRoot(filePath, workspaceDir) {
@@ -67,7 +68,7 @@ export function getSharedLibraryRoot(filePath, workspaceDir) {
67
68
  const raw = fs.readFileSync(projectJsonPath, 'utf-8');
68
69
  const projectConfig = JSON.parse(raw);
69
70
  const tags = Array.isArray(projectConfig.tags) ? projectConfig.tags : [];
70
- if (tags.includes('scope:shared') && tags.includes('type:shared')) {
71
+ if (tags.includes('testspectra:shared')) {
71
72
  return current;
72
73
  }
73
74
  return null;
@@ -96,8 +97,7 @@ export function isInsideSharedLibrary(filePath, workspaceDir) {
96
97
  export function findProjectRoot(startDir) {
97
98
  let current = path.resolve(startDir);
98
99
  while (true) {
99
- if (fs.existsSync(path.join(current, 'spectra.config.ts')) ||
100
- fs.existsSync(path.join(current, 'spectra.config.js'))) {
100
+ if (ConfigLoader.CONFIG_FILE_NAMES.some((name) => fs.existsSync(path.join(current, name)))) {
101
101
  return current;
102
102
  }
103
103
  const parent = path.dirname(current);
@@ -11,11 +11,11 @@ export declare const CoverageSchema: z.ZodObject<{
11
11
  web: z.ZodOptional<z.ZodEnum<["automated", "manual", "unsupported"]>>;
12
12
  mobile: z.ZodOptional<z.ZodEnum<["automated", "manual", "unsupported"]>>;
13
13
  }, "strip", z.ZodTypeAny, {
14
- web?: "automated" | "manual" | "unsupported" | undefined;
15
14
  mobile?: "automated" | "manual" | "unsupported" | undefined;
16
- }, {
17
15
  web?: "automated" | "manual" | "unsupported" | undefined;
16
+ }, {
18
17
  mobile?: "automated" | "manual" | "unsupported" | undefined;
18
+ web?: "automated" | "manual" | "unsupported" | undefined;
19
19
  }>;
20
20
  export declare const SpecFrontmatterSchema: z.ZodObject<{
21
21
  id: z.ZodString;
@@ -27,33 +27,33 @@ export declare const SpecFrontmatterSchema: z.ZodObject<{
27
27
  web: z.ZodOptional<z.ZodEnum<["automated", "manual", "unsupported"]>>;
28
28
  mobile: z.ZodOptional<z.ZodEnum<["automated", "manual", "unsupported"]>>;
29
29
  }, "strip", z.ZodTypeAny, {
30
- web?: "automated" | "manual" | "unsupported" | undefined;
31
30
  mobile?: "automated" | "manual" | "unsupported" | undefined;
32
- }, {
33
31
  web?: "automated" | "manual" | "unsupported" | undefined;
32
+ }, {
34
33
  mobile?: "automated" | "manual" | "unsupported" | undefined;
34
+ web?: "automated" | "manual" | "unsupported" | undefined;
35
35
  }>>;
36
36
  tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
37
37
  }, "strip", z.ZodTypeAny, {
38
38
  id: string;
39
- status: "draft" | "ready-for-automation" | "automated" | "deprecated";
40
39
  title: string;
40
+ status: "draft" | "ready-for-automation" | "automated" | "deprecated";
41
41
  priority: "Critical" | "High" | "Medium" | "Low";
42
42
  caseType: "Positive" | "Negative" | "Edge";
43
43
  coverage?: {
44
- web?: "automated" | "manual" | "unsupported" | undefined;
45
44
  mobile?: "automated" | "manual" | "unsupported" | undefined;
45
+ web?: "automated" | "manual" | "unsupported" | undefined;
46
46
  } | undefined;
47
47
  tags?: string[] | undefined;
48
48
  }, {
49
49
  id: string;
50
- status: "draft" | "ready-for-automation" | "automated" | "deprecated";
51
50
  title: string;
51
+ status: "draft" | "ready-for-automation" | "automated" | "deprecated";
52
52
  priority: "Critical" | "High" | "Medium" | "Low";
53
53
  caseType: "Positive" | "Negative" | "Edge";
54
54
  coverage?: {
55
- web?: "automated" | "manual" | "unsupported" | undefined;
56
55
  mobile?: "automated" | "manual" | "unsupported" | undefined;
56
+ web?: "automated" | "manual" | "unsupported" | undefined;
57
57
  } | undefined;
58
58
  tags?: string[] | undefined;
59
59
  }>;
@@ -15,8 +15,8 @@ export declare const SuiteFrontmatterSchema: z.ZodEffects<z.ZodObject<{
15
15
  }, "strip", z.ZodTypeAny, {
16
16
  id: string;
17
17
  name?: string | undefined;
18
- status?: "active" | "draft" | "deprecated" | undefined;
19
18
  title?: string | undefined;
19
+ status?: "draft" | "deprecated" | "active" | undefined;
20
20
  tags?: string[] | undefined;
21
21
  description?: string | undefined;
22
22
  executionOrder?: number | undefined;
@@ -24,8 +24,8 @@ export declare const SuiteFrontmatterSchema: z.ZodEffects<z.ZodObject<{
24
24
  }, {
25
25
  id: string;
26
26
  name?: string | undefined;
27
- status?: "active" | "draft" | "deprecated" | undefined;
28
27
  title?: string | undefined;
28
+ status?: "draft" | "deprecated" | "active" | undefined;
29
29
  tags?: string[] | undefined;
30
30
  description?: string | undefined;
31
31
  executionOrder?: number | undefined;
@@ -33,8 +33,8 @@ export declare const SuiteFrontmatterSchema: z.ZodEffects<z.ZodObject<{
33
33
  }>, {
34
34
  id: string;
35
35
  name?: string | undefined;
36
- status?: "active" | "draft" | "deprecated" | undefined;
37
36
  title?: string | undefined;
37
+ status?: "draft" | "deprecated" | "active" | undefined;
38
38
  tags?: string[] | undefined;
39
39
  description?: string | undefined;
40
40
  executionOrder?: number | undefined;
@@ -42,8 +42,8 @@ export declare const SuiteFrontmatterSchema: z.ZodEffects<z.ZodObject<{
42
42
  }, {
43
43
  id: string;
44
44
  name?: string | undefined;
45
- status?: "active" | "draft" | "deprecated" | undefined;
46
45
  title?: string | undefined;
46
+ status?: "draft" | "deprecated" | "active" | undefined;
47
47
  tags?: string[] | undefined;
48
48
  description?: string | undefined;
49
49
  executionOrder?: number | undefined;
@@ -3,7 +3,7 @@ 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' | 'mobile';
6
+ platform: 'web' | 'android' | 'ios' | 'common' | 'mobile' | 'component';
7
7
  suite?: string;
8
8
  testCases?: Array<{
9
9
  id: string;