@pixel-point/toolcraft 0.0.17 → 0.0.19

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 (503) hide show
  1. package/package.json +1 -1
  2. package/src/generate-demand-only-lifecycle.test.mjs +9 -1
  3. package/src/generate-performance-iteration-execution.test.mjs +3 -3
  4. package/src/generate-test-delivery-architecture-assertions.mjs +11 -73
  5. package/src/generate-test-demand-only-lifecycle.mjs +34 -36
  6. package/src/generate-test-dependency-sandbox.mjs +4 -1
  7. package/src/generate-test-doc-assertions.mjs +81 -89
  8. package/src/generate-test-doc-assertions.test.mjs +44 -1
  9. package/src/generate-test-doc-policy-assertions.mjs +92 -0
  10. package/src/generate-test-export-doc-assertions.mjs +53 -0
  11. package/src/generate-test-file-assertions.mjs +77 -83
  12. package/src/generate-test-integrity-assertions.mjs +5 -2
  13. package/src/generate-test-integrity-manifest-assertions.mjs +16 -5
  14. package/src/generate-test-integrity-ownership-assertions.mjs +36 -4
  15. package/src/generate-test-package-assertions.mjs +4 -0
  16. package/src/generate-test-product-fixture.mjs +1 -1
  17. package/src/generate-test-product-fixture.test.mjs +35 -38
  18. package/src/generate-test-product-iteration.mjs +0 -1
  19. package/src/generate-test-product-iteration.test.mjs +17 -1
  20. package/src/generate-test-runtime-boundary-assertions.mjs +178 -0
  21. package/src/generate-test-standalone-assertions.mjs +7 -13
  22. package/src/generate-test-standalone-delivery-stages.mjs +2 -86
  23. package/src/generate.test.mjs +4 -0
  24. package/src/generated-integrity-manifest.test.mjs +5 -2
  25. package/src/generated-source-policy.test.mjs +0 -4
  26. package/src/package-json.mjs +5 -0
  27. package/src/package-json.test.mjs +21 -0
  28. package/src/package-manager.mjs +2 -0
  29. package/src/package-manager.test.mjs +8 -0
  30. package/src/packaged-template-fallback-helpers.mjs +254 -0
  31. package/src/packaged-template-fallback.test.mjs +121 -46
  32. package/src/packaged-template-runtime-assertions.mjs +150 -0
  33. package/templates/runtime/contracts/component-contracts.choices.test.ts +64 -5
  34. package/templates/runtime/contracts/component-contracts.choices.ts +55 -5
  35. package/templates/runtime/contracts/component-contracts.inputs.test.ts +6 -6
  36. package/templates/runtime/contracts/component-contracts.inputs.ts +8 -7
  37. package/templates/runtime/contracts/component-contracts.media-custom.test.ts +8 -2
  38. package/templates/runtime/contracts/component-contracts.media-custom.ts +8 -2
  39. package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +22 -8
  40. package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +7 -1
  41. package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +3 -0
  42. package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +4 -1
  43. package/templates/runtime/contracts/component-contracts.runtime.ts +19 -12
  44. package/templates/runtime/contracts/component-contracts.test.ts +2 -0
  45. package/templates/runtime/contracts/component-contracts.visual.test.ts +20 -0
  46. package/templates/runtime/contracts/component-contracts.visual.ts +4 -0
  47. package/templates/runtime/contracts/decision-contracts.test.ts +35 -11
  48. package/templates/runtime/contracts/decision-contracts.ts +12 -12
  49. package/templates/runtime/contracts/performance-verification-policy.test.ts +12 -12
  50. package/templates/runtime/contracts/performance-verification-policy.ts +8 -8
  51. package/templates/runtime/export/artifact-download.ts +1 -0
  52. package/templates/runtime/export/artifact-frame-renderer.ts +2 -15
  53. package/templates/runtime/export/artifact-frame-state.ts +16 -0
  54. package/templates/runtime/export/artifact-scene-frame.test.ts +3 -3
  55. package/templates/runtime/export/artifact-scene-frame.ts +3 -3
  56. package/templates/runtime/export/export-background.ts +0 -19
  57. package/templates/runtime/export/export-error.ts +5 -0
  58. package/templates/runtime/export/export-renderer-coverage.ts +54 -0
  59. package/templates/runtime/export/export.test.ts +45 -42
  60. package/templates/runtime/export/image-artifact-export.ts +2 -2
  61. package/templates/runtime/export/index.ts +57 -16
  62. package/templates/runtime/export/product-export-renderer.test.ts +38 -4
  63. package/templates/runtime/export/product-export-renderer.ts +0 -41
  64. package/templates/runtime/export/product-svg-export-renderer.ts +21 -0
  65. package/templates/runtime/export/svg-artifact-export.test.ts +98 -0
  66. package/templates/runtime/export/svg-artifact-export.ts +120 -0
  67. package/templates/runtime/export/svg-document.test.ts +221 -0
  68. package/templates/runtime/export/svg-document.ts +400 -0
  69. package/templates/runtime/export/svg-policy.ts +47 -0
  70. package/templates/runtime/index.ts +3 -0
  71. package/templates/runtime/model-import/model-import-limits.ts +15 -4
  72. package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +21 -1
  73. package/templates/runtime/react/app-shell/settings-transfer.test.ts +21 -0
  74. package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +75 -1
  75. package/templates/runtime/react/app-shell/toolcraft-app.tsx +24 -9
  76. package/templates/runtime/react/canvas/canvas-shell-interactions.test.tsx +30 -0
  77. package/templates/runtime/react/canvas/canvas-shell-pinch-interactions.test.tsx +155 -0
  78. package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +77 -1
  79. package/templates/runtime/react/canvas/canvas-shell-test-utils.tsx +13 -1
  80. package/templates/runtime/react/canvas/canvas-shell.tsx +32 -6
  81. package/templates/runtime/react/canvas/canvas-viewport-geometry.ts +133 -0
  82. package/templates/runtime/react/canvas/product-scene-surface.test.tsx +195 -0
  83. package/templates/runtime/react/canvas/product-scene-surface.tsx +155 -0
  84. package/templates/runtime/react/canvas/runtime-scene-export.ts +1 -1
  85. package/templates/runtime/react/canvas/use-canvas-viewport-interactions.ts +285 -36
  86. package/templates/runtime/react/controls-panel/__tests__/control-conditions.test.ts +61 -0
  87. package/templates/runtime/react/controls-panel/__tests__/controls-panel.collection-actions.test.tsx +89 -0
  88. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-applicability-layout.test.tsx +134 -0
  89. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-layout.test.tsx +16 -1
  90. package/templates/runtime/react/controls-panel/__tests__/controls-panel.control-visibility.test.tsx +40 -19
  91. package/templates/runtime/react/controls-panel/__tests__/controls-panel.render-isolation.test.tsx +2 -0
  92. package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +40 -1
  93. package/templates/runtime/react/controls-panel/__tests__/controls-panel.setup-controls.test.tsx +3 -3
  94. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +59 -0
  95. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +67 -0
  96. package/templates/runtime/react/controls-panel/__tests__/controls-panel.vector-interaction.test.tsx +6 -6
  97. package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +4 -6
  98. package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +41 -6
  99. package/templates/runtime/react/controls-panel/conditions/control-conditions.ts +32 -119
  100. package/templates/runtime/react/controls-panel/layout/controls-panel-control-group.tsx +5 -2
  101. package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +41 -10
  102. package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +7 -4
  103. package/templates/runtime/react/controls-panel/renderers/controls-panel-action-renderer.tsx +2 -1
  104. package/templates/runtime/react/controls-panel/renderers/controls-panel-basic-renderers.tsx +2 -52
  105. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.test.tsx +63 -0
  106. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.tsx +138 -0
  107. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-items.tsx +104 -0
  108. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-renderer.tsx +115 -236
  109. package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.test.tsx +95 -0
  110. package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.tsx +82 -0
  111. package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.test.tsx +73 -1
  112. package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.tsx +50 -1
  113. package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.test.ts +1 -1
  114. package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.ts +2 -1
  115. package/templates/runtime/react/controls-panel/values/controls-panel-collection-values.ts +38 -6
  116. package/templates/runtime/react/controls-panel/values/controls-panel-color-values.ts +1 -9
  117. package/templates/runtime/react/controls-panel/values/controls-panel-spatial-values.ts +7 -2
  118. package/templates/runtime/react/controls-panel/values/controls-panel-value-labels.ts +1 -0
  119. package/templates/runtime/react/index.ts +4 -0
  120. package/templates/runtime/react/model-rendering/model-export.ts +1 -1
  121. package/templates/runtime/react/orientation-gizmo/orientation-gizmo-math.ts +9 -69
  122. package/templates/runtime/react/orientation-gizmo/orientation-gizmo-selection.ts +5 -5
  123. package/templates/runtime/react/orientation-gizmo/use-toolcraft-orientation-control-selection.ts +2 -2
  124. package/templates/runtime/scene/scene-bounds.test.ts +23 -0
  125. package/templates/runtime/scene/scene-bounds.ts +31 -17
  126. package/templates/runtime/schema/app-capabilities.test.ts +4 -0
  127. package/templates/runtime/schema/artifact-export-actions.test.ts +47 -0
  128. package/templates/runtime/schema/artifact-export-actions.ts +49 -0
  129. package/templates/runtime/schema/collection-item-controls.ts +29 -0
  130. package/templates/runtime/schema/control-applicability.test.ts +127 -0
  131. package/templates/runtime/schema/control-applicability.ts +433 -0
  132. package/templates/runtime/schema/control-schema-normalization.ts +177 -11
  133. package/templates/runtime/schema/controls-panel-actions.ts +2 -2
  134. package/templates/runtime/schema/controls-panel-section-layout.ts +14 -9
  135. package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +59 -0
  136. package/templates/runtime/schema/define-toolcraft.collection-actions-item-controls.test.ts +127 -0
  137. package/templates/runtime/schema/define-toolcraft.control-sections.test.ts +10 -4
  138. package/templates/runtime/schema/define-toolcraft.file-drop-item-controls.test.ts +98 -0
  139. package/templates/runtime/schema/define-toolcraft.file-drop-normalization.test.ts +27 -0
  140. package/templates/runtime/schema/define-toolcraft.segmented-control-fit.test.ts +20 -2
  141. package/templates/runtime/schema/define-toolcraft.setup-canvas.test.ts +16 -3
  142. package/templates/runtime/schema/define-toolcraft.source-collection.test.ts +79 -0
  143. package/templates/runtime/schema/runtime-setup-section.ts +24 -5
  144. package/templates/runtime/schema/types.ts +69 -13
  145. package/templates/runtime/state/canvas-background-state.ts +1 -16
  146. package/templates/runtime/state/canvas-state.ts +32 -20
  147. package/templates/runtime/state/control-value-codecs.test.ts +98 -0
  148. package/templates/runtime/state/control-value-codecs.ts +700 -0
  149. package/templates/runtime/state/control-value-normalization.test.ts +1 -1
  150. package/templates/runtime/state/control-value-normalization.ts +127 -135
  151. package/templates/runtime/state/controls-reducer.ts +26 -3
  152. package/templates/runtime/state/create-template-state.test.ts +30 -0
  153. package/templates/runtime/state/create-template-state.ts +52 -31
  154. package/templates/runtime/state/orientation-pose.ts +80 -0
  155. package/templates/runtime/state/persistence-control-values.test.ts +59 -0
  156. package/templates/runtime/state/reducer-controls.test.ts +45 -0
  157. package/templates/runtime/state/reducer-media-reset.test.ts +1 -1
  158. package/templates/runtime/state/reducer-timeline.test.ts +70 -0
  159. package/templates/runtime/state/timeline-reducer.ts +40 -2
  160. package/templates/runtime/testing/performance-schema-queries.ts +2 -2
  161. package/templates/starter/AGENTS.md +29 -28
  162. package/templates/starter/docs/toolcraft/README.md +6 -6
  163. package/templates/starter/docs/toolcraft/acceptance-testing.md +34 -48
  164. package/templates/starter/docs/toolcraft/agent-worklog.md +103 -1
  165. package/templates/starter/docs/toolcraft/assembly-workflow.md +16 -8
  166. package/templates/starter/docs/toolcraft/component-rules.md +9 -7
  167. package/templates/starter/docs/toolcraft/core/control-selection.md +9 -3
  168. package/templates/starter/docs/toolcraft/core/layout.md +13 -8
  169. package/templates/starter/docs/toolcraft/core/media-upload.md +3 -1
  170. package/templates/starter/docs/toolcraft/core/performance.md +8 -10
  171. package/templates/starter/docs/toolcraft/core/reference-study.md +80 -19
  172. package/templates/starter/docs/toolcraft/core/runtime-boundary.md +15 -3
  173. package/templates/starter/docs/toolcraft/core/setup-export.md +67 -11
  174. package/templates/starter/docs/toolcraft/custom-controls.md +6 -4
  175. package/templates/starter/docs/toolcraft/decision-contract.md +4 -2
  176. package/templates/starter/docs/toolcraft/performance.md +8 -10
  177. package/templates/starter/docs/toolcraft/renderer-technique.md +6 -2
  178. package/templates/starter/docs/toolcraft/schema-reference.md +24 -22
  179. package/templates/starter/docs/toolcraft/workflow.md +14 -14
  180. package/templates/starter/e2e/app-browser-control-applicability-requirements.spec.ts +163 -0
  181. package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +45 -2
  182. package/templates/starter/e2e/app-browser-motion-reference-requirements.spec.ts +411 -0
  183. package/templates/starter/e2e/app-browser-orientation-evidence.spec.ts +174 -21
  184. package/templates/starter/e2e/app-browser-proof-session.spec.ts +85 -0
  185. package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +63 -33
  186. package/templates/starter/e2e/app-browser-selection-scope-evidence.spec.ts +137 -0
  187. package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +61 -15
  188. package/templates/starter/e2e/{browser-conditional-output-evidence-helpers.ts → browser-background-output-evidence.ts} +0 -68
  189. package/templates/starter/e2e/browser-control-applicability-evidence.ts +114 -0
  190. package/templates/starter/e2e/browser-infinity-canvas-evidence.ts +20 -11
  191. package/templates/starter/e2e/browser-infinity-canvas-svg-evidence.ts +42 -0
  192. package/templates/starter/e2e/browser-layer-evidence-helpers.ts +15 -36
  193. package/templates/starter/e2e/browser-orientation-gizmo-evidence-helpers.ts +4 -0
  194. package/templates/starter/e2e/browser-orientation-gizmo-live-preconditions.ts +86 -0
  195. package/templates/starter/e2e/browser-product-raster-snapshot.ts +213 -0
  196. package/templates/starter/e2e/browser-proof-session.ts +43 -15
  197. package/templates/starter/e2e/browser-proof-surface-action.ts +79 -0
  198. package/templates/starter/e2e/browser-proof-types.ts +15 -0
  199. package/templates/starter/e2e/browser-runtime-applicability-requirements.ts +84 -0
  200. package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +9 -2
  201. package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +51 -32
  202. package/templates/starter/e2e/browser-selection-scope-evidence.ts +269 -0
  203. package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +122 -0
  204. package/templates/starter/e2e/browser-svg-export-evidence.spec.ts +79 -0
  205. package/templates/starter/e2e/browser-svg-export-evidence.ts +152 -0
  206. package/templates/starter/e2e/export-artifact-helpers.ts +70 -0
  207. package/templates/starter/e2e/product-observable-helpers.ts +8 -129
  208. package/templates/starter/e2e/svg-artifact-inspection.spec.ts +136 -0
  209. package/templates/starter/e2e/svg-artifact-inspection.ts +331 -0
  210. package/templates/starter/e2e/svg-download-test-fixtures.ts +34 -0
  211. package/templates/starter/e2e/toolcraft-delivery-catalog-reporter.ts +198 -15
  212. package/templates/starter/e2e/toolcraft-feature-verification-reporter.spec.ts +149 -0
  213. package/templates/starter/e2e/toolcraft-feature-verification-reporter.ts +223 -0
  214. package/templates/starter/package.json +2 -0
  215. package/templates/starter/scripts/check-toolcraft-docs.mjs +1 -0
  216. package/templates/starter/scripts/create-toolcraft-motion-reference-study.mjs +233 -0
  217. package/templates/starter/scripts/create-toolcraft-motion-reference-study.test.mjs +459 -0
  218. package/templates/starter/scripts/playwright-test-title-selection.d.mts +45 -0
  219. package/templates/starter/scripts/run-browser-performance-test-helpers.mjs +0 -27
  220. package/templates/starter/scripts/run-browser-performance.mjs +0 -6
  221. package/templates/starter/scripts/run-browser-performance.test.mjs +5 -13
  222. package/templates/starter/scripts/run-delivery-verification-test-helpers.mjs +0 -34
  223. package/templates/starter/scripts/run-delivery-verification.test.mjs +135 -31
  224. package/templates/starter/scripts/run-feature-verification.mjs +212 -0
  225. package/templates/starter/scripts/run-feature-verification.test.mjs +226 -0
  226. package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.mjs +21 -8
  227. package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.test.mjs +32 -92
  228. package/templates/starter/scripts/toolcraft-checkpoint-transaction.mjs +28 -6
  229. package/templates/starter/scripts/toolcraft-checkpoint-transaction.test.mjs +8 -63
  230. package/templates/starter/scripts/toolcraft-contract-manifest.json +1 -0
  231. package/templates/starter/scripts/toolcraft-delivery-anchor.mjs +28 -8
  232. package/templates/starter/scripts/toolcraft-delivery-anchor.test.mjs +50 -61
  233. package/templates/starter/scripts/toolcraft-delivery-architecture-inventory.mjs +0 -4
  234. package/templates/starter/scripts/toolcraft-delivery-architecture-policy.mjs +0 -1
  235. package/templates/starter/scripts/toolcraft-delivery-evidence.test.mjs +2 -3
  236. package/templates/starter/scripts/toolcraft-delivery-executor.mjs +5 -1
  237. package/templates/starter/scripts/toolcraft-delivery-executor.test.mjs +5 -12
  238. package/templates/starter/scripts/toolcraft-delivery-functional-context.d.mts +1 -48
  239. package/templates/starter/scripts/toolcraft-delivery-functional-context.mjs +2 -30
  240. package/templates/starter/scripts/toolcraft-delivery-functional-context.test.mjs +4 -166
  241. package/templates/starter/scripts/toolcraft-delivery-functional-initial.test.mjs +4 -20
  242. package/templates/starter/scripts/toolcraft-delivery-lifecycle.mjs +43 -192
  243. package/templates/starter/scripts/toolcraft-delivery-performance-iteration-lifecycle.test.mjs +79 -440
  244. package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +102 -297
  245. package/templates/starter/scripts/toolcraft-delivery-plan-construction.mjs +46 -97
  246. package/templates/starter/scripts/toolcraft-delivery-plan-test-helpers.mjs +125 -0
  247. package/templates/starter/scripts/toolcraft-delivery-plan-validation.test.mjs +58 -0
  248. package/templates/starter/scripts/toolcraft-delivery-plan.d.mts +19 -31
  249. package/templates/starter/scripts/toolcraft-delivery-plan.mjs +254 -252
  250. package/templates/starter/scripts/toolcraft-delivery-plan.test.mjs +29 -457
  251. package/templates/starter/scripts/toolcraft-delivery-receipt-performance.test.mjs +1 -1
  252. package/templates/starter/scripts/toolcraft-delivery-receipt-strictness.test.mjs +3 -72
  253. package/templates/starter/scripts/toolcraft-delivery-receipt-test-helpers.mjs +7 -36
  254. package/templates/starter/scripts/toolcraft-delivery-receipt.d.mts +3 -5
  255. package/templates/starter/scripts/toolcraft-delivery-receipt.mjs +15 -31
  256. package/templates/starter/scripts/toolcraft-delivery-receipt.test.mjs +28 -20
  257. package/templates/starter/scripts/toolcraft-delivery-receipt.types.test.mts +22 -30
  258. package/templates/starter/scripts/toolcraft-feature-verification-plan.d.mts +20 -0
  259. package/templates/starter/scripts/toolcraft-feature-verification-plan.mjs +146 -0
  260. package/templates/starter/scripts/toolcraft-feature-verification-plan.test.mjs +96 -0
  261. package/templates/starter/scripts/toolcraft-functional-proof-model.d.mts +3 -18
  262. package/templates/starter/scripts/toolcraft-functional-proof-model.mjs +39 -127
  263. package/templates/starter/scripts/toolcraft-functional-proof-model.test.mjs +25 -362
  264. package/templates/starter/scripts/toolcraft-functional-proof-model.types.test.mts +6 -83
  265. package/templates/starter/scripts/toolcraft-functional-proof-primitives.d.mts +11 -0
  266. package/templates/starter/scripts/toolcraft-functional-proof-primitives.mjs +61 -0
  267. package/templates/starter/scripts/toolcraft-functional-proof-primitives.test.mjs +43 -0
  268. package/templates/starter/scripts/toolcraft-integrity-policy.mjs +13 -0
  269. package/templates/starter/scripts/toolcraft-integrity-test-utils.mjs +1 -1
  270. package/templates/starter/scripts/toolcraft-layer-evidence-facade.test.mjs +58 -22
  271. package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.mjs +111 -0
  272. package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.test.mjs +116 -0
  273. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.d.mts +37 -0
  274. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.mjs +308 -0
  275. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.test.mjs +420 -0
  276. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.types.test.mts +50 -0
  277. package/templates/starter/scripts/toolcraft-motion-reference-command-options.mjs +195 -0
  278. package/templates/starter/scripts/toolcraft-motion-reference-command-options.test.mjs +224 -0
  279. package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.mjs +122 -0
  280. package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.test.mjs +153 -0
  281. package/templates/starter/scripts/toolcraft-motion-reference-evidence-assembly.mjs +270 -0
  282. package/templates/starter/scripts/toolcraft-motion-reference-evidence.test.mjs +432 -0
  283. package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.mjs +275 -0
  284. package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.test.mjs +294 -0
  285. package/templates/starter/scripts/toolcraft-motion-reference-group-inventory.mjs +148 -0
  286. package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.mjs +101 -0
  287. package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.test.mjs +124 -0
  288. package/templates/starter/scripts/toolcraft-motion-reference-image-source.mjs +259 -0
  289. package/templates/starter/scripts/toolcraft-motion-reference-image-source.test.mjs +338 -0
  290. package/templates/starter/scripts/toolcraft-motion-reference-image-timing.mjs +96 -0
  291. package/templates/starter/scripts/toolcraft-motion-reference-image-timing.test.mjs +81 -0
  292. package/templates/starter/scripts/toolcraft-motion-reference-lock-recovery.test.mjs +144 -0
  293. package/templates/starter/scripts/toolcraft-motion-reference-media-source.mjs +165 -0
  294. package/templates/starter/scripts/toolcraft-motion-reference-media-source.test.mjs +299 -0
  295. package/templates/starter/scripts/toolcraft-motion-reference-publication-discovery.test.mjs +142 -0
  296. package/templates/starter/scripts/toolcraft-motion-reference-publication-isolation.test.mjs +234 -0
  297. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-schema.mjs +122 -0
  298. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.mjs +89 -0
  299. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.test.mjs +74 -0
  300. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.mjs +264 -0
  301. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.test.mjs +377 -0
  302. package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.mjs +254 -0
  303. package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.test.mjs +130 -0
  304. package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.mjs +128 -0
  305. package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.test.mjs +209 -0
  306. package/templates/starter/scripts/toolcraft-motion-reference-publication.fixtures.mjs +88 -0
  307. package/templates/starter/scripts/toolcraft-motion-reference-publication.mjs +249 -0
  308. package/templates/starter/scripts/toolcraft-motion-reference-publication.test.mjs +433 -0
  309. package/templates/starter/scripts/toolcraft-motion-reference-review-output.mjs +38 -0
  310. package/templates/starter/scripts/toolcraft-motion-reference-review-output.test.mjs +29 -0
  311. package/templates/starter/scripts/toolcraft-motion-reference-root-safety.test.mjs +84 -0
  312. package/templates/starter/scripts/toolcraft-motion-reference-roots.mjs +83 -0
  313. package/templates/starter/scripts/toolcraft-motion-reference-sampling.mjs +283 -0
  314. package/templates/starter/scripts/toolcraft-motion-reference-sampling.test.mjs +480 -0
  315. package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.mjs +39 -0
  316. package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.test.mjs +59 -0
  317. package/templates/starter/scripts/toolcraft-motion-reference-stage.mjs +71 -0
  318. package/templates/starter/scripts/toolcraft-motion-reference-stage.test.mjs +61 -0
  319. package/templates/starter/scripts/toolcraft-motion-review-numeric.mjs +74 -0
  320. package/templates/starter/scripts/toolcraft-motion-review-numeric.test.mjs +65 -0
  321. package/templates/starter/scripts/toolcraft-motion-review-partitioning.mjs +268 -0
  322. package/templates/starter/scripts/toolcraft-motion-review-partitioning.test.mjs +329 -0
  323. package/templates/starter/scripts/toolcraft-motion-review-protected-units.mjs +120 -0
  324. package/templates/starter/scripts/toolcraft-motion-review-protected-units.test.mjs +111 -0
  325. package/templates/starter/scripts/toolcraft-performance-escalation-policy.test.mjs +77 -345
  326. package/templates/starter/scripts/toolcraft-performance-receipt-validation.test.mjs +19 -21
  327. package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +85 -115
  328. package/templates/starter/scripts/toolcraft-product-boundary-module-policy.mjs +101 -0
  329. package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +0 -72
  330. package/templates/starter/scripts/toolcraft-product-control-bindings.mjs +182 -0
  331. package/templates/starter/scripts/toolcraft-product-control-boundary.mjs +146 -0
  332. package/templates/starter/scripts/toolcraft-product-control-boundary.test.mjs +186 -0
  333. package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +16 -18
  334. package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +200 -0
  335. package/templates/starter/scripts/toolcraft-product-observable-facade.test.mjs +46 -1
  336. package/templates/starter/scripts/toolcraft-receipt-boundary.test.mjs +0 -1
  337. package/templates/starter/scripts/toolcraft-source-inventory.d.mts +5 -0
  338. package/templates/starter/scripts/toolcraft-source-inventory.mjs +25 -14
  339. package/templates/starter/scripts/toolcraft-source-inventory.test.mjs +48 -0
  340. package/templates/starter/scripts/toolcraft-source-ownership.mjs +0 -1
  341. package/templates/starter/scripts/toolcraft-source-ownership.test.mjs +30 -5
  342. package/templates/starter/scripts/toolcraft-typescript-source-evidence-structure.test.mjs +20 -0
  343. package/templates/starter/scripts/toolcraft-typescript-source-evidence.mjs +1 -0
  344. package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade.test.mjs +2 -0
  345. package/templates/starter/scripts/toolcraft-verification-receipt-test-helpers.mjs +5 -26
  346. package/templates/starter/scripts/toolcraft-verification-receipt.d.mts +0 -7
  347. package/templates/starter/scripts/toolcraft-verification-receipt.mjs +3 -47
  348. package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +6 -87
  349. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.d.mts +19 -0
  350. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.mjs +107 -0
  351. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.test.mjs +114 -0
  352. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.mjs +13 -2
  353. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.test.mjs +110 -0
  354. package/templates/starter/src/app/acceptance/artifact-export-intent.ts +161 -0
  355. package/templates/starter/src/app/acceptance/canvas-coverage.ts +1 -0
  356. package/templates/starter/src/app/acceptance/color-bank-labels.ts +11 -15
  357. package/templates/starter/src/app/acceptance/color-row-grouping.ts +33 -0
  358. package/templates/starter/src/app/acceptance/conditions.ts +1 -1
  359. package/templates/starter/src/app/acceptance/control-acceptance-context.ts +2 -2
  360. package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +6 -31
  361. package/templates/starter/src/app/acceptance/control-acceptance-kind-rules.ts +24 -5
  362. package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +4 -16
  363. package/templates/starter/src/app/acceptance/control-applicability-cases.test.ts +321 -0
  364. package/templates/starter/src/app/acceptance/control-applicability-cases.ts +290 -0
  365. package/templates/starter/src/app/acceptance/control-applicability.ts +332 -0
  366. package/templates/starter/src/app/acceptance/control-component-rules.ts +0 -10
  367. package/templates/starter/src/app/acceptance/control-labels.ts +30 -1
  368. package/templates/starter/src/app/acceptance/control-layout-dependency-rules.ts +20 -9
  369. package/templates/starter/src/app/acceptance/control-layout-entity-rules.ts +4 -6
  370. package/templates/starter/src/app/acceptance/control-layout-model.ts +4 -4
  371. package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +21 -10
  372. package/templates/starter/src/app/acceptance/control-parts.ts +8 -0
  373. package/templates/starter/src/app/acceptance/control-section-entity-cohesion.test.ts +215 -0
  374. package/templates/starter/src/app/acceptance/control-section-entity-cohesion.ts +132 -0
  375. package/templates/starter/src/app/acceptance/control-section-inventory.test.ts +87 -0
  376. package/templates/starter/src/app/acceptance/control-section-inventory.ts +74 -44
  377. package/templates/starter/src/app/acceptance/custom-controls.ts +11 -3
  378. package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +25 -17
  379. package/templates/starter/src/app/acceptance/feature-verification-selection.test.ts +295 -0
  380. package/templates/starter/src/app/acceptance/feature-verification-selection.ts +161 -0
  381. package/templates/starter/src/app/acceptance/infinity-canvas.ts +10 -0
  382. package/templates/starter/src/app/acceptance/inline-layout.ts +64 -9
  383. package/templates/starter/src/app/acceptance/interaction-ownership-intent.ts +19 -1
  384. package/templates/starter/src/app/acceptance/interaction-ownership.ts +18 -2
  385. package/templates/starter/src/app/acceptance/media-upload.ts +5 -1
  386. package/templates/starter/src/app/acceptance/motion-reference-evidence-validation.mjs +65 -0
  387. package/templates/starter/src/app/acceptance/motion-reference-evidence-windows.mjs +301 -0
  388. package/templates/starter/src/app/acceptance/motion-reference-evidence.d.mts +11 -0
  389. package/templates/starter/src/app/acceptance/motion-reference-evidence.mjs +145 -0
  390. package/templates/starter/src/app/acceptance/motion-reference-study-behaviors.ts +162 -0
  391. package/templates/starter/src/app/acceptance/motion-reference-study-coverage.ts +206 -0
  392. package/templates/starter/src/app/acceptance/motion-reference-study-identity.ts +129 -0
  393. package/templates/starter/src/app/acceptance/motion-reference-study-partitions.ts +186 -0
  394. package/templates/starter/src/app/acceptance/motion-reference-study.ts +90 -0
  395. package/templates/starter/src/app/acceptance/orientation-gizmo.ts +18 -11
  396. package/templates/starter/src/app/acceptance/output-background-rules.ts +2 -2
  397. package/templates/starter/src/app/acceptance/output-export-actions.test.ts +9 -1
  398. package/templates/starter/src/app/acceptance/output-export-actions.ts +14 -22
  399. package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +22 -10
  400. package/templates/starter/src/app/acceptance/output-export-model.ts +58 -11
  401. package/templates/starter/src/app/acceptance/output-export.ts +25 -10
  402. package/templates/starter/src/app/acceptance/output-video-export-rules.ts +99 -0
  403. package/templates/starter/src/app/acceptance/reference-study-types.ts +167 -17
  404. package/templates/starter/src/app/acceptance/runtime-coverage.ts +6 -1
  405. package/templates/starter/src/app/acceptance/selection-scope.test.ts +200 -0
  406. package/templates/starter/src/app/acceptance/selection-scope.ts +151 -0
  407. package/templates/starter/src/app/acceptance/transfer-mode-types.ts +114 -0
  408. package/templates/starter/src/app/acceptance/types.ts +65 -125
  409. package/templates/starter/src/app/acceptance/validate-coverage.ts +33 -5
  410. package/templates/starter/src/app/starter-acceptance-data.ts +1 -0
  411. package/templates/starter/src/app/starter-acceptance.animation-intent.test.ts +3 -0
  412. package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +312 -0
  413. package/templates/starter/src/app/starter-acceptance.background-export.test.ts +35 -0
  414. package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +18 -1
  415. package/templates/starter/src/app/starter-acceptance.color-row-grouping.test.ts +118 -0
  416. package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +66 -1
  417. package/templates/starter/src/app/starter-acceptance.contract-fixtures.test.ts +41 -0
  418. package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +113 -16
  419. package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +225 -0
  420. package/templates/starter/src/app/starter-acceptance.control-label-context.test.ts +1 -0
  421. package/templates/starter/src/app/starter-acceptance.control-labels.test.ts +78 -3
  422. package/templates/starter/src/app/starter-acceptance.control-naming-rules.test.ts +77 -1
  423. package/templates/starter/src/app/starter-acceptance.control-order.test.ts +58 -3
  424. package/templates/starter/src/app/starter-acceptance.control-state.test.ts +0 -111
  425. package/templates/starter/src/app/starter-acceptance.custom-control-collections.test.ts +3 -1
  426. package/templates/starter/src/app/starter-acceptance.custom-control-fit-check.test.ts +1 -1
  427. package/templates/starter/src/app/starter-acceptance.custom-control-valid.test.ts +1 -1
  428. package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +74 -3
  429. package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +26 -0
  430. package/templates/starter/src/app/{starter-acceptance.image-video-export-settings.test.ts → starter-acceptance.image-export-settings.test.ts} +39 -9
  431. package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +31 -3
  432. package/templates/starter/src/app/starter-acceptance.layers.test.ts +2 -1
  433. package/templates/starter/src/app/starter-acceptance.media-upload.fixtures.ts +11 -1
  434. package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +56 -0
  435. package/templates/starter/src/app/starter-acceptance.motion-reference-evidence.test.ts +17 -0
  436. package/templates/starter/src/app/starter-acceptance.motion-reference-identity.test.ts +163 -0
  437. package/templates/starter/src/app/starter-acceptance.motion-reference-mapping.test.ts +133 -0
  438. package/templates/starter/src/app/starter-acceptance.motion-reference-ownership.test.ts +121 -0
  439. package/templates/starter/src/app/starter-acceptance.motion-reference-partitions.test.ts +210 -0
  440. package/templates/starter/src/app/starter-acceptance.motion-reference-test-utils.ts +313 -0
  441. package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +458 -0
  442. package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +4 -0
  443. package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +116 -104
  444. package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +29 -0
  445. package/templates/starter/src/app/starter-acceptance.product-worklog.test.ts +123 -2
  446. package/templates/starter/src/app/starter-acceptance.reference-custom-timeline.test.ts +2 -0
  447. package/templates/starter/src/app/starter-acceptance.reference-foundation.test.ts +8 -0
  448. package/templates/starter/src/app/starter-acceptance.reference-timeline.test.ts +7 -0
  449. package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +3 -1
  450. package/templates/starter/src/app/starter-acceptance.section-dependencies.test.ts +35 -24
  451. package/templates/starter/src/app/starter-acceptance.section-size.test.ts +72 -0
  452. package/templates/starter/src/app/starter-acceptance.timeline-playback.test.ts +5 -0
  453. package/templates/starter/src/app/starter-acceptance.ts +45 -10
  454. package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +338 -0
  455. package/templates/starter/src/app/starter-acceptance.video-reference-study.test.ts +34 -236
  456. package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +12 -0
  457. package/templates/starter/src/app/starter-acceptance.worklog-test-utils.ts +122 -6
  458. package/templates/starter/src/app/starter-acceptance.worklog.test.ts +152 -16
  459. package/templates/starter/src/app/starter-performance.gates.test.ts +20 -18
  460. package/templates/starter/src/app/starter-performance.lifecycle.test.ts +22 -6
  461. package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +5 -2
  462. package/templates/starter/src/routes/index.tsx +1 -0
  463. package/templates/starter/tsconfig.json +1 -0
  464. package/templates/ui/components/composites/tabs.tsx +2 -2
  465. package/templates/ui/components/controls/collection-actions/collection-item-groups.test.tsx +38 -0
  466. package/templates/ui/components/controls/collection-actions/collection-item-groups.tsx +36 -0
  467. package/templates/ui/components/controls/collection-actions/index.ts +2 -0
  468. package/templates/ui/components/controls/file-drop/file-drop-collection-control.tsx +137 -0
  469. package/templates/ui/components/controls/file-drop/file-drop-control.test.tsx +189 -0
  470. package/templates/ui/components/controls/file-drop/file-drop-control.tsx +81 -88
  471. package/templates/ui/components/controls/file-drop/file-drop-presentation.tsx +131 -9
  472. package/templates/ui/components/controls/file-drop/file-drop-types.ts +36 -22
  473. package/templates/ui/components/controls/file-drop/index.ts +1 -0
  474. package/templates/ui/components/controls/index.ts +3 -0
  475. package/templates/ui/components/controls/range-slider/range-slider-control.tsx +1 -1
  476. package/templates/ui/components/controls/range-slider/range-slider-value.test.ts +14 -0
  477. package/templates/ui/components/controls/range-slider/range-slider-value.ts +3 -2
  478. package/templates/starter/scripts/toolcraft-browser-impact-selection.mjs +0 -26
  479. package/templates/starter/scripts/toolcraft-delivery-framework-refresh.test.mjs +0 -141
  480. package/templates/starter/scripts/toolcraft-delivery-functional-changed.test.mjs +0 -468
  481. package/templates/starter/scripts/toolcraft-delivery-functional-model-lifecycle.test.mjs +0 -254
  482. package/templates/starter/scripts/toolcraft-delivery-functional-semantic-regression.test.mjs +0 -135
  483. package/templates/starter/scripts/toolcraft-delivery-performance-iteration-durability.test.mjs +0 -329
  484. package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +0 -430
  485. package/templates/starter/scripts/toolcraft-delivery-plan-functional-model.test.mjs +0 -358
  486. package/templates/starter/scripts/toolcraft-functional-proof-regression-fixtures.mjs +0 -298
  487. package/templates/starter/scripts/toolcraft-verification-impact-inventory.d.mts +0 -62
  488. package/templates/starter/scripts/toolcraft-verification-impact-inventory.mjs +0 -344
  489. package/templates/starter/scripts/toolcraft-verification-impact-inventory.test.mjs +0 -204
  490. package/templates/starter/scripts/toolcraft-verification-impact-performance-candidates.test.mjs +0 -210
  491. package/templates/starter/scripts/toolcraft-verification-impact-resolution.mjs +0 -344
  492. package/templates/starter/scripts/toolcraft-verification-impact-resolution.test.mjs +0 -270
  493. package/templates/starter/scripts/toolcraft-verification-impact-semantic-resolution.test.mjs +0 -449
  494. package/templates/starter/scripts/toolcraft-verification-impact-support-resolution.test.mjs +0 -195
  495. package/templates/starter/scripts/toolcraft-verification-impact.d.mts +0 -132
  496. package/templates/starter/scripts/toolcraft-verification-impact.mjs +0 -169
  497. package/templates/starter/scripts/toolcraft-verification-impact.test.mjs +0 -300
  498. package/templates/starter/scripts/toolcraft-verification-input-roles.mjs +0 -197
  499. package/templates/starter/scripts/toolcraft-verification-input-roles.test.mjs +0 -225
  500. package/templates/starter/src/app/acceptance/condition-exclusivity.test.ts +0 -60
  501. package/templates/starter/src/app/acceptance/condition-exclusivity.ts +0 -221
  502. package/templates/starter/src/app/acceptance/video-reference-study.ts +0 -217
  503. package/templates/starter/src/app/starter-verification-impact.json +0 -15
