@testspectra/cli 1.1.7 → 1.1.8-rc.10

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 (256) hide show
  1. package/README.md +47 -0
  2. package/demo-app/assets/index-BhlW-eXG.css +1 -0
  3. package/demo-app/assets/index-DOtRypCa.js +154 -0
  4. package/demo-app/index.html +2 -2
  5. package/dist/.tsbuildinfo +1 -1
  6. package/dist/commands/__tests__/run-e2e.test.js +254 -13
  7. package/dist/commands/__tests__/run.test.js +92 -16
  8. package/dist/commands/add.js +2 -1
  9. package/dist/commands/demo.js +17 -7
  10. package/dist/commands/init.d.ts +1 -1
  11. package/dist/commands/init.js +8 -2
  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 +104 -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 +39 -1
  29. package/dist/generator/tsconfig-generator.js +44 -16
  30. package/dist/generator/type-generator.d.ts +29 -3
  31. package/dist/generator/type-generator.js +115 -22
  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 +22 -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 +85 -24
  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 +13 -4
  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 +5803 -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 +14388 -0
  171. package/templates/nx/package.json +3 -3
  172. package/templates/nx/packages/matchers/e2e/project.json +2 -2
  173. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/mobile.test.ts +25 -1
  174. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/web.test.ts +2 -2
  175. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/mobile.test.ts +22 -1
  176. package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/web.test.ts +2 -2
  177. package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +1 -1
  178. package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +1 -1
  179. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +1 -1
  180. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +1 -1
  181. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +1 -1
  182. package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +1 -1
  183. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +1 -1
  184. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +1 -1
  185. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +1 -1
  186. package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +1 -1
  187. package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/common.test.ts +5 -0
  188. package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/spec.md +16 -0
  189. package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/suite.md +9 -0
  190. package/templates/nx/packages/playground/e2e/project.json +2 -2
  191. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0001-form-controls/mobile.test.ts +1 -1
  192. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0001-form-controls/web.test.ts +1 -1
  193. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +1 -1
  194. package/templates/nx/packages/playground/e2e/specs/Playground/TC-0002-toggle-elements/web.test.ts +1 -1
  195. package/templates/nx/shared/testing/page-objects/MatchersPage/mobile.ts +1 -1
  196. package/templates/nx/shared/testing/page-objects/MatchersPage/web.ts +83 -29
  197. package/templates/nx/shared/testing/page-objects/NavigationPage/mobile.ts +1 -1
  198. package/templates/nx/shared/testing/page-objects/NavigationPage/web.ts +1 -1
  199. package/templates/nx/shared/testing/page-objects/PlaygroundPage/mobile.ts +1 -1
  200. package/templates/nx/shared/testing/page-objects/PlaygroundPage/web.ts +2 -2
  201. package/templates/nx/shared/testing/project.json +1 -2
  202. package/templates/nx/shared/testing/support/actions/fillCredentials/mobile.action.ts +1 -1
  203. package/templates/nx/shared/testing/support/actions/fillCredentials/web.action.ts +1 -1
  204. package/templates/nx/shared/testing/support/steps/togglePlaygroundStates/mobile.step.ts +1 -1
  205. package/templates/nx/shared/testing/support/steps/togglePlaygroundStates/web.step.ts +1 -1
  206. package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/mobile.step.ts +1 -1
  207. package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/web.step.ts +1 -1
  208. package/templates/nx/spectra.config.ts +1 -17
  209. package/templates/react-component/.cursorrules +17 -0
  210. package/templates/react-component/.vscode/extensions.json +5 -0
  211. package/templates/react-component/CLAUDE.md +14 -0
  212. package/templates/react-component/README.md +69 -0
  213. package/templates/react-component/fixtures/component-mock.json +12 -0
  214. package/templates/react-component/global-hooks/after/web.hook.ts +3 -0
  215. package/templates/react-component/global-hooks/before/web.hook.ts +3 -0
  216. package/templates/react-component/package.json +27 -0
  217. package/templates/react-component/page-objects/BadgeComponent/web.ts +23 -0
  218. package/templates/react-component/page-objects/ButtonComponent/web.ts +23 -0
  219. package/templates/react-component/page-objects/InputComponent/web.ts +13 -0
  220. package/templates/react-component/specs/BadgeComponent/TC-0002-badge-severities-and-dot/spec.md +18 -0
  221. package/templates/react-component/specs/BadgeComponent/TC-0002-badge-severities-and-dot/web.test.tsx +11 -0
  222. package/templates/react-component/specs/BadgeComponent/TC-0006-badge-success-with-dot/spec.md +18 -0
  223. package/templates/react-component/specs/BadgeComponent/TC-0006-badge-success-with-dot/web.test.tsx +10 -0
  224. package/templates/react-component/specs/BadgeComponent/TC-0007-badge-by-severity-lookup/spec.md +18 -0
  225. package/templates/react-component/specs/BadgeComponent/TC-0007-badge-by-severity-lookup/web.test.tsx +16 -0
  226. package/templates/react-component/specs/BadgeComponent/suite.md +12 -0
  227. package/templates/react-component/specs/ButtonComponent/TC-0001-button-rendering-and-click/spec.md +19 -0
  228. package/templates/react-component/specs/ButtonComponent/TC-0001-button-rendering-and-click/web.test.tsx +28 -0
  229. package/templates/react-component/specs/ButtonComponent/TC-0004-disabled-button-not-clickable/spec.md +19 -0
  230. package/templates/react-component/specs/ButtonComponent/TC-0004-disabled-button-not-clickable/web.test.tsx +22 -0
  231. package/templates/react-component/specs/ButtonComponent/TC-0005-button-renders-icon/spec.md +18 -0
  232. package/templates/react-component/specs/ButtonComponent/TC-0005-button-renders-icon/web.test.tsx +8 -0
  233. package/templates/react-component/specs/ButtonComponent/suite.md +12 -0
  234. package/templates/react-component/specs/InputComponent/TC-0003-input-typing-and-clear/spec.md +20 -0
  235. package/templates/react-component/specs/InputComponent/TC-0003-input-typing-and-clear/web.test.tsx +28 -0
  236. package/templates/react-component/specs/InputComponent/TC-0008-disabled-input-not-editable/spec.md +18 -0
  237. package/templates/react-component/specs/InputComponent/TC-0008-disabled-input-not-editable/web.test.tsx +9 -0
  238. package/templates/react-component/specs/InputComponent/suite.md +12 -0
  239. package/templates/react-component/spectra.config.ts +27 -0
  240. package/templates/react-component/src/components/Badge/Badge.tsx +60 -0
  241. package/templates/react-component/src/components/Button/Button.tsx +57 -0
  242. package/templates/react-component/src/components/Input/Input.tsx +41 -0
  243. package/templates/react-component/src/test-utils.tsx +23 -0
  244. package/templates/react-component/support/actions/fillInputField/web.action.ts +9 -0
  245. package/templates/react-component/support/steps/verifyButtonState/web.step.ts +12 -0
  246. package/templates/react-component/tsconfig.json +8 -0
  247. package/bin/.testspectra-runner.hash +0 -1
  248. package/bin/testspectra-runner +0 -0
  249. package/demo-app/assets/index-DPfv5_EF.js +0 -116
  250. package/demo-app/assets/index-gIwu2EMV.css +0 -1
  251. package/dist/commands/__tests__/cloud-run.test.js +0 -93
  252. package/dist/commands/cloud-run.d.ts +0 -13
  253. package/dist/commands/cloud-run.js +0 -120
  254. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +0 -17
  255. package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +0 -17
  256. /package/dist/{commands/__tests__/cloud-run.test.d.ts → linter/__tests__/anonymous-export.test.d.ts} +0 -0
