@testspectra/cli 1.1.6 → 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
@@ -12,8 +12,8 @@
12
12
  "postinstall": "spectra sync-types"
13
13
  },
14
14
  "devDependencies": {
15
- "@testspectra/cli": "link:../..",
16
- "@testspectra/matchers": "link:../../../tools/matchers",
15
+ "@testspectra/cli": "^1.1.8-rc.1",
16
+ "@testspectra/matchers": "^1.1.8-rc.1",
17
17
  "@types/node": "^20.14.0",
18
18
  "@wdio/cli": "^9.2.8",
19
19
  "@wdio/local-runner": "^9.2.8",
@@ -25,4 +25,4 @@
25
25
  "typescript": "^5.4.5",
26
26
  "webdriverio": "^9.2.8"
27
27
  }
28
- }
28
+ }
@@ -1,3 +1,27 @@
1
- it("should handle GET API state on Mobile", async () => {
1
+ it("Mock and assert GET API requests using browser.intercept", async () => {
2
+ // Navigate to API Fetch section
2
3
  await MatchersPage.open("api-fetch");
4
+
5
+ // Setup API interception with Fixture data
6
+ const mock = await Spectra.intercept(
7
+ "/api/posts",
8
+ "GET",
9
+ Fixture.apiData.mockPosts
10
+ );
11
+
12
+ // Trigger fetch button in mobile demo app
13
+ await MatchersPage.fetchApiButton.click();
14
+
15
+ // Assert status and mocked elements
16
+ await MatchersPage.fetchStatusBadge.shouldHaveText("200 OK");
17
+ await MatchersPage.fetchedItems.shouldHaveLength(Fixture.apiData.mockPosts.length);
18
+ await MatchersPage.fetchedItems.first().shouldContainText(Fixture.apiData.mockPosts[0].title);
19
+
20
+ // Dynamically update fixture response
21
+ await mock.respondWith([
22
+ { id: 99, title: "Dynamic Updated Mock Title", body: "Updated on the fly" }
23
+ ]);
24
+ await MatchersPage.fetchApiButton.click();
25
+ await MatchersPage.fetchedItems.shouldHaveLength(1);
26
+ await MatchersPage.fetchedItems.first().shouldContainText("Dynamic Updated Mock Title");
3
27
  });
@@ -1,9 +1,9 @@
1
- it("should mock GET API response using browser.intercept and verify rendered items", async () => {
1
+ it("Mock and assert GET API requests using browser.intercept", async () => {
2
2
  // Navigate to API Fetch section
3
3
  await MatchersPage.open("api-fetch");
4
4
 
5
5
  // Setup API interception with Fixture data
6
- const mock = await browser.intercept(
6
+ const mock = await Spectra.intercept(
7
7
  "/api/posts",
8
8
  "GET",
9
9
  Fixture.apiData.mockPosts
@@ -1,3 +1,24 @@
1
- it("should handle POST API state on Mobile", async () => {
1
+ it("Mock and assert POST API requests using browser.intercept", async () => {
2
+ // Navigate to API POST section
2
3
  await MatchersPage.open("api-post");
4
+
5
+ // Setup POST API interception with status 201
6
+ await Spectra.intercept(
7
+ "/api/posts",
8
+ "POST",
9
+ Fixture.apiData.mockPostResponse,
10
+ { statusCode: 201 }
11
+ );
12
+
13
+ // Fill in form fields from Fixture
14
+ await MatchersPage.postTitleInput.type(Fixture.apiData.mockNewPost.title);
15
+ await MatchersPage.postBodyInput.type(Fixture.apiData.mockNewPost.body);
16
+
17
+ // Submit POST form
18
+ await MatchersPage.submitPostButton.click();
19
+
20
+ // Assert response elements and status
21
+ await MatchersPage.postStatusBadge.shouldHaveText("201 Created");
22
+ await MatchersPage.postSuccessBanner.shouldBeVisible();
23
+ await MatchersPage.postResponseJson.shouldContainText(Fixture.apiData.mockNewPost.title);
3
24
  });
@@ -1,9 +1,9 @@
1
- it("should mock POST API submission using browser.intercept and verify created response", async () => {
1
+ it("Mock and assert POST API requests using browser.intercept", async () => {
2
2
  // Navigate to API POST section
3
3
  await MatchersPage.open("api-post");
4
4
 
5
5
  // Setup POST API interception with status 201
6
- await browser.intercept(
6
+ await Spectra.intercept(
7
7
  "/api/posts",
8
8
  "POST",
9
9
  Fixture.apiData.mockPostResponse,
@@ -1,3 +1,3 @@
1
- it("should verify title on Mobile", async () => {
1
+ it("Verify page title and sidebar navigation links", async () => {
2
2
  await MatchersPage.open();
3
3
  });
@@ -1,4 +1,4 @@
1
- it("should verify browser page title, URL, diagnostics, and navigation on Web", async () => {
1
+ it("Verify page title and sidebar navigation links", async () => {
2
2
  await MatchersPage.open();
3
3
 
4
4
  // Browser title assertions
@@ -1,3 +1,3 @@
1
- it("should verify text on Mobile", async () => {
1
+ it("Verify exact text, substring text, and input values", async () => {
2
2
  await MatchersPage.open("text");
3
3
  });
@@ -1,4 +1,4 @@
1
- it("should verify text and value matchers on Web", async () => {
1
+ it("Verify exact text, substring text, and input values", async () => {
2
2
  await MatchersPage.open("text");
3
3
 
4
4
  // Text assertions (positive and negative)
@@ -1,3 +1,3 @@
1
- it("should verify collection length on Mobile", async () => {
1
+ it("Verify collection lengths, counts, and empty lists", async () => {
2
2
  await MatchersPage.open("length");
3
3
  });
@@ -1,4 +1,4 @@
1
- it("should verify collection lengths and empty lists on Web", async () => {
1
+ it("Verify collection lengths, counts, and empty lists", async () => {
2
2
  await MatchersPage.open("length");
3
3
 
4
4
  // Receiver assertion methods
@@ -1,3 +1,3 @@
1
- it("should verify visibility on Mobile", async () => {
1
+ it("Verify element visibility and existence matchers", async () => {
2
2
  await MatchersPage.open("visibility");
3
3
  });
@@ -1,4 +1,4 @@
1
- it("should verify visibility and DOM existence matchers on Web", async () => {
1
+ it("Verify element visibility and existence matchers", async () => {
2
2
  await MatchersPage.open("visibility");
3
3
 
4
4
  // Element visibility (positive and negative)
@@ -1,3 +1,3 @@
1
- it("should verify button state on Mobile", async () => {
1
+ it("Verify button state, checkbox, radio and attributes", async () => {
2
2
  await MatchersPage.open("state");
3
3
  });
@@ -1,4 +1,4 @@
1
- it("should verify interactivity states, classes, attributes, and CSS styling on Web", async () => {
1
+ it("Verify button state, checkbox, radio and attributes", async () => {
2
2
  await MatchersPage.open("state");
3
3
 
4
4
  // Interactivity & state assertions
@@ -0,0 +1,5 @@
1
+ it("Verify a custom environmentVariables entry is readable via Spectra.env", async () => {
2
+ if (Spectra.env.DEMO_API_MODE !== "sandbox") {
3
+ throw new Error(`Expected Spectra.env.DEMO_API_MODE to be "sandbox", got "${Spectra.env.DEMO_API_MODE}"`);
4
+ }
5
+ });
@@ -0,0 +1,16 @@
1
+ ---
2
+ id: TC-0019-read-custom-environment-variable
3
+ title: Verify a custom environmentVariables entry is readable via Spectra.env
4
+ priority: Medium
5
+ caseType: Positive
6
+ status: ready-for-automation
7
+ coverage:
8
+ web: automated
9
+ mobile: automated
10
+ ---
11
+
12
+ # Verify a custom environmentVariables entry is readable via Spectra.env
13
+
14
+ ## Test Steps
15
+ 1. Read the DEMO_API_MODE variable via the typed Spectra.env
16
+ 2. Assert it matches the value configured in spectra.config.ts's executionConfig.environmentVariables
@@ -0,0 +1,9 @@
1
+ ---
2
+ id: suite-environment-config
3
+ name: EnvironmentConfig
4
+ description: Reading custom executionConfig.environmentVariables values via Spectra.env
5
+ executionOrder: 2.3
6
+ parallel: true
7
+ ---
8
+
9
+ # Suite: EnvironmentConfig
@@ -1,3 +1,3 @@
1
- it("should verify playground states (Mobile)", async () => {
1
+ it("Verify playground form inputs and default states", async () => {
2
2
  await Step.verifyPlaygroundState();
3
3
  });
@@ -1,4 +1,4 @@
1
- it("should verify live playground form inputs and default states (Web)", async () => {
1
+ it("Verify playground form inputs and default states", async () => {
2
2
  await Step.verifyPlaygroundState();
3
3
  await PlaygroundPage.emailInput.shouldHaveValue(Fixture.playgroundData.defaultEmail);
4
4
  await PlaygroundPage.tokenInput.shouldContainValue("JWT_");
@@ -1,3 +1,3 @@
1
- it("should fill credentials (Mobile)", async () => {
1
+ it("Verify typing credentials and updating playground inputs", async () => {
2
2
  await PlaygroundPage.open();
3
3
  });
@@ -1,4 +1,4 @@
1
- it("should update input values and verify updated state (Web)", async () => {
1
+ it("Verify typing credentials and updating playground inputs", async () => {
2
2
  await PlaygroundPage.open();
3
3
  await PlaygroundPage.fillCredentials("qa.expert@testspectra.dev", "JWT_custom_session_token");
4
4
  await PlaygroundPage.emailInput.shouldHaveValue("qa.expert@testspectra.dev");
@@ -1,4 +1,4 @@
1
- export class MatchersPage {
1
+ class MatchersPage {
2
2
  get visibleElement() { return Spectra.get("~visible_element"); }
3
3
  get hiddenElement() { return Spectra.get("~hidden_element"); }
4
4
  get existingElement() { return Spectra.get("~existing_element"); }
@@ -1,36 +1,90 @@
1
- export class MatchersPage {
2
- get visibleElement() { return Spectra.get("#demo-visible-el"); }
3
- get hiddenElement() { return Spectra.get("#demo-hidden-el"); }
4
- get existingElement() { return Spectra.get("#demo-existing-el"); }
5
- get submitButton() { return Spectra.get("#demo-submit-btn"); }
6
- get disabledButton() { return Spectra.get("#demo-disabled-btn"); }
7
- get checkbox() { return Spectra.get("#demo-checkbox"); }
8
- get radio() { return Spectra.get("#demo-radio"); }
9
- get emailInput() { return Spectra.get("#demo-email-input"); }
10
- get tokenInput() { return Spectra.get("#demo-token-input"); }
11
- get exactText() { return Spectra.get("#demo-exact-text"); }
12
- get partialText() { return Spectra.get("#demo-partial-text"); }
13
- get activeTab() { return Spectra.get("#demo-active-tab"); }
14
- get navLink() { return Spectra.get("#demo-nav-link"); }
15
- get styledElement() { return Spectra.get("#demo-styled-el"); }
16
- get focusInput() { return Spectra.get("#demo-focus-input"); }
17
- get productCards() { return Spectra.getAll(".demo-product-card"); }
18
- get emptyList() { return Spectra.getAll("#demo-empty-list > *"); }
1
+ class MatchersPage {
2
+ get visibleElement() {
3
+ return Spectra.get("#demo-visible-el");
4
+ }
5
+ get hiddenElement() {
6
+ return Spectra.get("#demo-hidden-el");
7
+ }
8
+ get existingElement() {
9
+ return Spectra.get("#demo-existing-el");
10
+ }
11
+ get submitButton() {
12
+ return Spectra.get("#demo-submit-btn");
13
+ }
14
+ get disabledButton() {
15
+ return Spectra.get("#demo-disabled-btn");
16
+ }
17
+ get checkbox() {
18
+ return Spectra.get("#demo-checkbox");
19
+ }
20
+ get radio() {
21
+ return Spectra.get("#demo-radio");
22
+ }
23
+ get emailInput() {
24
+ return Spectra.get("#demo-email-input");
25
+ }
26
+ get tokenInput() {
27
+ return Spectra.get("#demo-token-input");
28
+ }
29
+ get exactText() {
30
+ return Spectra.get("#demo-exact-text");
31
+ }
32
+ get partialText() {
33
+ return Spectra.get("#demo-partial-text");
34
+ }
35
+ get activeTab() {
36
+ return Spectra.get("#demo-active-tab");
37
+ }
38
+ get navLink() {
39
+ return Spectra.get("#demo-nav-link");
40
+ }
41
+ get styledElement() {
42
+ return Spectra.get("#demo-styled-el");
43
+ }
44
+ get focusInput() {
45
+ return Spectra.get("#demo-focus-input");
46
+ }
47
+ get productCards() {
48
+ return Spectra.getAll(".demo-product-card");
49
+ }
50
+ get emptyList() {
51
+ return Spectra.getAll("#demo-empty-list > *");
52
+ }
19
53
 
20
54
  // API Interception & Mocking elements
21
- get fetchApiButton() { return Spectra.get("#fetch-api-btn"); }
22
- get fetchStatusBadge() { return Spectra.get("#fetch-status-badge"); }
23
- get fetchedItems() { return Spectra.getAll(".api-fetched-item"); }
24
- get fetchLoadingIndicator() { return Spectra.get("#fetch-loading-indicator"); }
25
- get postTitleInput() { return Spectra.get("#post-input-title"); }
26
- get postBodyInput() { return Spectra.get("#post-input-body"); }
27
- get submitPostButton() { return Spectra.get("#submit-post-btn"); }
28
- get postStatusBadge() { return Spectra.get("#post-status-badge"); }
29
- get postSuccessBanner() { return Spectra.get("#post-success-banner"); }
30
- get postResponseJson() { return Spectra.get("#post-response-json"); }
55
+ get fetchApiButton() {
56
+ return Spectra.get("#fetch-api-btn");
57
+ }
58
+ get fetchStatusBadge() {
59
+ return Spectra.get("#fetch-status-badge");
60
+ }
61
+ get fetchedItems() {
62
+ return Spectra.getAll(".api-fetched-item");
63
+ }
64
+ get fetchLoadingIndicator() {
65
+ return Spectra.get("#fetch-loading-indicator");
66
+ }
67
+ get postTitleInput() {
68
+ return Spectra.get("#post-input-title");
69
+ }
70
+ get postBodyInput() {
71
+ return Spectra.get("#post-input-body");
72
+ }
73
+ get submitPostButton() {
74
+ return Spectra.get("#submit-post-btn");
75
+ }
76
+ get postStatusBadge() {
77
+ return Spectra.get("#post-status-badge");
78
+ }
79
+ get postSuccessBanner() {
80
+ return Spectra.get("#post-success-banner");
81
+ }
82
+ get postResponseJson() {
83
+ return Spectra.get("#post-response-json");
84
+ }
31
85
 
32
86
  async open(section = "") {
33
- await browser.url("/" + (section ? "#" + section : ""));
87
+ await Spectra.navigate("/" + (section ? "#" + section : ""));
34
88
  }
35
89
  }
36
90
 
@@ -1,4 +1,4 @@
1
- export class NavigationPage {
1
+ class NavigationPage {
2
2
  get sidebarLinks() { return Spectra.getAll("~sidebar_link"); }
3
3
  }
4
4
 
@@ -1,4 +1,4 @@
1
- export class NavigationPage {
1
+ class NavigationPage {
2
2
  get sidebarLinks() { return Spectra.getAll("aside a"); }
3
3
  get overviewLink() { return Spectra.get("aside a[href='#overview']"); }
4
4
  get visibilityLink() { return Spectra.get("aside a[href='#visibility']"); }
@@ -1,4 +1,4 @@
1
- export class PlaygroundPage {
1
+ class PlaygroundPage {
2
2
  get visibleElement() { return Spectra.get("~visible_element"); }
3
3
  get hiddenElement() { return Spectra.get("~hidden_element"); }
4
4
  get existingElement() { return Spectra.get("~existing_element"); }
@@ -1,4 +1,4 @@
1
- export class PlaygroundPage {
1
+ class PlaygroundPage {
2
2
  get visibleElement() { return Spectra.get("#demo-visible-el-pg"); }
3
3
  get hiddenElement() { return Spectra.get("#demo-hidden-el-pg"); }
4
4
  get existingElement() { return Spectra.get("#demo-existing-el-pg"); }
@@ -19,7 +19,7 @@ export class PlaygroundPage {
19
19
  get emptyList() { return Spectra.getAll("#demo-empty-list-pg > *"); }
20
20
 
21
21
  async open() {
22
- await browser.url("/#playground");
22
+ await Spectra.navigate("/#playground");
23
23
  }
24
24
 
25
25
  async fillCredentials(email = Fixture.playgroundData.defaultEmail, token = Fixture.playgroundData.defaultToken) {
@@ -1,4 +1,4 @@
1
- export default async function fillCredentials(this: any, email: string, token: string) {
1
+ export default async function (this: any, email: string, token: string) {
2
2
  await this.get("~email_input").type(email);
3
3
  await this.get("~token_input").type(token);
4
4
  }
@@ -1,4 +1,4 @@
1
- export default async function fillCredentials(this: any, email: string, token: string) {
1
+ export default async function (this: any, email: string, token: string) {
2
2
  await this.get("#demo-email-input-pg").type(email);
3
3
  await this.get("#demo-token-input-pg").type(token);
4
4
  }
@@ -1,3 +1,3 @@
1
- export default async function togglePlaygroundStates() {
1
+ export default async function () {
2
2
  await PlaygroundPage.open();
3
3
  }
@@ -1,4 +1,4 @@
1
- export default async function togglePlaygroundStates() {
1
+ export default async function () {
2
2
  await PlaygroundPage.open();
3
3
  await PlaygroundPage.hiddenElement.shouldBeVisible();
4
4
  await PlaygroundPage.existingElement.shouldExist();
@@ -1,4 +1,4 @@
1
- export default async function verifyPlaygroundState() {
1
+ export default async function () {
2
2
  await PlaygroundPage.open();
3
3
  await PlaygroundPage.visibleElement.shouldBeVisible();
4
4
  }
@@ -1,4 +1,4 @@
1
- export default async function verifyPlaygroundState() {
1
+ export default async function () {
2
2
  await PlaygroundPage.open();
3
3
  await PlaygroundPage.visibleElement.shouldBeVisible();
4
4
  await PlaygroundPage.enabledButton.shouldBeEnabled();
@@ -6,22 +6,12 @@ export default defineConfig({
6
6
  maxConcurrentSessions: "1",
7
7
  headless: true,
8
8
  implicitWait: "5000",
9
- pageLoadTimeout: "30000",
10
- scriptTimeout: "30000",
11
9
  parallelizationMode: "testcase",
12
10
  },
13
- browsers: [
14
- {
15
- id: "chrome-desktop",
16
- type: "chrome",
17
- mobileEmulation: false,
18
- },
19
- ],
20
11
  androidConfig: {
21
12
  driverServer: "tcp://127.0.0.1:8200",
22
13
  appPackage: "",
23
14
  appActivity: "",
24
- autoGrantPermissions: true,
25
15
  noReset: false,
26
16
  implicitWait: "10000",
27
17
  parallelizationMode: "suite",
@@ -52,17 +42,11 @@ export default defineConfig({
52
42
  },
53
43
  ],
54
44
  },
55
- loadConfig: {
56
- virtualUsers: "10",
57
- duration: "1m",
58
- },
59
- loadStages: [],
60
- thresholds: [],
61
45
  executionConfig: {
62
46
  networkMonitoringEnabled: true,
63
47
  fastResponseTime: "200",
64
48
  normalResponseTime: "1000",
65
49
  monitoredDomains: [],
66
- environmentVariables: [],
50
+ environmentVariables: { DEMO_API_MODE: "sandbox" },
67
51
  },
68
52
  });
@@ -0,0 +1,17 @@
1
+ # TestSpectra AI Instructions for Cursor
2
+
3
+ You are developing automated tests and React components with the TestSpectra testing framework.
4
+
5
+ ## Key Rules & Conventions
6
+ 1. **Zero-Import Standard**: Never add manual `import` statements for Page/Component Objects (`ButtonComponent`, `BadgeComponent`, `InputComponent`), Steps (`Step.*`), Fixtures (`Fixture.*`), or Actions (`Spectra.*`). All typings are provided globally and ambiently via `.testspectra/types/`.
7
+ 2. **Component Testing Pattern**: Mount React components using `await Spectra.mount(<Component />)` (real JSX and static component imports are allowed in `*.test.tsx` files, unlike zero-import `*.web.test.ts` E2E specs), then inspect and interact using `Spectra.get(...)` / `Spectra.getAll(...)` or Page/Component Objects. Each `Spectra.mount()` call replaces the previous mount automatically — no cleanup command needed. Run via `spectra test` (a separate suite from E2E's `spectra run`).
8
+ 3. **Platform Separation**:
9
+ - `web.test.ts` / `web.test.tsx` / `web.ts`: Web / Browser component implementations.
10
+ - `common.test.ts` / `common.ts`: Cross-platform shared implementations.
11
+ 4. **CamelCase Naming Convention**:
12
+ - Component Objects (`page-objects/ButtonComponent/`, `page-objects/BadgeComponent/`)
13
+ - Reusable Actions (`support/actions/fillInputField/`)
14
+ - Reusable Steps (`support/steps/verifyButtonState/`)
15
+ 5. **Spec-as-Code**:
16
+ - Suites are defined in `specs/<suite-name>/suite.md` with YAML frontmatter (`id`, `name`, `executionOrder`, `tags`).
17
+ - Test cases are defined in `specs/<suite-name>/<TC-ID-slug>/spec.md` with YAML frontmatter (`id`, `title`, `priority`, `coverage`).
@@ -0,0 +1,5 @@
1
+ {
2
+ "recommendations": [
3
+ "testspectra.testspectra-vscode"
4
+ ]
5
+ }
@@ -0,0 +1,14 @@
1
+ # TestSpectra React Component Testing Workspace
2
+
3
+ ## Commands
4
+ - `pnpm test` or `spectra test` — Run the component test suite (bundled Vitest browser mode via `@testspectra/react`)
5
+ - `pnpm run test:headed` — Run component tests with a visible browser window
6
+ - `pnpm run sync-types` — Scan workspace and regenerate ambient `.testspectra/types/`
7
+ - `pnpm run type-check` — Type check with `tsc -b`
8
+
9
+ ## Architecture Rules
10
+
11
+ 1. Zero-import standard for `Spectra.*`, `ButtonComponent`, `BadgeComponent`, `InputComponent`, `Step.*`, and `Fixture.*` — these stay ambient globals, auto-discovered from `page-objects/`, `support/steps/`, and `fixtures/`.
12
+ 2. Component testing uses `Spectra.mount(<Component />)` — real JSX, real static imports for the component under test are allowed and expected in `*.test.tsx` files (unlike `*.web.test.ts` E2E specs). `Spectra.mount()` always replaces whatever was previously mounted; no manual cleanup call is needed between tests.
13
+ 3. Component tests are a **separate test suite** from E2E (`spectra run`) — they live in `specs/<Suite>/<TC-ID>/web.test.tsx` alongside `spec.md`, run via `spectra test`, not `spectra run`. See `docs/v2/features/component-testing/react/`.
14
+ 4. Assertions use the same TestSpectra DSL as E2E (`Spectra.get().shouldBeVisible()`, `.shouldHaveText()`, etc.) — nothing new to learn beyond `Spectra.mount()`.
@@ -0,0 +1,69 @@
1
+ # TestSpectra React Component Testing Template
2
+
3
+ A high-performance, real-browser React component testing template powered by **TestSpectra**, **WebdriverIO Browser Runner**, and **Testing Library**.
4
+
5
+ ## 🚀 Features
6
+
7
+ - **Direct Component Mounting**: Mount TSX components directly in real Chromium/Blink engines using `@testing-library/react`.
8
+ - **Zero Mock Browser**: Real layout calculations, CSS rendering, focus states, and browser events without JSDOM/HappyDOM limitations.
9
+ - **Fast Vite HMR Core**: Instant test startup powered by Vite bundler inside the browser runner.
10
+ - **TestSpectra Matchers**: Comprehensive semantic assertions (`.shouldBeVisible()`, `.shouldExist()`, `expect(el).toHaveText()`).
11
+
12
+ ## 📁 Directory Structure
13
+
14
+ ```
15
+ .
16
+ ├── spectra.config.ts # TestSpectra centralized configuration
17
+ ├── wdio.conf.ts # WebdriverIO Browser Runner + Vite config
18
+ ├── tsconfig.json # TypeScript configuration for JSX & runner types
19
+ └── src/
20
+ ├── components/ # React components and tests
21
+ │ ├── Button/
22
+ │ │ ├── Button.tsx
23
+ │ │ └── Button.test.tsx
24
+ │ ├── Badge/
25
+ │ │ ├── Badge.tsx
26
+ │ │ └── Badge.test.tsx
27
+ │ └── Input/
28
+ │ ├── Input.tsx
29
+ │ └── Input.test.tsx
30
+ └── test-utils.tsx # Common testing helpers & providers
31
+ ```
32
+
33
+ ## 🛠️ Usage & Commands
34
+
35
+ ```bash
36
+ # Run all component tests
37
+ pnpm test
38
+
39
+ # Run component tests in headless mode
40
+ pnpm run test:headless
41
+
42
+ # Run tests in high-concurrency chunked worker mode
43
+ pnpm run test:chunked
44
+
45
+ # Type check
46
+ pnpm run type-check
47
+ ```
48
+
49
+ ## 📝 Writing Component Tests
50
+
51
+ ```tsx
52
+ import React from 'react';
53
+ import { render } from '@testing-library/react';
54
+ import { expect, $ } from '@wdio/globals';
55
+ import { Button } from './Button';
56
+
57
+ describe('Button Component', () => {
58
+ it('renders label and handles user clicks', async () => {
59
+ let clicked = false;
60
+ render(<Button label="Submit" onClick={() => (clicked = true)} />);
61
+
62
+ const button = await $('button=Submit');
63
+ await expect(button).toBeDisplayed();
64
+
65
+ await button.click();
66
+ expect(clicked).toBe(true);
67
+ });
68
+ });
69
+ ```
@@ -0,0 +1,12 @@
1
+ {
2
+ "user": {
3
+ "name": "Alex Mercer",
4
+ "role": "Developer",
5
+ "status": "active"
6
+ },
7
+ "labels": {
8
+ "save": "Save Changes",
9
+ "cancel": "Cancel",
10
+ "delete": "Delete Item"
11
+ }
12
+ }
@@ -0,0 +1,3 @@
1
+ export default async function () {
2
+ // Global after hook for web component testing suite
3
+ }
@@ -0,0 +1,3 @@
1
+ export default async function () {
2
+ // Global before hook for web component testing suite
3
+ }