@@ -18,6 +18,7 @@ export type InfinityCanvasObservation = Readonly<{
18
18
  finiteControlSize: { height: number; width: number } | null;
19
19
  finiteControlsPresent: boolean;
20
20
  overflow: string;
21
+ productSceneStatus: "empty" | "ready" | "unavailable" | null;
21
22
  sceneRect: { height: number; width: number; x: number; y: number } | null;
22
23
  viewportOffset: { x: number; y: number };
23
24
  }>;
@@ -91,18 +92,17 @@ export async function observeInfinityCanvasBackground(
91
92
 
92
93
  export async function observeInfinityCanvas(
93
94
  page: Page,
94
- sceneSelector?: string,
95
95
  ): Promise<InfinityCanvasObservation> {
96
- return page.evaluate((selector) => {
96
+ return page.evaluate(() => {
97
97
  const surface = document.querySelector<HTMLElement>(
98
98
  "[data-toolcraft-canvas-mode]",
99
99
  );
100
100
  const world = document.querySelector<HTMLElement>(
101
101
  "[data-toolcraft-canvas-world]",
102
102
  );
103
- const scene = selector
104
- ? document.querySelector<HTMLElement>(selector)
105
- : null;
103
+ const productScene = document.querySelector<HTMLElement>(
104
+ "[data-toolcraft-product-scene]",
105
+ );
106
106
  const finiteControlsPresent = [
107
107
  "canvas.aspectRatio",
108
108
  "canvas.size.width",
@@ -138,7 +138,7 @@ export async function observeInfinityCanvas(
138
138
  const parsed = Number.parseFloat(value ?? "");
139
139
  return Number.isFinite(parsed) ? parsed : null;
140
140
  };
141
- const style = scene?.style;
141
+ const style = productScene?.style;
142
142
  const sceneValues = style
143
143
  ? {
144
144
  height: read(style.height),
@@ -156,11 +156,11 @@ export async function observeInfinityCanvas(
156
156
  y: sceneValues.y!,
157
157
  }
158
158
  : null;
159
+ const productSceneStatus =
160
+ productScene?.dataset.toolcraftProductSceneStatus;
159
161
 
160
162
  return {
161
- artboardPresent: Boolean(
162
- editableCanvas,
163
- ),
163
+ artboardPresent: Boolean(editableCanvas),
164
164
  canvasMode: surface?.getAttribute("data-toolcraft-canvas-mode") ?? null,
165
165
  finiteCanvasSize:
166
166
  canvasWidth === null || canvasHeight === null
@@ -172,13 +172,19 @@ export async function observeInfinityCanvas(
172
172
  : { height: controlHeight, width: controlWidth },
173
173
  finiteControlsPresent,
174
174
  overflow: surface ? getComputedStyle(surface).overflow : "missing",
175
+ productSceneStatus:
176
+ productSceneStatus === "ready" ||
177
+ productSceneStatus === "empty" ||
178
+ productSceneStatus === "unavailable"
179
+ ? productSceneStatus
180
+ : null,
175
181
  sceneRect,
176
182
  viewportOffset: {
177
183
  x: Number(world?.dataset.toolcraftCanvasOffsetX ?? 0),
178
184
  y: Number(world?.dataset.toolcraftCanvasOffsetY ?? 0),
179
185
  },
180
186
  };
181
- }, sceneSelector);
187
+ });
182
188
  }
183
189
 
184
190
  export function expectInfiniteCanvasObservation(
@@ -191,7 +197,10 @@ export function expectInfiniteCanvasObservation(
191
197
  expect(observation.finiteControlSize).toEqual(null);
192
198
  expect(observation.finiteControlsPresent).toBe(false);
193
199
  expect(observation.overflow).toBe("visible");
194
- if (expectedSceneRect) expect(observation.sceneRect).toEqual(expectedSceneRect);
200
+ if (expectedSceneRect) {
201
+ expect(observation.productSceneStatus).toBe("ready");
202
+ expect(observation.sceneRect).toEqual(expectedSceneRect);
203
+ }
195
204
  expect(Number.isFinite(observation.viewportOffset.x)).toBe(true);
196
205
  expect(Number.isFinite(observation.viewportOffset.y)).toBe(true);
197
206
  }
@@ -0,0 +1,42 @@
1
+ import { expect } from "@playwright/test";
2
+
3
+ import { attachToolcraftBrowserRuntimeEvidence } from "./browser-runtime-evidence";
4
+ import type { ToolcraftSvgArtifactInspection } from "./export-artifact-helpers";
5
+ import { assertToolcraftInspectedSvgArtifact } from "./svg-artifact-inspection";
6
+
7
+ export async function expectToolcraftInfinityCanvasSvgExportEvidence(
8
+ artifacts: Readonly<{
9
+ finite: ToolcraftSvgArtifactInspection;
10
+ infinite: ToolcraftSvgArtifactInspection;
11
+ }>,
12
+ options: Readonly<{
13
+ expectedFiniteSize: Readonly<{ height: number; width: number }>;
14
+ expectedInfiniteSize: Readonly<{ height: number; width: number }>;
15
+ requirementId: string;
16
+ target: string;
17
+ }>,
18
+ ): Promise<void> {
19
+ assertToolcraftInspectedSvgArtifact(artifacts.finite);
20
+ assertToolcraftInspectedSvgArtifact(artifacts.infinite);
21
+ expect(artifacts.finite).toMatchObject(options.expectedFiniteSize);
22
+ expect(artifacts.infinite).toMatchObject(options.expectedInfiniteSize);
23
+
24
+ for (const artifact of [artifacts.finite, artifacts.infinite]) {
25
+ expect(artifact.byteLength).toBeGreaterThan(100);
26
+ expect(artifact.contentHash).toMatch(/^[a-f0-9]{64}$/u);
27
+ expect(artifact.mediaType).toBe("image/svg+xml");
28
+ expect(artifact.vectorElementCount).toBeGreaterThan(0);
29
+ }
30
+
31
+ expect({ height: artifacts.infinite.height, width: artifacts.infinite.width })
32
+ .not.toEqual({
33
+ height: artifacts.finite.height,
34
+ width: artifacts.finite.width,
35
+ });
36
+
37
+ await attachToolcraftBrowserRuntimeEvidence({
38
+ evidenceType: "infinity-scene-bounds-svg-export",
39
+ requirementId: options.requirementId,
40
+ target: options.target,
41
+ });
42
+ }
@@ -11,6 +11,10 @@ import {
11
11
  type ToolcraftBrowserAction,
12
12
  type ToolcraftBrowserObservation,
13
13
  } from "./browser-proof-session";
14
+ import {
15
+ expectToolcraftSelectionScopedControl,
16
+ type ToolcraftSelectionScopedControlOptions,
17
+ } from "./browser-selection-scope-evidence";
14
18
 
15
19
  export type ToolcraftLayerCollectionObservation = {
16
20
  layerIds: readonly string[];
@@ -22,12 +26,6 @@ export type ToolcraftLayerGroupingObservation =
22
26
  groupSignature: string;
23
27
  };
24
28
 
25
- export type ToolcraftLayerSelectedControlObservation = {
26
- controlValue: unknown;
27
- outputSignature: string;
28
- selectedLayerId: string;
29
- };
30
-
31
29
  export type ToolcraftLayerSelectionObservation = {
32
30
  selectedLayerId: string;
33
31
  };
@@ -223,37 +221,18 @@ export async function expectToolcraftLayerGrouping(
223
221
  return after;
224
222
  }
225
223
 
224
+ export type ToolcraftSelectedLayerControlOptions =
225
+ ToolcraftSelectionScopedControlOptions;
226
+
226
227
  export async function expectToolcraftSelectedLayerControl(
227
- observeControl: ToolcraftBrowserObservation<ToolcraftLayerSelectedControlObservation>,
228
- action: ToolcraftBrowserAction,
229
- expected: ToolcraftLayerSelectedControlObservation,
230
- options: ToolcraftSemanticEvidenceOptions,
231
- ): Promise<ToolcraftLayerSelectedControlObservation> {
232
- const target = requireLayerActionTarget(action, options.requirementId);
233
- validateIdentifier(expected.selectedLayerId, "Selected-layer control requires a layer id.");
234
- validateIdentifier(
235
- expected.outputSignature,
236
- "Selected-layer control requires product-output semantics.",
237
- );
238
- const { after, before } = await expectToolcraftExpectedOutcomeAfterAction(
239
- observeControl,
240
- action,
241
- expected,
242
- createToolcraftSemanticTransitionOptions(
243
- `Selected-layer control "${options.requirementId}" should edit the selected layer output.`,
244
- options,
245
- ),
246
- );
247
- expect(before.selectedLayerId).toBe(after.selectedLayerId);
248
- expect(before.controlValue).not.toEqual(after.controlValue);
249
- expect(before.outputSignature).not.toBe(after.outputSignature);
250
- await attachLayerEvidence(
251
- "media-lifecycle",
252
- "layer-selected-layer-controls",
253
- options.requirementId,
254
- target,
255
- );
256
- return after;
228
+ options: ToolcraftSelectedLayerControlOptions,
229
+ ): Promise<void> {
230
+ await expectToolcraftSelectionScopedControl(options);
231
+ await attachToolcraftBrowserRuntimeEvidence({
232
+ evidenceType: "layer-selected-layer-controls",
233
+ requirementId: options.requirementId,
234
+ target: options.propertyTarget,
235
+ });
257
236
  }
258
237
 
259
238
  export async function expectToolcraftLayerMediaLifecycle(
@@ -26,6 +26,9 @@ import {
26
26
  getToolcraftOrientationAxisPosition,
27
27
  type ToolcraftOrientationAxis,
28
28
  } from "./browser-orientation-gizmo-actions";
29
+ import {
30
+ expectToolcraftOrientationLiveDragPreconditions,
31
+ } from "./browser-orientation-gizmo-live-preconditions";
29
32
 
30
33
  export type ToolcraftOrientationBrowserObservation = {
31
34
  outputSignature: string;
@@ -222,6 +225,7 @@ export async function expectToolcraftOrientationAxisDrag(
222
225
  message,
223
226
  options,
224
227
  );
228
+ await expectToolcraftOrientationLiveDragPreconditions(session);
225
229
  const before = snapshotToolcraftOutcome(await observe(), message);
226
230
 
227
231
  validateObservation(before, options);
@@ -0,0 +1,86 @@
1
+ import { expect, type Locator, type Page } from "@playwright/test";
2
+
3
+ import {
4
+ countToolcraftControlOwnersByTarget,
5
+ getToolcraftControlFieldByTarget,
6
+ } from "./browser-control-target-helpers";
7
+ import {
8
+ getToolcraftBrowserProofPage,
9
+ type ToolcraftBrowserProofSession,
10
+ } from "./browser-proof-session";
11
+
12
+ const TOOLCRAFT_APP_ROOT_SELECTOR = '[data-slot="toolcraft-runtime-app"]';
13
+ const RENDER_SCALE_TARGET = "canvas.renderScale";
14
+
15
+ async function expectPausedPlaybackWhenPresent(page: Page): Promise<void> {
16
+ const root = page.locator(TOOLCRAFT_APP_ROOT_SELECTOR);
17
+ const play = root.getByRole("button", { name: "Play playback" });
18
+ const pause = root.getByRole("button", { name: "Pause playback" });
19
+ const playCount = await play.count();
20
+ const actionCount = playCount + (await pause.count());
21
+
22
+ if (actionCount === 0) return;
23
+
24
+ expect(
25
+ actionCount,
26
+ "Orientation axis-drag proof requires exactly one standard playback action.",
27
+ ).toBe(1);
28
+ expect(
29
+ playCount,
30
+ "Orientation axis-drag proof must be paused; Play playback must be visible before its baseline.",
31
+ ).toBe(1);
32
+ await expect(play).toBeVisible();
33
+ }
34
+
35
+ async function readFiniteAriaNumber(
36
+ slider: Locator,
37
+ name: "aria-valuemax" | "aria-valuenow",
38
+ ): Promise<number> {
39
+ const raw = await slider.getAttribute(name);
40
+ const value = raw === null || raw.trim() === "" ? Number.NaN : Number(raw);
41
+
42
+ expect(
43
+ Number.isFinite(value),
44
+ `Orientation axis-drag proof requires a finite ${name} on canvas.renderScale.`,
45
+ ).toBe(true);
46
+ return value;
47
+ }
48
+
49
+ async function expectMaximumRenderScaleWhenPresent(page: Page): Promise<void> {
50
+ const ownerCount = await countToolcraftControlOwnersByTarget(
51
+ page,
52
+ RENDER_SCALE_TARGET,
53
+ );
54
+
55
+ if (ownerCount === 0) return;
56
+
57
+ expect(
58
+ ownerCount,
59
+ "Orientation axis-drag proof requires exactly one canvas.renderScale owner.",
60
+ ).toBe(1);
61
+ const field = await getToolcraftControlFieldByTarget(
62
+ page,
63
+ RENDER_SCALE_TARGET,
64
+ );
65
+ const slider = field.getByRole("slider");
66
+ await expect(
67
+ slider,
68
+ "Orientation axis-drag proof requires one canvas.renderScale slider.",
69
+ ).toHaveCount(1);
70
+ await expect(slider).toBeVisible();
71
+
72
+ const value = await readFiniteAriaNumber(slider, "aria-valuenow");
73
+ const maximum = await readFiniteAriaNumber(slider, "aria-valuemax");
74
+ expect(
75
+ value,
76
+ "Orientation axis-drag proof requires canvas.renderScale at maximum quality before its baseline.",
77
+ ).toBe(maximum);
78
+ }
79
+
80
+ export async function expectToolcraftOrientationLiveDragPreconditions(
81
+ session: ToolcraftBrowserProofSession,
82
+ ): Promise<void> {
83
+ const page = await getToolcraftBrowserProofPage(session);
84
+ await expectPausedPlaybackWhenPresent(page);
85
+ await expectMaximumRenderScaleWhenPresent(page);
86
+ }
@@ -0,0 +1,213 @@
1
+ import { expect, type Locator, type Page } from "@playwright/test";
2
+
3
+ const maxRasterDimension = 4096;
4
+ const maxRasterPixelArea = 8_388_608;
5
+ const screenshotOptions = Object.freeze({
6
+ animations: "disabled" as const,
7
+ caret: "hide" as const,
8
+ scale: "css" as const,
9
+ type: "png" as const,
10
+ });
11
+ const warmedSelectors = new WeakMap<Page, Set<string>>();
12
+
13
+ export type ToolcraftProductRasterRegion = Readonly<{
14
+ height: number;
15
+ width: number;
16
+ x: number;
17
+ y: number;
18
+ }>;
19
+
20
+ export type ToolcraftProductRasterProbe = Readonly<{
21
+ region?: ToolcraftProductRasterRegion;
22
+ selector: string;
23
+ }>;
24
+
25
+ export type ToolcraftResolvedProductRasterProbe = Readonly<{
26
+ bounds: ToolcraftProductRasterRegion;
27
+ capture: () => Promise<string>;
28
+ locator: Locator;
29
+ }>;
30
+
31
+ function validateRegion(
32
+ region: ToolcraftProductRasterRegion,
33
+ ownerWidth: number,
34
+ ownerHeight: number,
35
+ label: string,
36
+ ): void {
37
+ if (
38
+ !Number.isFinite(region.x) ||
39
+ !Number.isFinite(region.y) ||
40
+ !Number.isFinite(region.width) ||
41
+ !Number.isFinite(region.height) ||
42
+ region.x < 0 ||
43
+ region.y < 0 ||
44
+ region.width <= 0 ||
45
+ region.height <= 0 ||
46
+ region.x + region.width > ownerWidth ||
47
+ region.y + region.height > ownerHeight
48
+ ) {
49
+ throw new Error(
50
+ `Raster probe "${label}" requires a finite positive region inside its visible selector.`,
51
+ );
52
+ }
53
+ }
54
+
55
+ async function decodeRasterSnapshot(
56
+ page: Page,
57
+ raster: Buffer,
58
+ region: ToolcraftProductRasterRegion | undefined,
59
+ selector: string,
60
+ ): Promise<string> {
61
+ const snapshot = await page.evaluate(
62
+ async ({ encoded, maxDimension, maxPixelArea, probeRegion, selector }) => {
63
+ const binary = atob(encoded);
64
+ const bytes = Uint8Array.from(
65
+ binary,
66
+ (character) => character.charCodeAt(0),
67
+ );
68
+ const bitmap = await createImageBitmap(
69
+ new Blob([bytes], { type: "image/png" }),
70
+ );
71
+
72
+ try {
73
+ const source = probeRegion ?? {
74
+ height: bitmap.height,
75
+ width: bitmap.width,
76
+ x: 0,
77
+ y: 0,
78
+ };
79
+ if (
80
+ source.width > maxDimension ||
81
+ source.height > maxDimension ||
82
+ source.width * source.height > maxPixelArea
83
+ ) {
84
+ throw new Error(
85
+ `Raster probe "${selector}" exceeds the bounded visual proof limit (${source.width}x${source.height}).`,
86
+ );
87
+ }
88
+
89
+ const canvas = document.createElement("canvas");
90
+ canvas.width = Math.ceil(source.width);
91
+ canvas.height = Math.ceil(source.height);
92
+ const context = canvas.getContext("2d", { willReadFrequently: true });
93
+ if (!context) {
94
+ throw new Error(
95
+ `Raster probe "${selector}" could not decode its visual pixels.`,
96
+ );
97
+ }
98
+ context.drawImage(
99
+ bitmap,
100
+ source.x,
101
+ source.y,
102
+ source.width,
103
+ source.height,
104
+ 0,
105
+ 0,
106
+ source.width,
107
+ source.height,
108
+ );
109
+ const pixels = context.getImageData(
110
+ 0,
111
+ 0,
112
+ canvas.width,
113
+ canvas.height,
114
+ ).data;
115
+ const digest = await crypto.subtle.digest(
116
+ "SHA-256",
117
+ new Uint8Array(
118
+ pixels.buffer,
119
+ pixels.byteOffset,
120
+ pixels.byteLength,
121
+ ),
122
+ );
123
+ return {
124
+ height: canvas.height,
125
+ rasterHash: [...new Uint8Array(digest)]
126
+ .map((byte) => byte.toString(16).padStart(2, "0"))
127
+ .join(""),
128
+ width: canvas.width,
129
+ };
130
+ } finally {
131
+ bitmap.close();
132
+ }
133
+ },
134
+ {
135
+ encoded: raster.toString("base64"),
136
+ maxDimension: maxRasterDimension,
137
+ maxPixelArea: maxRasterPixelArea,
138
+ probeRegion: region,
139
+ selector,
140
+ },
141
+ );
142
+
143
+ return JSON.stringify(snapshot);
144
+ }
145
+
146
+ export async function resolveToolcraftProductRasterProbe(
147
+ page: Page,
148
+ probe: ToolcraftProductRasterProbe,
149
+ timeoutMs = 5000,
150
+ ): Promise<ToolcraftResolvedProductRasterProbe> {
151
+ if (!probe.selector.trim()) {
152
+ throw new Error("A raster probe requires a non-empty selector.");
153
+ }
154
+
155
+ const locator = page.locator(probe.selector);
156
+ await expect(
157
+ locator,
158
+ `Raster probe "${probe.selector}" must resolve exactly once.`,
159
+ ).toHaveCount(1);
160
+ await expect(locator).toBeVisible({ timeout: timeoutMs });
161
+ const ownerBounds = await locator.boundingBox();
162
+ if (
163
+ ownerBounds === null ||
164
+ !Number.isFinite(ownerBounds.width) ||
165
+ !Number.isFinite(ownerBounds.height) ||
166
+ ownerBounds.width <= 0 ||
167
+ ownerBounds.height <= 0
168
+ ) {
169
+ throw new Error(
170
+ `Raster probe "${probe.selector}" must have finite positive visible bounds.`,
171
+ );
172
+ }
173
+
174
+ if (probe.region) {
175
+ validateRegion(
176
+ probe.region,
177
+ ownerBounds.width,
178
+ ownerBounds.height,
179
+ probe.selector,
180
+ );
181
+ }
182
+ const localBounds = probe.region ?? {
183
+ height: ownerBounds.height,
184
+ width: ownerBounds.width,
185
+ x: 0,
186
+ y: 0,
187
+ };
188
+ const bounds = {
189
+ height: localBounds.height,
190
+ width: localBounds.width,
191
+ x: ownerBounds.x + localBounds.x,
192
+ y: ownerBounds.y + localBounds.y,
193
+ };
194
+
195
+ return {
196
+ bounds,
197
+ capture: async () => {
198
+ const pageSelectors = warmedSelectors.get(page) ?? new Set<string>();
199
+ const key = `${probe.selector}:${JSON.stringify(probe.region ?? null)}`;
200
+ if (!pageSelectors.has(key)) {
201
+ await locator.screenshot(screenshotOptions);
202
+ await page.evaluate(
203
+ () => new Promise<void>((resolve) => requestAnimationFrame(() => resolve())),
204
+ );
205
+ pageSelectors.add(key);
206
+ warmedSelectors.set(page, pageSelectors);
207
+ }
208
+ const raster = await locator.screenshot(screenshotOptions);
209
+ return decodeRasterSnapshot(page, raster, probe.region, probe.selector);
210
+ },
211
+ locator,
212
+ };
213
+ }
@@ -6,27 +6,27 @@ import {
6
6
  } from "@playwright/test";
7
7
 
8
8
  import { getToolcraftControlFieldByTarget } from "./browser-control-target-helpers";
9
-
9
+ import {
10
+ createToolcraftSurfaceActionRunner,
11
+ normalizeToolcraftSurfaceActionOptions,
12
+ type ToolcraftBrowserActionSurface,
13
+ type ToolcraftBrowserSurfaceActionOptions,
14
+ } from "./browser-proof-surface-action";
15
+ import type {
16
+ ToolcraftBrowserAction,
17
+ ToolcraftBrowserObservation,
18
+ } from "./browser-proof-types";
10
19
  const TOOLCRAFT_APP_ROOT_SELECTOR = '[data-slot="toolcraft-runtime-app"]';
11
20
  const TOOLCRAFT_APP_TITLE_SELECTOR = 'meta[name="toolcraft-app-title"]';
12
21
  const TOOLCRAFT_SERVER_IDENTITY_PATH = "/.toolcraft/server-identity.json";
13
22
 
14
- declare const toolcraftBrowserActionBrand: unique symbol;
15
- declare const toolcraftBrowserObservationBrand: unique symbol;
16
23
  declare const toolcraftBrowserSessionBrand: unique symbol;
17
24
 
18
- export type ToolcraftBrowserAction<
19
- Kind extends string = "interaction",
20
- Result = void,
21
- > = {
22
- readonly [toolcraftBrowserActionBrand]: true;
23
- readonly kind?: Kind;
24
- readonly result?: Result;
25
- };
26
-
27
- export type ToolcraftBrowserObservation<T> = {
28
- readonly [toolcraftBrowserObservationBrand]: T;
29
- };
25
+ export type {
26
+ ToolcraftBrowserAction,
27
+ ToolcraftBrowserObservation,
28
+ } from "./browser-proof-types";
29
+ export type { ToolcraftBrowserActionSurface } from "./browser-proof-surface-action";
30
30
 
31
31
  export type ToolcraftBrowserProofSession = {
32
32
  action<Result = void>(
@@ -36,6 +36,10 @@ export type ToolcraftBrowserProofSession = {
36
36
  target: string,
37
37
  run: (control: Locator, page: Page) => Promise<Result>,
38
38
  ): ToolcraftBrowserAction<"interaction", Result>;
39
+ surfaceAction(
40
+ target: string,
41
+ options: ToolcraftBrowserSurfaceActionOptions,
42
+ ): ToolcraftBrowserAction<"interaction">;
39
43
  targetAction<Result = void>(
40
44
  target: string,
41
45
  run: (page: Page) => Promise<Result>,
@@ -60,6 +64,7 @@ type ActionRecord = {
60
64
  kind: "interaction" | "reload";
61
65
  run: (page: Page) => Promise<unknown>;
62
66
  session: SessionRecord;
67
+ surface?: ToolcraftBrowserActionSurface;
63
68
  target?: string;
64
69
  };
65
70
 
@@ -289,6 +294,23 @@ export async function createToolcraftBrowserProofSession(
289
294
  return run(control, currentPage);
290
295
  },
291
296
  session: record,
297
+ surface: "panel",
298
+ target: normalizedTarget,
299
+ });
300
+ return action;
301
+ },
302
+ surfaceAction(
303
+ target: string,
304
+ rawOptions: ToolcraftBrowserSurfaceActionOptions,
305
+ ): ToolcraftBrowserAction<"interaction"> {
306
+ const normalizedTarget = normalizeActionTarget(target);
307
+ const options = normalizeToolcraftSurfaceActionOptions(rawOptions);
308
+ const action = Object.freeze({}) as ToolcraftBrowserAction<"interaction">;
309
+ actionRecords.set(action, {
310
+ kind: "interaction",
311
+ run: createToolcraftSurfaceActionRunner(options),
312
+ session: record,
313
+ surface: options.surface,
292
314
  target: normalizedTarget,
293
315
  });
294
316
  return action;
@@ -364,6 +386,12 @@ export function getToolcraftBrowserActionTarget(
364
386
  return requireAction(action).target;
365
387
  }
366
388
 
389
+ export function getToolcraftBrowserActionSurface(
390
+ action: ToolcraftBrowserAction,
391
+ ): ToolcraftBrowserActionSurface | undefined {
392
+ return requireAction(action).surface;
393
+ }
394
+
367
395
  export async function readToolcraftBrowserObservation<T>(
368
396
  observation: ToolcraftBrowserObservation<T>,
369
397
  ): Promise<T> {
@@ -0,0 +1,79 @@
1
+ import { expect, type Page } from "@playwright/test";
2
+
3
+ export type ToolcraftBrowserActionSurface = "canvas" | "panel";
4
+
5
+ export type ToolcraftBrowserSurfaceActionOptions = Readonly<{
6
+ position?: Readonly<{ x: number; y: number }>;
7
+ selector: string;
8
+ surface: ToolcraftBrowserActionSurface;
9
+ }>;
10
+
11
+ export function normalizeToolcraftSurfaceActionOptions(
12
+ options: ToolcraftBrowserSurfaceActionOptions,
13
+ ): ToolcraftBrowserSurfaceActionOptions {
14
+ if (!options.selector.trim()) {
15
+ throw new Error("A surface action requires a non-empty selector.");
16
+ }
17
+ if (options.surface !== "canvas" && options.surface !== "panel") {
18
+ throw new Error("A surface action requires canvas or panel ownership.");
19
+ }
20
+ if (
21
+ options.position &&
22
+ (!Number.isFinite(options.position.x) ||
23
+ !Number.isFinite(options.position.y) ||
24
+ options.position.x < 0 ||
25
+ options.position.y < 0)
26
+ ) {
27
+ throw new Error(
28
+ "A surface action position requires finite nonnegative coordinates.",
29
+ );
30
+ }
31
+ return options;
32
+ }
33
+
34
+ async function getToolcraftActionSurface(
35
+ page: Page,
36
+ options: ToolcraftBrowserSurfaceActionOptions,
37
+ ): Promise<ToolcraftBrowserActionSurface | null> {
38
+ return page.locator(options.selector).evaluate((element) => {
39
+ if (element.closest('[data-slot="toolcraft-runtime-canvas"]')) {
40
+ return "canvas";
41
+ }
42
+ if (
43
+ element.closest(
44
+ "[data-toolcraft-controls-panel-shell], [data-toolcraft-layers-panel]",
45
+ )
46
+ ) {
47
+ return "panel";
48
+ }
49
+ return null;
50
+ });
51
+ }
52
+
53
+ export function createToolcraftSurfaceActionRunner(
54
+ options: ToolcraftBrowserSurfaceActionOptions,
55
+ ): (page: Page) => Promise<void> {
56
+ return async (page) => {
57
+ const locator = page.locator(options.selector);
58
+ await expect(
59
+ locator,
60
+ `Surface action locator "${options.selector}" must resolve exactly once.`,
61
+ ).toHaveCount(1);
62
+ await expect(locator).toBeVisible();
63
+ expect(
64
+ await getToolcraftActionSurface(page, options),
65
+ `Surface action locator "${options.selector}" must live inside the declared ${options.surface} runtime surface.`,
66
+ ).toBe(options.surface);
67
+
68
+ if (options.position) {
69
+ const bounds = await locator.boundingBox();
70
+ expect(bounds).not.toBeNull();
71
+ expect(options.position.x).toBeLessThanOrEqual(bounds!.width);
72
+ expect(options.position.y).toBeLessThanOrEqual(bounds!.height);
73
+ }
74
+
75
+ await locator.click(
76
+ options.position ? { position: options.position } : undefined,
77
+ );
78
+ };
79
+ }