@@ -0,0 +1,104 @@
1
+ import path from 'node:path';
2
+ import chalk from 'chalk';
3
+ import * as p from '@clack/prompts';
4
+ import { renderSummaryView } from '../reporter/summary-view.js';
5
+ import { Reporter } from '../runner/reporter.js';
6
+ import { runSystemChecks } from './doctor.js';
7
+ /**
8
+ * Finds the Chrome-for-Testing binary that `spectra doctor` already installs/manages for the
9
+ * E2E CDP driver (`core/driver-cdp`) — same install, same binary. `@testspectra/react` must not
10
+ * contain any browser-discovery logic of its own (see the package-level comment in
11
+ * tools/react/vitest.config.ts): this is the one place that resolves the path, passed down to
12
+ * the bundled Vitest/Playwright runner as a plain argument (env var), so component testing never
13
+ * requires a separate `playwright install` download alongside TestSpectra's own browser.
14
+ */
15
+ async function resolveBrowserExecutable(cwd) {
16
+ try {
17
+ const { dependencies } = await runSystemChecks(cwd);
18
+ const chrome = dependencies.find((d) => d.category === 'web' && (d.name.includes('Chrome') || d.name.includes('Chromium')));
19
+ return chrome?.installed && chrome.location ? chrome.location : null;
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ /**
26
+ * `spectra test` — delegates to `@testspectra/react`'s bundled Vitest browser-mode runner for
27
+ * component testing. Deliberately separate from `spectra run` (E2E via core/orchestrator): see
28
+ * docs/v2/features/component-testing/react/README.md §2 for why these are two independent
29
+ * runners rather than one extended pipeline.
30
+ */
31
+ export async function testCommand(options = {}) {
32
+ const cwd = options.cwd ?? process.cwd();
33
+ let reactPkg;
34
+ try {
35
+ reactPkg = await import('@testspectra/react');
36
+ }
37
+ catch {
38
+ p.log.error(chalk.red('✖ @testspectra/react is not installed in this workspace.'));
39
+ p.log.info(chalk.dim('Component testing requires the @testspectra/react package.'));
40
+ p.log.info(chalk.dim(' 👉 Install it: pnpm add -D @testspectra/react'));
41
+ process.exit(1);
42
+ return;
43
+ }
44
+ const browserExecutablePath = await resolveBrowserExecutable(cwd);
45
+ if (!browserExecutablePath) {
46
+ p.log.error(chalk.red('✖ TestSpectra-managed Chrome for Testing was not found.'));
47
+ p.log.info(chalk.dim('Component testing reuses the same browser install as `spectra run` (web).'));
48
+ p.log.info(chalk.dim(' 👉 Install it: spectra doctor --fix'));
49
+ process.exit(1);
50
+ return;
51
+ }
52
+ let stepDelayMs;
53
+ const rawDelay = options.stepDelay ?? options.delay;
54
+ if (rawDelay !== undefined) {
55
+ const delayNum = parseInt(String(rawDelay), 10);
56
+ if (!isNaN(delayNum) && delayNum >= 0) {
57
+ stepDelayMs = delayNum;
58
+ }
59
+ }
60
+ let headless = true;
61
+ if (options.headed) {
62
+ headless = false;
63
+ }
64
+ else if (options.headless !== undefined) {
65
+ headless = options.headless;
66
+ }
67
+ const concurrency = options.concurrency !== undefined ? parseInt(String(options.concurrency), 10) : undefined;
68
+ const outputFile = options.output ? path.resolve(cwd, options.output) : undefined;
69
+ // Reuses the exact same semantic terminal reporter `spectra run` drives (see
70
+ // docs/v2/cli/matchers-semantic-reporter.md) — @testspectra/react emits the identical
71
+ // [TESTSPECTRA_*] protocol lines the E2E Rust orchestrator does (see tools/react/src/prelude.ts
72
+ // / setup.ts), so the same Reporter class parses them with zero changes on either side.
73
+ const reporter = new Reporter();
74
+ const runStartedAt = Date.now();
75
+ const ok = await reactPkg.runComponentTests({
76
+ cwd,
77
+ headless,
78
+ stepDelayMs,
79
+ spec: options.spec,
80
+ outputFile,
81
+ concurrency: concurrency !== undefined && !isNaN(concurrency) ? concurrency : undefined,
82
+ browserExecutablePath,
83
+ onLine: (line) => {
84
+ if (!line.startsWith('[TESTSPECTRA_'))
85
+ return;
86
+ reporter.addLog({ timestamp: new Date().toLocaleTimeString(), level: 'INFO', message: line });
87
+ if (!reporter.isInteractiveMode()) {
88
+ console.log(line);
89
+ }
90
+ },
91
+ });
92
+ const durationMs = Date.now() - runStartedAt;
93
+ const result = reporter.generateResult(ok ? 'passed' : 'failed', `${(durationMs / 1000).toFixed(1)}s`);
94
+ const totalTests = result.passedCount + result.failedCount;
95
+ renderSummaryView({
96
+ totalSuites: totalTests,
97
+ totalTests,
98
+ passedCount: result.passedCount,
99
+ failedCount: result.failedCount,
100
+ durationMs,
101
+ reportLocation: outputFile ? path.relative(cwd, outputFile) : '(use -o/--output to save a report)',
102
+ });
103
+ process.exit(ok ? 0 : 1);
104
+ }
@@ -3,15 +3,22 @@ import path from 'path';
3
3
  import chalk from 'chalk';
4
4
  import { TypeGenerator } from '../types/generator.js';
5
5
  export function startWatcher(cwd, debounceMs = 60) {
6
- // Initial generation
6
+ // Initial generation. TypeGenerator.generateAll itself stays synchronous (reading
7
+ // spectra.config.ts is unavoidably async, so that part is handled by the separate
8
+ // syncEnvDeclaration call below); startWatcher stays sync so it can return the watcher handle
9
+ // immediately, with the async env sync fired-and-forgotten.
7
10
  TypeGenerator.generateAll(cwd);
11
+ TypeGenerator.syncEnvDeclaration(cwd).catch((err) => {
12
+ console.error(chalk.red(`✖ Error generating initial env.d.ts: ${err?.message}`));
13
+ });
8
14
  let debounceTimer = null;
9
15
  const triggerRegen = (filePath, eventType) => {
10
16
  if (debounceTimer)
11
17
  clearTimeout(debounceTimer);
12
- debounceTimer = setTimeout(() => {
18
+ debounceTimer = setTimeout(async () => {
13
19
  try {
14
20
  TypeGenerator.generateAll(cwd);
21
+ await TypeGenerator.syncEnvDeclaration(cwd);
15
22
  const time = new Date().toLocaleTimeString();
16
23
  const rel = path.relative(cwd, filePath) || filePath;
17
24
  console.log(chalk.gray(`[${time}] `) + chalk.cyan(`✨ Updated ambient types `) + chalk.gray(`(${eventType}: ${rel})`));
@@ -34,7 +41,6 @@ export function startWatcher(cwd, debounceMs = 60) {
34
41
  }
35
42
  if (fn.includes('fixtures') ||
36
43
  fn.includes('page-objects') ||
37
- fn.includes('pageobjects') ||
38
44
  fn.includes('actions') ||
39
45
  fn.includes('steps') ||
40
46
  fn.includes('hooks') ||
@@ -89,7 +89,7 @@ export class ConfigLoader {
89
89
  environmentVariables: overrides?.executionConfig?.environmentVariables ??
90
90
  loaded.executionConfig?.environmentVariables ??
91
91
  DEFAULT_CONFIG_DATA.executionConfig?.environmentVariables ??
92
- [],
92
+ {},
93
93
  },
94
94
  };
95
95
  }
@@ -20,19 +20,11 @@ export interface WebConfig {
20
20
  headless: boolean | 'new';
21
21
  /**
22
22
  * Implicit wait timeout (in milliseconds) for finding elements before throwing an error.
23
+ * Also the ceiling auto-waiting element assertions/actions poll against (capped at 2000ms for
24
+ * assertions — see `getAssertionTimeoutMs()`).
23
25
  * @default "5000"
24
26
  */
25
27
  implicitWait: string;
26
- /**
27
- * Maximum time (in milliseconds) allowed for a webpage to complete navigation and initial load.
28
- * @default "30000"
29
- */
30
- pageLoadTimeout: string;
31
- /**
32
- * Maximum time (in milliseconds) allowed for asynchronous scripts to finish executing.
33
- * @default "30000"
34
- */
35
- scriptTimeout: string;
36
28
  /**
37
29
  * Delay between consecutive actions and commands in milliseconds (slow motion).
38
30
  * @default 0
@@ -46,37 +38,6 @@ export interface WebConfig {
46
38
  */
47
39
  parallelizationMode: 'testcase' | 'suite';
48
40
  }
49
- /**
50
- * Browser target definition for web test execution.
51
- */
52
- export interface Browser {
53
- /**
54
- * Unique identifier for this browser configuration.
55
- */
56
- id: string;
57
- /**
58
- * Browser type/engine: `"chrome"`, `"firefox"`, `"safari"`, `"edge"`.
59
- * @default "chrome"
60
- */
61
- type: string;
62
- /**
63
- * Whether to simulate mobile viewport and touch metrics.
64
- * @default false
65
- */
66
- mobileEmulation: boolean;
67
- /**
68
- * Emulated device name when `mobileEmulation` is true (e.g. `"iPhone 14"`, `"Pixel 7"`).
69
- */
70
- deviceName?: string;
71
- /**
72
- * Custom browser window width in pixels.
73
- */
74
- width?: string;
75
- /**
76
- * Custom browser window height in pixels.
77
- */
78
- height?: string;
79
- }
80
41
  /**
81
42
  * Target Android device specification for multi-device parallel execution.
82
43
  */
@@ -156,11 +117,6 @@ export interface AndroidConfig {
156
117
  * Main activity name launched when starting the app.
157
118
  */
158
119
  appActivity: string;
159
- /**
160
- * Whether to automatically grant Android runtime permissions upon installation.
161
- * @default true
162
- */
163
- autoGrantPermissions: boolean;
164
120
  /**
165
121
  * Whether to preserve app state and prevent clearing app data/cache between sessions.
166
122
  * @default false
@@ -265,40 +221,6 @@ export interface IosConfig {
265
221
  */
266
222
  parallelizationMode: 'testcase' | 'suite';
267
223
  }
268
- /**
269
- * Load testing stage ramp-up profile.
270
- */
271
- export interface LoadStage {
272
- /**
273
- * Stage identifier.
274
- */
275
- id: string;
276
- /**
277
- * Duration for this load stage (e.g. `"30s"`, `"2m"`).
278
- */
279
- duration: string;
280
- /**
281
- * Target virtual users (VUs) to scale to during this stage.
282
- */
283
- targetVUs: string;
284
- }
285
- /**
286
- * Performance and pass/fail metric threshold definition.
287
- */
288
- export interface SuccessThreshold {
289
- /**
290
- * Unique threshold identifier.
291
- */
292
- id: string;
293
- /**
294
- * Performance metric type (e.g. `"http_req_duration"`, `"http_req_failed"`).
295
- */
296
- metricType: string;
297
- /**
298
- * Maximum acceptable value (e.g. `"500ms"`, `"0.01"`).
299
- */
300
- maxValue: string;
301
- }
302
224
  /**
303
225
  * Specific domain filter for real-time network interception and recording.
304
226
  */
@@ -312,19 +234,6 @@ export interface MonitoredDomain {
312
234
  */
313
235
  enabled: boolean;
314
236
  }
315
- /**
316
- * Custom environment variable key-value pair injected into the test execution sandbox.
317
- */
318
- export interface EnvironmentVariable {
319
- /**
320
- * Environment variable name (e.g. `"API_SECRET_KEY"`).
321
- */
322
- key: string;
323
- /**
324
- * Environment variable value.
325
- */
326
- value: string;
327
- }
328
237
  /**
329
238
  * Test execution, CDP network monitoring, and sandbox environment configuration.
330
239
  */
@@ -349,9 +258,10 @@ export interface ExecutionConfig {
349
258
  */
350
259
  monitoredDomains?: MonitoredDomain[];
351
260
  /**
352
- * Custom environment variables injected into the test process runtime.
261
+ * Custom environment variables injected into the test process runtime
262
+ * (e.g. `{ API_SECRET_KEY: "..." }`).
353
263
  */
354
- environmentVariables?: EnvironmentVariable[];
264
+ environmentVariables?: Record<string, string>;
355
265
  }
356
266
  /**
357
267
  * Root configuration data structure matching TestSpectra project schema.
@@ -361,10 +271,6 @@ export interface ConfigData {
361
271
  * Web browser execution settings.
362
272
  */
363
273
  webConfig: WebConfig;
364
- /**
365
- * List of target browsers for web automation runs.
366
- */
367
- browsers: Browser[];
368
274
  /**
369
275
  * Android Appium driver and device options.
370
276
  */
@@ -373,21 +279,6 @@ export interface ConfigData {
373
279
  * iOS Appium driver and device options.
374
280
  */
375
281
  iosConfig: IosConfig;
376
- /**
377
- * Load testing parameters.
378
- */
379
- loadConfig: {
380
- virtualUsers: string;
381
- duration: string;
382
- };
383
- /**
384
- * Load testing stages.
385
- */
386
- loadStages: LoadStage[];
387
- /**
388
- * Pass/fail metric thresholds.
389
- */
390
- thresholds: SuccessThreshold[];
391
282
  /**
392
283
  * Advanced execution and network recording settings.
393
284
  */
@@ -25,22 +25,12 @@ export const DEFAULT_CONFIG_DATA = {
25
25
  maxConcurrentSessions: '1',
26
26
  headless: true,
27
27
  implicitWait: '5000',
28
- pageLoadTimeout: '30000',
29
- scriptTimeout: '30000',
30
28
  parallelizationMode: 'testcase',
31
29
  },
32
- browsers: [
33
- {
34
- id: 'chrome-desktop',
35
- type: 'chrome',
36
- mobileEmulation: false,
37
- },
38
- ],
39
30
  androidConfig: {
40
31
  driverServer: 'http://127.0.0.1:4800',
41
32
  appPackage: '',
42
33
  appActivity: '',
43
- autoGrantPermissions: true,
44
34
  noReset: false,
45
35
  implicitWait: 10000,
46
36
  parallelizationMode: 'suite',
@@ -71,17 +61,11 @@ export const DEFAULT_CONFIG_DATA = {
71
61
  },
72
62
  ],
73
63
  },
74
- loadConfig: {
75
- virtualUsers: '10',
76
- duration: '1m',
77
- },
78
- loadStages: [],
79
- thresholds: [],
80
64
  executionConfig: {
81
65
  networkMonitoringEnabled: true,
82
66
  fastResponseTime: '200',
83
67
  normalResponseTime: '1000',
84
68
  monitoredDomains: [],
85
- environmentVariables: [],
69
+ environmentVariables: {},
86
70
  },
87
71
  };
@@ -261,7 +261,7 @@ describe('Platform TSConfigs & Type Isolation (docs/v2/cli/tsconfig-platform-iso
261
261
  expect(threw).toBe(true);
262
262
  expect(errorMessage).toContain("Cannot find name 'AuthLoginPage'");
263
263
  });
264
- it('E2E: compiles the full Nx monorepo template via tsc -b with 0 errors', () => {
264
+ it('E2E: compiles the full Nx monorepo template via tsc -b with 0 errors', async () => {
265
265
  let root = process.cwd();
266
266
  while (root && root !== path.dirname(root)) {
267
267
  if (fs.existsSync(path.join(root, 'pnpm-workspace.yaml')))
@@ -269,8 +269,12 @@ describe('Platform TSConfigs & Type Isolation (docs/v2/cli/tsconfig-platform-iso
269
269
  root = path.dirname(root);
270
270
  }
271
271
  const nxTemplateDir = path.join(root, 'cli', 'templates', 'nx');
272
- // Generate latest ambient types for the nx template
272
+ // Generate latest ambient types for the nx template, including env.d.ts (a separate async
273
+ // step — see TypeGenerator.syncEnvDeclaration — since spectra.config.ts's
274
+ // executionConfig.environmentVariables is what the template's EnvironmentConfig suite
275
+ // exercises via the typed Env global).
273
276
  TypeGenerator.generateAll(nxTemplateDir);
277
+ await TypeGenerator.syncEnvDeclaration(nxTemplateDir);
274
278
  expect(() => {
275
279
  execSync(`npx tsc -b ${nxTemplateDir}`, { stdio: 'pipe' });
276
280
  }).not.toThrow();
@@ -52,7 +52,7 @@ describe('TypeGenerator Engine (docs/v2/cli/ambient-types-generator.md)', () =>
52
52
  fs.writeFileSync(path.join(poDir, 'web.ts'), 'export default class LoginPage {\n static username = "#user";\n static async login() {}\n}');
53
53
  const stepDir = path.join(tmpDir, 'support', 'steps', 'loginAsAdmin');
54
54
  fs.mkdirSync(stepDir, { recursive: true });
55
- fs.writeFileSync(path.join(stepDir, 'web.step.ts'), 'export default async function loginAsAdmin(role?: string) {}');
55
+ fs.writeFileSync(path.join(stepDir, 'web.step.ts'), 'export default async function (role?: string) {}');
56
56
  const fixDir = path.join(tmpDir, 'fixtures');
57
57
  fs.mkdirSync(fixDir, { recursive: true });
58
58
  fs.writeFileSync(path.join(fixDir, 'users.json'), JSON.stringify({ admin: { id: 101, email: 'admin@test.local' } }));
@@ -383,4 +383,42 @@ async function verifyZeroImport() {
383
383
  expect(fs.existsSync(path.join(tmpDir, '.testspectra', 'types', 'web.d.ts'))).toBe(false);
384
384
  expect(fs.existsSync(path.join(tmpDir, '.testspectra', 'types', 'common.d.ts'))).toBe(false);
385
385
  });
386
+ it('nx monorepo: does NOT treat feature library as shared library and discovers nested e2e subproject', () => {
387
+ // 1. Shared library with testspectra:shared
388
+ const sharedDir = path.join(tmpDir, 'shared', 'testing');
389
+ fs.mkdirSync(path.join(sharedDir, 'page-objects', 'SharedNav'), { recursive: true });
390
+ fs.writeFileSync(path.join(sharedDir, 'project.json'), JSON.stringify({ name: 'shared-testing', projectType: 'library', tags: ['testspectra:shared'] }));
391
+ fs.writeFileSync(path.join(sharedDir, 'page-objects', 'SharedNav', 'common.ts'), 'export default class SharedNav {}');
392
+ // 2. Nx Feature library (projectType: "library", standard Nx tags, NO testspectra tags)
393
+ const featureLibDir = path.join(tmpDir, 'packages', 'features', 'auth');
394
+ fs.mkdirSync(featureLibDir, { recursive: true });
395
+ fs.writeFileSync(path.join(featureLibDir, 'project.json'), JSON.stringify({
396
+ name: '@tagsamurai/feature-auth',
397
+ projectType: 'library',
398
+ sourceRoot: 'packages/features/auth',
399
+ targets: {},
400
+ tags: ['type:feature', 'scope:feature-auth'],
401
+ }));
402
+ // 3. Nested E2E subproject inside feature library
403
+ const featureE2eDir = path.join(featureLibDir, 'e2e');
404
+ fs.mkdirSync(path.join(featureE2eDir, 'specs', 'AuthSuite', 'TC-001'), { recursive: true });
405
+ fs.writeFileSync(path.join(featureE2eDir, 'project.json'), JSON.stringify({
406
+ name: 'feature-auth-e2e',
407
+ projectType: 'application',
408
+ tags: ['testspectra:e2e', 'testspectra:scope:feature-auth'],
409
+ }));
410
+ fs.writeFileSync(path.join(featureE2eDir, 'specs', 'AuthSuite', 'TC-001', 'web.test.ts'), 'it("auth test", async () => {});');
411
+ const scopes = TypeGenerator.getEntityScopes(tmpDir);
412
+ expect(scopes).toHaveLength(2);
413
+ const sharedScope = scopes.find((s) => s.isShared);
414
+ expect(sharedScope).toBeDefined();
415
+ expect(sharedScope?.name).toBe('shared');
416
+ expect(sharedScope?.dir).toBe(path.resolve(sharedDir));
417
+ const featureScope = scopes.find((s) => !s.isShared);
418
+ expect(featureScope).toBeDefined();
419
+ expect(featureScope?.name).toBe('feature-auth');
420
+ expect(featureScope?.dir).toBe(path.resolve(featureE2eDir));
421
+ // Verify packages/features/auth is NOT in scopes
422
+ expect(scopes.some((s) => s.dir === path.resolve(featureLibDir))).toBe(false);
423
+ });
386
424
  });
@@ -31,7 +31,7 @@ export class TsConfigGenerator {
31
31
  static getStemExcludes(prefix, stems) {
32
32
  const excludes = [];
33
33
  for (const stem of stems) {
34
- excludes.push(`${prefix}/**/page-objects/**/${stem}.ts`, `${prefix}/**/pageobjects/**/${stem}.ts`, `${prefix}/**/support/**/${stem}.*`, `${prefix}/**/global-hooks/**/${stem}.*`, `${prefix}/**/specs/**/hooks/**/${stem}.*`, `${prefix}/**/specs/**/${stem}.test.ts`, `${prefix}/**/${stem}.ts`, `${prefix}/**/${stem}.*`, `${prefix}/**/${stem}.*.ts`, `${prefix}/**/*.${stem}.ts`, `${prefix}/**/*.${stem}.*`, `${prefix}/**/*.${stem}.*.ts`);
34
+ excludes.push(`${prefix}/**/page-objects/**/${stem}.ts`, `${prefix}/**/support/**/${stem}.*`, `${prefix}/**/global-hooks/**/${stem}.*`, `${prefix}/**/specs/**/hooks/**/${stem}.*`, `${prefix}/**/specs/**/${stem}.test.ts`, `${prefix}/**/${stem}.ts`, `${prefix}/**/${stem}.*`, `${prefix}/**/${stem}.*.ts`, `${prefix}/**/*.${stem}.ts`, `${prefix}/**/*.${stem}.*`, `${prefix}/**/*.${stem}.*.ts`);
35
35
  }
36
36
  return excludes;
37
37
  }
@@ -41,21 +41,28 @@ export class TsConfigGenerator {
41
41
  target: 'ES2022',
42
42
  module: 'NodeNext',
43
43
  moduleResolution: 'NodeNext',
44
+ jsx: 'react-jsx',
44
45
  composite: true,
45
46
  noEmit: true,
46
47
  skipLibCheck: true,
47
48
  strict: true,
48
- types: ['node', '@wdio/globals/types', '@wdio/mocha-framework'],
49
+ types: ['node'],
49
50
  },
50
51
  include: [
51
52
  '../types/web.d.ts',
52
53
  '../types/fixtures.d.ts',
53
54
  '../../**/specs/**/*.ts',
55
+ '../../**/specs/**/*.tsx',
54
56
  '../../**/page-objects/**/*.ts',
55
- '../../**/pageobjects/**/*.ts',
57
+ '../../**/page-objects/**/*.tsx',
56
58
  '../../**/support/**/*.ts',
59
+ '../../**/support/**/*.tsx',
57
60
  '../../**/global-hooks/**/*.ts',
61
+ '../../**/global-hooks/**/*.tsx',
58
62
  '../../**/fixtures/**/*.ts',
63
+ '../../**/fixtures/**/*.json',
64
+ '../../**/src/**/*.ts',
65
+ '../../**/src/**/*.tsx',
59
66
  '../../spectra.config.ts',
60
67
  ],
61
68
  exclude: [
@@ -74,21 +81,28 @@ export class TsConfigGenerator {
74
81
  target: 'ES2022',
75
82
  module: 'NodeNext',
76
83
  moduleResolution: 'NodeNext',
84
+ jsx: 'react-jsx',
77
85
  composite: true,
78
86
  noEmit: true,
79
87
  skipLibCheck: true,
80
88
  strict: true,
81
- types: ['node', '@wdio/globals/types', '@wdio/mocha-framework'],
89
+ types: ['node'],
82
90
  },
83
91
  include: [
84
92
  '../types/mobile.d.ts',
85
93
  '../types/fixtures.d.ts',
86
94
  '../../**/specs/**/*.ts',
95
+ '../../**/specs/**/*.tsx',
87
96
  '../../**/page-objects/**/*.ts',
88
- '../../**/pageobjects/**/*.ts',
97
+ '../../**/page-objects/**/*.tsx',
89
98
  '../../**/support/**/*.ts',
99
+ '../../**/support/**/*.tsx',
90
100
  '../../**/global-hooks/**/*.ts',
101
+ '../../**/global-hooks/**/*.tsx',
91
102
  '../../**/fixtures/**/*.ts',
103
+ '../../**/fixtures/**/*.json',
104
+ '../../**/src/**/*.ts',
105
+ '../../**/src/**/*.tsx',
92
106
  '../../spectra.config.ts',
93
107
  ],
94
108
  exclude: [
@@ -107,21 +121,28 @@ export class TsConfigGenerator {
107
121
  target: 'ES2022',
108
122
  module: 'NodeNext',
109
123
  moduleResolution: 'NodeNext',
124
+ jsx: 'react-jsx',
110
125
  composite: true,
111
126
  noEmit: true,
112
127
  skipLibCheck: true,
113
128
  strict: true,
114
- types: ['node', '@wdio/globals/types', '@wdio/mocha-framework'],
129
+ types: ['node'],
115
130
  },
116
131
  include: [
117
132
  '../types/android.d.ts',
118
133
  '../types/fixtures.d.ts',
119
134
  '../../**/specs/**/*.ts',
135
+ '../../**/specs/**/*.tsx',
120
136
  '../../**/page-objects/**/*.ts',
121
- '../../**/pageobjects/**/*.ts',
137
+ '../../**/page-objects/**/*.tsx',
122
138
  '../../**/support/**/*.ts',
139
+ '../../**/support/**/*.tsx',
123
140
  '../../**/global-hooks/**/*.ts',
141
+ '../../**/global-hooks/**/*.tsx',
124
142
  '../../**/fixtures/**/*.ts',
143
+ '../../**/fixtures/**/*.json',
144
+ '../../**/src/**/*.ts',
145
+ '../../**/src/**/*.tsx',
125
146
  '../../spectra.config.ts',
126
147
  ],
127
148
  exclude: [
@@ -140,21 +161,28 @@ export class TsConfigGenerator {
140
161
  target: 'ES2022',
141
162
  module: 'NodeNext',
142
163
  moduleResolution: 'NodeNext',
164
+ jsx: 'react-jsx',
143
165
  composite: true,
144
166
  noEmit: true,
145
167
  skipLibCheck: true,
146
168
  strict: true,
147
- types: ['node', '@wdio/globals/types', '@wdio/mocha-framework'],
169
+ types: ['node'],
148
170
  },
149
171
  include: [
150
172
  '../types/ios.d.ts',
151
173
  '../types/fixtures.d.ts',
152
174
  '../../**/specs/**/*.ts',
175
+ '../../**/specs/**/*.tsx',
153
176
  '../../**/page-objects/**/*.ts',
154
- '../../**/pageobjects/**/*.ts',
177
+ '../../**/page-objects/**/*.tsx',
155
178
  '../../**/support/**/*.ts',
179
+ '../../**/support/**/*.tsx',
156
180
  '../../**/global-hooks/**/*.ts',
181
+ '../../**/global-hooks/**/*.tsx',
157
182
  '../../**/fixtures/**/*.ts',
183
+ '../../**/fixtures/**/*.json',
184
+ '../../**/src/**/*.ts',
185
+ '../../**/src/**/*.tsx',
158
186
  '../../spectra.config.ts',
159
187
  ],
160
188
  exclude: [
@@ -173,21 +201,23 @@ export class TsConfigGenerator {
173
201
  target: 'ES2022',
174
202
  module: 'NodeNext',
175
203
  moduleResolution: 'NodeNext',
204
+ jsx: 'react-jsx',
176
205
  composite: true,
177
206
  noEmit: true,
178
207
  skipLibCheck: true,
179
208
  strict: true,
180
- types: ['node', '@wdio/globals/types', '@wdio/mocha-framework'],
209
+ types: ['node'],
181
210
  },
182
211
  include: [
183
212
  '../types/common.d.ts',
184
213
  '../types/fixtures.d.ts',
185
214
  '../../**/page-objects/**/common.ts',
186
- '../../**/pageobjects/**/common.ts',
215
+ '../../**/page-objects/**/common.tsx',
187
216
  '../../**/support/**/common.*',
188
217
  '../../**/global-hooks/**/common.*',
189
218
  '../../**/specs/**/hooks/**/common.*',
190
219
  '../../**/specs/**/common.test.ts',
220
+ '../../**/specs/**/common.test.tsx',
191
221
  '../../spectra.config.ts',
192
222
  ],
193
223
  exclude: [
@@ -215,7 +245,7 @@ export class TsConfigGenerator {
215
245
  const relCache = path.relative(subConfigDir, path.join(options.cwd, '.testspectra', 'cache')).replace(/\\/g, '/');
216
246
  const platformDts = `${relTypesDir}/${platform}.d.ts`;
217
247
  const fixturesDts = `${relTypesDir}/fixtures.d.ts`;
218
- const include = [platformDts, fixturesDts, `${relScope}/**/*.ts`, relSpectraConfig];
248
+ const include = [platformDts, fixturesDts, `${relScope}/**/*.ts`, `${relScope}/**/*.tsx`, relSpectraConfig];
219
249
  const baseExcludes = [relNodeModules, relDist, relReports, relRuns, relCache];
220
250
  const stemMap = {
221
251
  web: ['android', 'ios', 'mobile'],
@@ -234,7 +264,7 @@ export class TsConfigGenerator {
234
264
  noEmit: true,
235
265
  skipLibCheck: true,
236
266
  strict: true,
237
- types: ['node', '@wdio/globals/types', '@wdio/mocha-framework'],
267
+ types: ['node'],
238
268
  },
239
269
  include,
240
270
  exclude: [...baseExcludes, ...platformExcludes],
@@ -269,9 +299,7 @@ export class TsConfigGenerator {
269
299
  const sharedScope = scopes.find((s) => s.isShared);
270
300
  const featureScopes = scopes.filter((s) => !s.isShared);
271
301
  const hasScopes = Boolean(sharedScope || featureScopes.length > 0);
272
- const hasRootEntities = fs.existsSync(path.join(cwd, 'specs')) ||
273
- fs.existsSync(path.join(cwd, 'page-objects')) ||
274
- fs.existsSync(path.join(cwd, 'pageobjects'));
302
+ const hasRootEntities = fs.existsSync(path.join(cwd, 'specs')) || fs.existsSync(path.join(cwd, 'page-objects'));
275
303
  if (!hasScopes || hasRootEntities) {
276
304
  for (const filename of Object.keys(platformConfigs)) {
277
305
  references.push({ path: `./tsconfig/${filename}` });