@pixel-point/toolcraft 0.0.16 → 0.0.18
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.
- package/package.json +1 -1
- package/src/generate-performance-iteration-execution.test.mjs +2 -2
- package/src/generate-test-demand-only-lifecycle.mjs +14 -3
- package/src/generate-test-dependency-sandbox.mjs +42 -5
- package/src/generate-test-doc-assertions.mjs +109 -69
- package/src/generate-test-doc-assertions.test.mjs +65 -0
- package/src/generate-test-doc-policy-assertions.mjs +92 -0
- package/src/generate-test-file-assertions.mjs +36 -118
- package/src/generate-test-output-assertions.mjs +95 -0
- package/src/generate-test-package-assertions.mjs +6 -0
- package/src/generate-test-performance-boundary-assertions.mjs +45 -0
- package/src/generate-test-product-fixture.mjs +1 -0
- package/src/generate-test-product-fixture.test.mjs +18 -0
- package/src/generate-test-product-iteration.mjs +1 -0
- package/src/generate-test-product-iteration.test.mjs +18 -0
- package/src/generate-test-runtime-boundary-assertions.mjs +158 -0
- package/src/generate-test-standalone-assertions.mjs +10 -0
- package/src/generate-test-standalone-delivery-stages.mjs +14 -6
- package/src/generate.test.mjs +14 -0
- package/templates/runtime/contracts/component-contracts.choices.test.ts +59 -12
- package/templates/runtime/contracts/component-contracts.choices.ts +58 -12
- package/templates/runtime/contracts/component-contracts.inputs.test.ts +6 -6
- package/templates/runtime/contracts/component-contracts.inputs.ts +6 -6
- package/templates/runtime/contracts/component-contracts.media-custom.test.ts +8 -2
- package/templates/runtime/contracts/component-contracts.media-custom.ts +8 -2
- package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +21 -6
- package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +7 -1
- package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +4 -1
- package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +4 -1
- package/templates/runtime/contracts/component-contracts.runtime.ts +15 -10
- package/templates/runtime/contracts/component-contracts.test.ts +2 -0
- package/templates/runtime/contracts/decision-contracts.test.ts +43 -4
- package/templates/runtime/contracts/decision-contracts.ts +10 -10
- package/templates/runtime/contracts/performance-verification-policy.test.ts +59 -6
- package/templates/runtime/contracts/performance-verification-policy.ts +5 -2
- package/templates/runtime/export/artifact-download.test.ts +71 -0
- package/templates/runtime/export/artifact-download.ts +80 -0
- package/templates/runtime/export/artifact-export-request.ts +23 -0
- package/templates/runtime/export/artifact-export-settings.test.ts +75 -0
- package/templates/runtime/export/artifact-export-settings.ts +96 -0
- package/templates/runtime/export/artifact-frame-renderer.test.ts +107 -0
- package/templates/runtime/export/artifact-frame-renderer.ts +96 -0
- package/templates/runtime/export/artifact-frame-state.test.ts +54 -0
- package/templates/runtime/export/artifact-frame-state.ts +44 -0
- package/templates/runtime/export/artifact-scene-frame.test.ts +84 -0
- package/templates/runtime/export/artifact-scene-frame.ts +118 -0
- package/templates/runtime/export/export-background.ts +46 -0
- package/templates/runtime/export/export-error.ts +43 -0
- package/templates/runtime/export/export.test.ts +49 -226
- package/templates/runtime/export/image-artifact-export.test.ts +111 -0
- package/templates/runtime/export/image-artifact-export.ts +145 -0
- package/templates/runtime/export/index.ts +44 -3
- package/templates/runtime/export/product-export-renderer.test.ts +77 -0
- package/templates/runtime/export/product-export-renderer.ts +63 -0
- package/templates/runtime/export/video-artifact-export.test.ts +166 -0
- package/templates/runtime/export/video-artifact-export.ts +164 -0
- package/templates/runtime/export/video-encoding-backend.ts +124 -0
- package/templates/runtime/export/video-encoding-policy.test.ts +68 -0
- package/templates/runtime/export/video-encoding-policy.ts +86 -0
- package/templates/runtime/export/video-frame-schedule.test.ts +58 -0
- package/templates/runtime/export/video-frame-schedule.ts +42 -0
- package/templates/runtime/index.ts +3 -0
- package/templates/runtime/model-import/model-import-limits.ts +15 -4
- package/templates/runtime/react/app-shell/runtime-public-api-runtime.test.tsx +291 -0
- package/templates/runtime/react/app-shell/runtime-public-api-test-support.ts +21 -0
- package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +15 -304
- package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +41 -27
- package/templates/runtime/react/app-shell/toolcraft-app.tsx +39 -11
- package/templates/runtime/react/app-shell/toolcraft-source-asset-context.test.tsx +16 -57
- package/templates/runtime/react/app-shell/toolcraft-source-asset-context.tsx +75 -434
- package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.test.ts +194 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.ts +227 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-provider-ownership.test.tsx +243 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-test-support.ts +51 -0
- package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.test.ts +138 -0
- package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.ts +378 -0
- package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +76 -0
- package/templates/runtime/react/canvas/canvas-shell-test-utils.tsx +13 -1
- package/templates/runtime/react/canvas/canvas-shell.tsx +16 -1
- package/templates/runtime/react/canvas/product-scene-surface.test.tsx +195 -0
- package/templates/runtime/react/canvas/product-scene-surface.tsx +155 -0
- package/templates/runtime/react/canvas/runtime-scene-export.ts +1 -1
- package/templates/runtime/react/controls-panel/__tests__/control-conditions.test.ts +61 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.collection-actions.test.tsx +89 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.control-visibility.test.tsx +40 -19
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.footer-actions.test.tsx +7 -12
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +18 -84
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +62 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +67 -0
- package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +43 -87
- package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +68 -0
- package/templates/runtime/react/controls-panel/conditions/control-conditions.ts +32 -119
- package/templates/runtime/react/controls-panel/layout/controls-panel-control-group.tsx +5 -2
- package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +10 -8
- package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +3 -3
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.test.tsx +63 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.tsx +138 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-items.tsx +104 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-renderer.tsx +115 -236
- package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.test.tsx +95 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.tsx +82 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.test.tsx +73 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.tsx +50 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.test.ts +1 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.ts +2 -1
- package/templates/runtime/react/controls-panel/values/controls-panel-collection-values.ts +38 -6
- package/templates/runtime/react/controls-panel/values/controls-panel-value-labels.ts +1 -0
- package/templates/runtime/react/index.ts +4 -0
- package/templates/runtime/react/model-rendering/model-export.ts +1 -1
- package/templates/runtime/react/orientation-gizmo/orientation-gizmo-selection.ts +5 -5
- package/templates/runtime/react/orientation-gizmo/use-toolcraft-orientation-control-selection.ts +2 -2
- package/templates/runtime/react/panel-host/panel-host-runtime-placement.test.tsx +30 -0
- package/templates/runtime/react/panel-host/panel-host.tsx +4 -0
- package/templates/runtime/scene/scene-bounds.test.ts +23 -0
- package/templates/runtime/scene/scene-bounds.ts +32 -19
- package/templates/runtime/schema/app-capabilities.test.ts +4 -0
- package/templates/runtime/schema/canvas-render-scale.ts +62 -0
- package/templates/runtime/schema/collection-item-controls.ts +29 -0
- package/templates/runtime/schema/control-applicability.test.ts +127 -0
- package/templates/runtime/schema/control-applicability.ts +433 -0
- package/templates/runtime/schema/control-schema-normalization.ts +177 -11
- package/templates/runtime/schema/controls-panel-actions.ts +2 -2
- package/templates/runtime/schema/controls-panel-section-id.test.ts +1 -1
- package/templates/runtime/schema/controls-panel-section-layout.ts +14 -9
- package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +62 -3
- package/templates/runtime/schema/define-toolcraft.collection-actions-item-controls.test.ts +127 -0
- package/templates/runtime/schema/define-toolcraft.control-sections.test.ts +10 -4
- package/templates/runtime/schema/define-toolcraft.file-drop-item-controls.test.ts +98 -0
- package/templates/runtime/schema/define-toolcraft.file-drop-normalization.test.ts +27 -0
- package/templates/runtime/schema/define-toolcraft.segmented-control-fit.test.ts +20 -2
- package/templates/runtime/schema/define-toolcraft.setup-background.test.ts +1 -1
- package/templates/runtime/schema/define-toolcraft.setup-canvas.test.ts +16 -3
- package/templates/runtime/schema/define-toolcraft.setup-render-scale-timeline.test.ts +71 -3
- package/templates/runtime/schema/define-toolcraft.source-collection.test.ts +79 -0
- package/templates/runtime/schema/define-toolcraft.ts +1 -1
- package/templates/runtime/schema/runtime-setup-section.ts +24 -5
- package/templates/runtime/schema/schema-resolvers.ts +0 -56
- package/templates/runtime/schema/types.ts +72 -17
- package/templates/runtime/state/canvas-background-state.ts +6 -0
- package/templates/runtime/testing/performance-render-plan-integration.test.ts +64 -0
- package/templates/runtime/testing/performance-renderer-pipeline-validation.ts +18 -1
- package/templates/starter/AGENTS.md +18 -15
- package/templates/starter/NOTICE.md +6 -0
- package/templates/starter/docs/toolcraft/README.md +2 -1
- package/templates/starter/docs/toolcraft/acceptance-testing.md +23 -35
- package/templates/starter/docs/toolcraft/agent-worklog.md +18 -3
- package/templates/starter/docs/toolcraft/assembly-workflow.md +13 -5
- package/templates/starter/docs/toolcraft/component-rules.md +8 -6
- package/templates/starter/docs/toolcraft/core/control-selection.md +9 -3
- package/templates/starter/docs/toolcraft/core/layout.md +7 -7
- package/templates/starter/docs/toolcraft/core/media-upload.md +4 -2
- package/templates/starter/docs/toolcraft/core/performance.md +14 -3
- package/templates/starter/docs/toolcraft/core/runtime-boundary.md +16 -3
- package/templates/starter/docs/toolcraft/core/setup-export.md +49 -19
- package/templates/starter/docs/toolcraft/core/timeline-animation.md +4 -4
- package/templates/starter/docs/toolcraft/custom-controls.md +6 -4
- package/templates/starter/docs/toolcraft/decision-contract.md +3 -1
- package/templates/starter/docs/toolcraft/performance.md +20 -6
- package/templates/starter/docs/toolcraft/renderer-technique.md +5 -1
- package/templates/starter/docs/toolcraft/schema-reference.md +23 -25
- package/templates/starter/docs/toolcraft/workflow.md +7 -2
- package/templates/starter/e2e/app-browser-control-applicability-requirements.spec.ts +163 -0
- package/templates/starter/e2e/app-browser-control-coverage.spec.ts +33 -0
- package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +50 -3
- package/templates/starter/e2e/app-browser-orientation-evidence.spec.ts +174 -21
- package/templates/starter/e2e/app-browser-render-scale-evidence.spec.ts +60 -6
- package/templates/starter/e2e/app-browser-render-scale-requirements.spec.ts +77 -1
- package/templates/starter/e2e/app-browser-runtime-provenance.spec.ts +8 -0
- package/templates/starter/e2e/app-browser-runtime-reporter.spec.ts +35 -0
- package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +5 -34
- package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +61 -16
- package/templates/starter/e2e/app-browser-shell.spec.ts +13 -5
- package/templates/starter/e2e/app-performance-path-adapters.ts +8 -1
- package/templates/starter/e2e/app-performance.spec.ts +16 -9
- package/templates/starter/e2e/{browser-conditional-output-evidence-helpers.ts → browser-background-output-evidence.ts} +0 -68
- package/templates/starter/e2e/browser-control-applicability-evidence.ts +114 -0
- package/templates/starter/e2e/browser-infinity-canvas-evidence.ts +29 -341
- package/templates/starter/e2e/browser-infinity-canvas-unavailable-image-evidence.ts +370 -0
- package/templates/starter/e2e/browser-media-export-evidence.spec.ts +77 -0
- package/templates/starter/e2e/browser-media-export-evidence.ts +208 -0
- package/templates/starter/e2e/browser-orientation-gizmo-evidence-helpers.ts +4 -0
- package/templates/starter/e2e/browser-orientation-gizmo-live-preconditions.ts +86 -0
- package/templates/starter/e2e/browser-render-scale-evidence.ts +37 -29
- package/templates/starter/e2e/browser-runtime-applicability-requirements.ts +84 -0
- package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +13 -3
- package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +72 -35
- package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +25 -0
- package/templates/starter/e2e/browser-standard-timeline-evidence.ts +106 -0
- package/templates/starter/e2e/decoded-pixel-observation.spec.ts +74 -0
- package/templates/starter/e2e/decoded-pixel-observation.ts +227 -0
- package/templates/starter/e2e/export-artifact-helpers.ts +206 -25
- package/templates/starter/e2e/image-artifact-inspection.spec.ts +41 -0
- package/templates/starter/e2e/image-artifact-inspection.ts +99 -0
- package/templates/starter/e2e/performance-canvas-helpers.ts +22 -21
- package/templates/starter/e2e/performance-canvas-quality-guard.spec.ts +312 -0
- package/templates/starter/e2e/performance-canvas-quality-guard.ts +196 -0
- package/templates/starter/e2e/performance-canvas-quality-observer.ts +351 -0
- package/templates/starter/e2e/performance-control-layout-helpers.ts +2 -2
- package/templates/starter/e2e/performance-path-adapter-contract.ts +4 -4
- package/templates/starter/e2e/performance-path-helpers.spec.ts +203 -70
- package/templates/starter/e2e/performance-path-helpers.ts +210 -91
- package/templates/starter/e2e/performance-pipeline-evidence-continuity.spec.ts +76 -0
- package/templates/starter/e2e/performance-pipeline-evidence-test-fixtures.ts +11 -2
- package/templates/starter/e2e/performance-pipeline-invariants.ts +47 -4
- package/templates/starter/e2e/performance-render-scale-runner.spec.ts +140 -38
- package/templates/starter/e2e/video-artifact-inspection.spec.ts +64 -0
- package/templates/starter/e2e/video-artifact-inspection.ts +281 -0
- package/templates/starter/gitignore +1 -0
- package/templates/starter/package.json +1 -0
- package/templates/starter/scripts/check-toolcraft-docs.mjs +17 -0
- package/templates/starter/scripts/toolcraft-contract-manifest.json +1 -0
- package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +60 -0
- package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +7 -2
- package/templates/starter/scripts/toolcraft-delivery-plan.mjs +7 -3
- package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +95 -103
- package/templates/starter/scripts/toolcraft-product-boundary-module-policy.mjs +101 -0
- package/templates/starter/scripts/toolcraft-product-boundary.mjs +12 -0
- package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +0 -26
- package/templates/starter/scripts/toolcraft-product-control-bindings.mjs +182 -0
- package/templates/starter/scripts/toolcraft-product-control-boundary.mjs +146 -0
- package/templates/starter/scripts/toolcraft-product-control-boundary.test.mjs +186 -0
- package/templates/starter/scripts/toolcraft-product-evidence-boundary.test.mjs +85 -20
- package/templates/starter/scripts/toolcraft-product-evidence-import-policy.mjs +43 -0
- package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +157 -0
- package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +196 -0
- package/templates/starter/scripts/toolcraft-typescript-analysis.d.mts +73 -0
- package/templates/starter/scripts/toolcraft-typescript-source-evidence-structure.test.mjs +20 -0
- package/templates/starter/scripts/toolcraft-typescript-source-evidence.mjs +1 -0
- package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade-test-helpers.mjs +318 -0
- package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade.test.mjs +157 -206
- package/templates/starter/scripts/toolcraft-verification-inventory.mjs +1 -0
- package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +51 -0
- package/templates/starter/scripts/toolcraft-vite-env-activation.test.mjs +128 -59
- package/templates/starter/src/app/acceptance/artifact-export-intent.ts +130 -0
- package/templates/starter/src/app/acceptance/conditions.ts +1 -1
- package/templates/starter/src/app/acceptance/control-acceptance-context.ts +2 -2
- package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +6 -20
- package/templates/starter/src/app/acceptance/control-acceptance-kind-rules.ts +24 -5
- package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +2 -13
- package/templates/starter/src/app/acceptance/control-applicability-cases.test.ts +321 -0
- package/templates/starter/src/app/acceptance/control-applicability-cases.ts +290 -0
- package/templates/starter/src/app/acceptance/control-applicability.ts +332 -0
- package/templates/starter/src/app/acceptance/control-layout-dependency-rules.ts +20 -9
- package/templates/starter/src/app/acceptance/control-layout-entity-rules.ts +4 -6
- package/templates/starter/src/app/acceptance/control-layout-model.ts +4 -4
- package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +3 -10
- package/templates/starter/src/app/acceptance/control-parts.ts +8 -0
- package/templates/starter/src/app/acceptance/control-section-entity-cohesion.test.ts +215 -0
- package/templates/starter/src/app/acceptance/control-section-entity-cohesion.ts +132 -0
- package/templates/starter/src/app/acceptance/control-section-inventory.test.ts +87 -0
- package/templates/starter/src/app/acceptance/control-section-inventory.ts +74 -44
- package/templates/starter/src/app/acceptance/custom-controls.ts +11 -3
- package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +113 -0
- package/templates/starter/src/app/acceptance/inline-layout.ts +64 -9
- package/templates/starter/src/app/acceptance/media-upload.ts +5 -1
- package/templates/starter/src/app/acceptance/orientation-gizmo.ts +18 -11
- package/templates/starter/src/app/acceptance/output-background-rules.ts +2 -2
- package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +18 -10
- package/templates/starter/src/app/acceptance/output-export-model.ts +54 -11
- package/templates/starter/src/app/acceptance/output-export.ts +35 -12
- package/templates/starter/src/app/acceptance/output-video-export-rules.ts +99 -0
- package/templates/starter/src/app/acceptance/types.ts +30 -8
- package/templates/starter/src/app/acceptance/validate-coverage.ts +20 -2
- package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +239 -0
- package/templates/starter/src/app/starter-acceptance.background-export.test.ts +33 -0
- package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +16 -1
- package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +65 -0
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.test.ts +41 -0
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +112 -16
- package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +224 -0
- package/templates/starter/src/app/starter-acceptance.control-order.test.ts +58 -3
- package/templates/starter/src/app/starter-acceptance.control-state.test.ts +0 -111
- package/templates/starter/src/app/starter-acceptance.custom-control-collections.test.ts +3 -1
- package/templates/starter/src/app/starter-acceptance.custom-control-valid.test.ts +1 -1
- package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +131 -0
- package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +22 -0
- package/templates/starter/src/app/{starter-acceptance.image-video-export-settings.test.ts → starter-acceptance.image-export-settings.test.ts} +37 -9
- package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +12 -0
- package/templates/starter/src/app/starter-acceptance.keyframes.test.ts +14 -4
- package/templates/starter/src/app/starter-acceptance.media-upload.fixtures.ts +11 -1
- package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +28 -0
- package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +384 -0
- package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +46 -1
- package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +112 -105
- package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +12 -0
- package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +1 -1
- package/templates/starter/src/app/starter-acceptance.section-dependencies.test.ts +35 -24
- package/templates/starter/src/app/starter-acceptance.section-size.test.ts +72 -0
- package/templates/starter/src/app/starter-acceptance.ts +13 -2
- package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +336 -0
- package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +8 -0
- package/templates/starter/src/app/starter-performance-test-utils.ts +103 -0
- package/templates/starter/src/app/starter-performance.gates.test.ts +231 -278
- package/templates/starter/src/app/starter-performance.lifecycle.test.ts +261 -0
- package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +4 -2
- package/templates/starter/src/routes/index.tsx +2 -0
- package/templates/ui/components/composites/tabs.tsx +2 -2
- package/templates/ui/components/controls/collection-actions/collection-item-groups.test.tsx +38 -0
- package/templates/ui/components/controls/collection-actions/collection-item-groups.tsx +36 -0
- package/templates/ui/components/controls/collection-actions/index.ts +2 -0
- package/templates/ui/components/controls/file-drop/file-drop-collection-control.tsx +137 -0
- package/templates/ui/components/controls/file-drop/file-drop-control.test.tsx +189 -0
- package/templates/ui/components/controls/file-drop/file-drop-control.tsx +81 -88
- package/templates/ui/components/controls/file-drop/file-drop-presentation.tsx +131 -9
- package/templates/ui/components/controls/file-drop/file-drop-types.ts +36 -22
- package/templates/ui/components/controls/file-drop/index.ts +1 -0
- package/templates/ui/components/controls/index.ts +3 -0
- package/templates/ui/components/controls/range-slider/range-slider-control.tsx +1 -1
- package/templates/ui/components/controls/range-slider/range-slider-value.test.ts +14 -0
- package/templates/ui/components/controls/range-slider/range-slider-value.ts +3 -2
- package/templates/runtime/export/export.ts +0 -166
- package/templates/starter/src/app/acceptance/condition-exclusivity.test.ts +0 -60
- package/templates/starter/src/app/acceptance/condition-exclusivity.ts +0 -221
|
@@ -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
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { expect, type Page } from "@playwright/test";
|
|
2
|
-
import
|
|
2
|
+
import { TOOLCRAFT_CANVAS_RENDER_SCALE } from "@repo/toolcraft-runtime";
|
|
3
3
|
|
|
4
|
+
import type { ToolcraftPerformancePipelinePhase } from "../src/app/test-evidence/browser-performance-contract";
|
|
4
5
|
import type { ToolcraftRenderScaleState } from "../src/app/starter-acceptance";
|
|
5
6
|
import { attachToolcraftBrowserRuntimeEvidence } from "./browser-runtime-evidence";
|
|
6
7
|
|
|
7
|
-
type
|
|
8
|
+
export type ToolcraftCanvasBackingMetrics = Readonly<{
|
|
8
9
|
backingHeight: number;
|
|
9
10
|
backingWidth: number;
|
|
10
11
|
cssHeight: number;
|
|
@@ -12,6 +13,8 @@ type CanvasMetrics = Readonly<{
|
|
|
12
13
|
devicePixelRatio: number;
|
|
13
14
|
}>;
|
|
14
15
|
|
|
16
|
+
export type ToolcraftCanvasVisibleSizePolicy = "fixed" | "viewport-driven";
|
|
17
|
+
|
|
15
18
|
export type ToolcraftRenderScaleStateTransition = Readonly<{
|
|
16
19
|
run: () => Promise<void>;
|
|
17
20
|
state: ToolcraftRenderScaleState;
|
|
@@ -19,20 +22,12 @@ export type ToolcraftRenderScaleStateTransition = Readonly<{
|
|
|
19
22
|
|
|
20
23
|
export type ToolcraftRenderScaleBackingOptions = Readonly<{
|
|
21
24
|
baselineCssSize?: Readonly<{ height: number; width: number }>;
|
|
22
|
-
state?:
|
|
25
|
+
state?:
|
|
26
|
+
| ToolcraftRenderScaleState
|
|
27
|
+
| "performance-baseline"
|
|
28
|
+
| `performance-${ToolcraftPerformancePipelinePhase}`;
|
|
23
29
|
}>;
|
|
24
30
|
|
|
25
|
-
export function isToolcraftRenderScalePerformancePath(
|
|
26
|
-
path: Pick<ToolcraftPerformancePath, "targets" | "workloadDimensions">,
|
|
27
|
-
): boolean {
|
|
28
|
-
return (
|
|
29
|
-
path.targets.includes("canvas.renderScale") ||
|
|
30
|
-
path.workloadDimensions.some((dimension) =>
|
|
31
|
-
/render[-_.]?scale|resolution[-_.]?scale/iu.test(dimension),
|
|
32
|
-
)
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
31
|
function assertPositiveFiniteScale(selectedScale: number): void {
|
|
37
32
|
if (!Number.isFinite(selectedScale) || selectedScale <= 0) {
|
|
38
33
|
throw new Error(
|
|
@@ -64,7 +59,7 @@ export function assertToolcraftRenderScaleBackingProofConfig(
|
|
|
64
59
|
async function readCanvasMetrics(
|
|
65
60
|
page: Page,
|
|
66
61
|
canvasSelector: string,
|
|
67
|
-
): Promise<
|
|
62
|
+
): Promise<ToolcraftCanvasBackingMetrics> {
|
|
68
63
|
if (!canvasSelector.trim()) {
|
|
69
64
|
throw new Error(
|
|
70
65
|
"Toolcraft canvas backing-pixel checks require a non-empty canvas selector.",
|
|
@@ -95,8 +90,8 @@ async function readCanvasMetrics(
|
|
|
95
90
|
});
|
|
96
91
|
}
|
|
97
92
|
|
|
98
|
-
function
|
|
99
|
-
metrics:
|
|
93
|
+
export function assertToolcraftCanvasBackingMetricsForRenderScale(
|
|
94
|
+
metrics: ToolcraftCanvasBackingMetrics,
|
|
100
95
|
selectedScale: number,
|
|
101
96
|
options: ToolcraftRenderScaleBackingOptions,
|
|
102
97
|
): void {
|
|
@@ -128,14 +123,16 @@ function assertBackingMetrics(
|
|
|
128
123
|
metrics.cssWidth * metrics.devicePixelRatio * selectedScale;
|
|
129
124
|
const expectedHeight =
|
|
130
125
|
metrics.cssHeight * metrics.devicePixelRatio * selectedScale;
|
|
126
|
+
const widthError = Math.abs(metrics.backingWidth - expectedWidth);
|
|
127
|
+
const heightError = Math.abs(metrics.backingHeight - expectedHeight);
|
|
131
128
|
expect(
|
|
132
|
-
|
|
133
|
-
`${stateLabel} expected canvas backing width
|
|
134
|
-
).
|
|
129
|
+
widthError,
|
|
130
|
+
`${stateLabel} expected exact canvas backing width within one physical pixel for Resolution scale ${selectedScale}.`,
|
|
131
|
+
).toBeLessThanOrEqual(1);
|
|
135
132
|
expect(
|
|
136
|
-
|
|
137
|
-
`${stateLabel} expected canvas backing height
|
|
138
|
-
).
|
|
133
|
+
heightError,
|
|
134
|
+
`${stateLabel} expected exact canvas backing height within one physical pixel for Resolution scale ${selectedScale}.`,
|
|
135
|
+
).toBeLessThanOrEqual(1);
|
|
139
136
|
}
|
|
140
137
|
|
|
141
138
|
export async function expectToolcraftCanvasBackingPixelsForRenderScale(
|
|
@@ -146,7 +143,11 @@ export async function expectToolcraftCanvasBackingPixelsForRenderScale(
|
|
|
146
143
|
): Promise<Readonly<{ height: number; width: number }>> {
|
|
147
144
|
assertPositiveFiniteScale(selectedScale);
|
|
148
145
|
const metrics = await readCanvasMetrics(page, canvasSelector);
|
|
149
|
-
|
|
146
|
+
assertToolcraftCanvasBackingMetricsForRenderScale(
|
|
147
|
+
metrics,
|
|
148
|
+
selectedScale,
|
|
149
|
+
options,
|
|
150
|
+
);
|
|
150
151
|
return { height: metrics.cssHeight, width: metrics.cssWidth };
|
|
151
152
|
}
|
|
152
153
|
|
|
@@ -216,13 +217,17 @@ export async function expectToolcraftPerformanceRenderScaleBackingEvidence(
|
|
|
216
217
|
page: Page,
|
|
217
218
|
{
|
|
218
219
|
canvasSelector,
|
|
220
|
+
baselineCssSize,
|
|
221
|
+
cssSizePolicy,
|
|
219
222
|
pathId,
|
|
220
|
-
|
|
223
|
+
phase,
|
|
221
224
|
target,
|
|
222
225
|
}: Readonly<{
|
|
226
|
+
baselineCssSize: Readonly<{ height: number; width: number }>;
|
|
223
227
|
canvasSelector: string;
|
|
228
|
+
cssSizePolicy: ToolcraftCanvasVisibleSizePolicy;
|
|
224
229
|
pathId: string;
|
|
225
|
-
|
|
230
|
+
phase: ToolcraftPerformancePipelinePhase;
|
|
226
231
|
target?: string;
|
|
227
232
|
}>,
|
|
228
233
|
): Promise<void> {
|
|
@@ -234,12 +239,15 @@ export async function expectToolcraftPerformanceRenderScaleBackingEvidence(
|
|
|
234
239
|
await expectToolcraftCanvasBackingPixelsForRenderScale(
|
|
235
240
|
page,
|
|
236
241
|
canvasSelector,
|
|
237
|
-
|
|
238
|
-
{
|
|
242
|
+
TOOLCRAFT_CANVAS_RENDER_SCALE.defaultValue,
|
|
243
|
+
{
|
|
244
|
+
...(cssSizePolicy === "fixed" ? { baselineCssSize } : {}),
|
|
245
|
+
state: `performance-${phase}`,
|
|
246
|
+
},
|
|
239
247
|
);
|
|
240
248
|
await attachToolcraftBrowserRuntimeEvidence({
|
|
241
249
|
evidenceType: "performance-render-scale",
|
|
242
|
-
requirementId: pathId
|
|
250
|
+
requirementId: `${pathId}#${phase}`,
|
|
243
251
|
target,
|
|
244
252
|
});
|
|
245
253
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { ResolvedToolcraftAppSchema } from "@repo/toolcraft-runtime";
|
|
2
|
+
|
|
3
|
+
import type { ToolcraftBrowserRuntimeRequirement } from "../src/app/test-evidence/browser-runtime-contract";
|
|
4
|
+
import {
|
|
5
|
+
getToolcraftApplicabilityRequirementId,
|
|
6
|
+
getToolcraftControlApplicabilityCases,
|
|
7
|
+
type ToolcraftComponentAcceptance,
|
|
8
|
+
type ToolcraftControlSectionInventoryEntry,
|
|
9
|
+
} from "../src/app/starter-acceptance";
|
|
10
|
+
|
|
11
|
+
type ApplicabilityAcceptanceSource = Pick<
|
|
12
|
+
ToolcraftComponentAcceptance,
|
|
13
|
+
"browserTestName" | "id" | "kind" | "target"
|
|
14
|
+
>;
|
|
15
|
+
|
|
16
|
+
const layoutOnlyEvidenceTypes = new Set<
|
|
17
|
+
ToolcraftBrowserRuntimeRequirement["evidenceType"]
|
|
18
|
+
>(["discrete-slider-layout", "segmented-control-layout"]);
|
|
19
|
+
|
|
20
|
+
export function expandToolcraftControlApplicabilityRequirements({
|
|
21
|
+
entry,
|
|
22
|
+
schema,
|
|
23
|
+
sectionInventory,
|
|
24
|
+
templates,
|
|
25
|
+
}: Readonly<{
|
|
26
|
+
entry: ApplicabilityAcceptanceSource;
|
|
27
|
+
schema?: Pick<ResolvedToolcraftAppSchema, "panels">;
|
|
28
|
+
sectionInventory: readonly ToolcraftControlSectionInventoryEntry[];
|
|
29
|
+
templates: readonly ToolcraftBrowserRuntimeRequirement[];
|
|
30
|
+
}>): ToolcraftBrowserRuntimeRequirement[] {
|
|
31
|
+
if (!schema || entry.kind !== "control" || !entry.target) {
|
|
32
|
+
return [...templates];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const cases = getToolcraftControlApplicabilityCases({
|
|
36
|
+
schema,
|
|
37
|
+
sectionInventory,
|
|
38
|
+
target: entry.target,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (cases.length === 0) {
|
|
42
|
+
return [...templates];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const hasOutcomeRequirement = templates.some(
|
|
46
|
+
(requirement) => !layoutOnlyEvidenceTypes.has(requirement.evidenceType),
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return cases.flatMap((applicabilityCase) => {
|
|
50
|
+
const visibilityRequirement = {
|
|
51
|
+
evidenceType:
|
|
52
|
+
applicabilityCase.expectation === "hidden"
|
|
53
|
+
? ("control-applicability-hidden" as const)
|
|
54
|
+
: ("control-applicability-visible" as const),
|
|
55
|
+
requirementId: getToolcraftApplicabilityRequirementId(
|
|
56
|
+
entry.id,
|
|
57
|
+
applicabilityCase,
|
|
58
|
+
),
|
|
59
|
+
target: entry.target,
|
|
60
|
+
testName: entry.browserTestName,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (applicabilityCase.expectation === "hidden") {
|
|
64
|
+
return [visibilityRequirement];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!hasOutcomeRequirement) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Visible applicability case for ${entry.id} has no product outcome requirement.`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return [
|
|
74
|
+
visibilityRequirement,
|
|
75
|
+
...templates.map((requirement) => ({
|
|
76
|
+
...requirement,
|
|
77
|
+
requirementId: getToolcraftApplicabilityRequirementId(
|
|
78
|
+
requirement.requirementId,
|
|
79
|
+
applicabilityCase,
|
|
80
|
+
),
|
|
81
|
+
})),
|
|
82
|
+
];
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -19,7 +19,10 @@ import {
|
|
|
19
19
|
type ToolcraftBrowserRuntimeRequirement,
|
|
20
20
|
type ToolcraftBrowserRuntimeTest,
|
|
21
21
|
} from "../src/app/test-evidence/browser-runtime-contract";
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
starterAcceptance,
|
|
24
|
+
starterControlSectionInventory,
|
|
25
|
+
} from "../src/app/starter-acceptance";
|
|
23
26
|
import { starterPerformance } from "../src/app/starter-performance";
|
|
24
27
|
import { starterSchema } from "../src/app/starter-schema";
|
|
25
28
|
import {
|
|
@@ -166,14 +169,21 @@ export default class ToolcraftBrowserRuntimeEvidenceReporter implements Reporter
|
|
|
166
169
|
this.performanceSchema = this.performanceSchemaOverride ?? starterSchema;
|
|
167
170
|
this.acceptanceRequirements =
|
|
168
171
|
this.acceptanceRequirementsOverride ??
|
|
169
|
-
deriveToolcraftBrowserRuntimeRequirements(
|
|
172
|
+
deriveToolcraftBrowserRuntimeRequirements(
|
|
173
|
+
starterAcceptance,
|
|
174
|
+
starterSchema,
|
|
175
|
+
starterControlSectionInventory,
|
|
176
|
+
);
|
|
170
177
|
this.canonicalPaths = deriveToolcraftPerformancePaths(
|
|
171
178
|
this.performanceSchema,
|
|
172
179
|
this.performanceConfig,
|
|
173
180
|
);
|
|
174
181
|
this.performanceRequirements =
|
|
175
182
|
this.performanceRequirementsOverride ??
|
|
176
|
-
deriveToolcraftPerformancePathRuntimeRequirements(
|
|
183
|
+
deriveToolcraftPerformancePathRuntimeRequirements(
|
|
184
|
+
this.canonicalPaths,
|
|
185
|
+
this.performanceSchema,
|
|
186
|
+
);
|
|
177
187
|
}
|
|
178
188
|
|
|
179
189
|
onEnd(_result: FullResult): { status: "failed" } | undefined {
|
|
@@ -3,20 +3,23 @@ import type {
|
|
|
3
3
|
ToolcraftPerformancePath,
|
|
4
4
|
} from "@repo/toolcraft-runtime";
|
|
5
5
|
|
|
6
|
+
import {
|
|
7
|
+
TOOLCRAFT_PERFORMANCE_PIPELINE_PHASES,
|
|
8
|
+
} from "../src/app/test-evidence/browser-performance-contract";
|
|
6
9
|
import type { ToolcraftBrowserRuntimeRequirement } from "../src/app/test-evidence/browser-runtime-contract";
|
|
7
10
|
import { schemaHasVideoExportPanelAction } from "../src/app/acceptance/output-export";
|
|
8
11
|
import {
|
|
9
12
|
getRequiredToolcraftControlPartCoverage,
|
|
10
13
|
type ToolcraftBackgroundOutputCoverage,
|
|
11
14
|
type ToolcraftComponentAcceptance,
|
|
12
|
-
type
|
|
15
|
+
type ToolcraftControlSectionInventoryEntry,
|
|
13
16
|
type ToolcraftInfinityCanvasCoverage,
|
|
14
17
|
type ToolcraftModelImportCoverage,
|
|
15
18
|
type ToolcraftOrientationGizmoCoverage,
|
|
16
19
|
type ToolcraftTimelinePlaybackCoverage,
|
|
17
20
|
TOOLCRAFT_REQUIRED_MODEL_IMPORT_COVERAGE,
|
|
18
21
|
} from "../src/app/starter-acceptance";
|
|
19
|
-
import {
|
|
22
|
+
import { expandToolcraftControlApplicabilityRequirements } from "./browser-runtime-applicability-requirements";
|
|
20
23
|
import { getToolcraftPerformancePathTestName } from "./performance-path-helpers";
|
|
21
24
|
|
|
22
25
|
type BrowserAcceptanceRequirementSource = Pick<
|
|
@@ -27,6 +30,7 @@ type BrowserAcceptanceRequirementSource = Pick<
|
|
|
27
30
|
| "canvasHandle"
|
|
28
31
|
| "controlPartCoverage"
|
|
29
32
|
| "evidence"
|
|
33
|
+
| "exportArtifactCoverage"
|
|
30
34
|
| "id"
|
|
31
35
|
| "infinityCanvasCoverage"
|
|
32
36
|
| "layerCoverage"
|
|
@@ -38,10 +42,14 @@ type BrowserAcceptanceRequirementSource = Pick<
|
|
|
38
42
|
| "target"
|
|
39
43
|
| "timelineCoverage"
|
|
40
44
|
| "timelinePlaybackCoverage"
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
> & {
|
|
46
|
+
kind?: ToolcraftComponentAcceptance["kind"];
|
|
47
|
+
};
|
|
43
48
|
|
|
44
|
-
type BrowserSchemaRequirementSource = Pick<
|
|
49
|
+
type BrowserSchemaRequirementSource = Pick<
|
|
50
|
+
ResolvedToolcraftAppSchema,
|
|
51
|
+
"canvas" | "panels"
|
|
52
|
+
>;
|
|
45
53
|
|
|
46
54
|
function getAcceptanceEvidenceType(
|
|
47
55
|
evidence: ToolcraftComponentAcceptance["evidence"],
|
|
@@ -90,18 +98,6 @@ const timelinePlaybackCoverage = Object.keys(
|
|
|
90
98
|
timelineEvidenceTypeByCoverage,
|
|
91
99
|
) as Array<keyof typeof timelineEvidenceTypeByCoverage>;
|
|
92
100
|
|
|
93
|
-
const conditionalVisibilityEvidenceTypeByCoverage = {
|
|
94
|
-
hidden: "conditional-control-hidden",
|
|
95
|
-
visible: "conditional-control-visible",
|
|
96
|
-
} as const satisfies Record<
|
|
97
|
-
ToolcraftConditionalVisibilityCoverage,
|
|
98
|
-
ToolcraftBrowserRuntimeRequirement["evidenceType"]
|
|
99
|
-
>;
|
|
100
|
-
|
|
101
|
-
const conditionalVisibilityCoverage = Object.keys(
|
|
102
|
-
conditionalVisibilityEvidenceTypeByCoverage,
|
|
103
|
-
) as ToolcraftConditionalVisibilityCoverage[];
|
|
104
|
-
|
|
105
101
|
const backgroundOutputEvidenceTypeByCoverage = {
|
|
106
102
|
"image-transparent-when-excluded": "background-image-transparency",
|
|
107
103
|
"infinity-viewport-color-and-dependency": "background-infinity-viewport",
|
|
@@ -167,7 +163,7 @@ const modelImportEvidenceTypeByCoverage = {
|
|
|
167
163
|
ToolcraftBrowserRuntimeRequirement["evidenceType"]
|
|
168
164
|
>;
|
|
169
165
|
|
|
170
|
-
|
|
166
|
+
function deriveUnqualifiedToolcraftBrowserRuntimeRequirements(
|
|
171
167
|
acceptance: readonly BrowserAcceptanceRequirementSource[],
|
|
172
168
|
schema?: BrowserSchemaRequirementSource,
|
|
173
169
|
): ToolcraftBrowserRuntimeRequirement[] {
|
|
@@ -188,7 +184,25 @@ export function deriveToolcraftBrowserRuntimeRequirements(
|
|
|
188
184
|
entry.orientationGizmoCoverage !== undefined;
|
|
189
185
|
const evidenceTypes: ToolcraftBrowserRuntimeRequirement["evidenceType"][] = [];
|
|
190
186
|
const baseEvidenceType = getAcceptanceEvidenceType(entry.evidence);
|
|
191
|
-
|
|
187
|
+
const exportArtifactCoverage = entry.exportArtifactCoverage
|
|
188
|
+
? typeof entry.exportArtifactCoverage === "string"
|
|
189
|
+
? [entry.exportArtifactCoverage]
|
|
190
|
+
: entry.exportArtifactCoverage
|
|
191
|
+
: [];
|
|
192
|
+
if (
|
|
193
|
+
baseEvidenceType &&
|
|
194
|
+
entry.renderScaleCoverage === undefined &&
|
|
195
|
+
exportArtifactCoverage.length === 0
|
|
196
|
+
) {
|
|
197
|
+
evidenceTypes.push(baseEvidenceType);
|
|
198
|
+
}
|
|
199
|
+
for (const coverage of exportArtifactCoverage) {
|
|
200
|
+
evidenceTypes.push(
|
|
201
|
+
coverage === "all-required-image-export-behavior"
|
|
202
|
+
? "image-export-artifact"
|
|
203
|
+
: "video-export-artifact",
|
|
204
|
+
);
|
|
205
|
+
}
|
|
192
206
|
|
|
193
207
|
if (entry.canvasHandle && !hasOrientationCoverage) {
|
|
194
208
|
evidenceTypes.push("canvas-handle-interaction");
|
|
@@ -216,15 +230,6 @@ export function deriveToolcraftBrowserRuntimeRequirements(
|
|
|
216
230
|
if (entry.referenceCoverage || entry.referenceTimelineCoverage) {
|
|
217
231
|
evidenceTypes.push("reference-parity");
|
|
218
232
|
}
|
|
219
|
-
const visibilityCoverage =
|
|
220
|
-
entry.visibilityCoverage === "all-conditional-visibility"
|
|
221
|
-
? conditionalVisibilityCoverage
|
|
222
|
-
: entry.visibilityCoverage ?? [];
|
|
223
|
-
evidenceTypes.push(
|
|
224
|
-
...visibilityCoverage.map(
|
|
225
|
-
(item) => conditionalVisibilityEvidenceTypeByCoverage[item],
|
|
226
|
-
),
|
|
227
|
-
);
|
|
228
233
|
const backgroundCoverage =
|
|
229
234
|
entry.backgroundOutputCoverage === "all-required-background-output"
|
|
230
235
|
? backgroundOutputCoverage.filter(
|
|
@@ -321,7 +326,28 @@ export function deriveToolcraftBrowserRuntimeRequirements(
|
|
|
321
326
|
});
|
|
322
327
|
}
|
|
323
328
|
|
|
324
|
-
|
|
329
|
+
export function deriveToolcraftBrowserRuntimeRequirements(
|
|
330
|
+
acceptance: readonly BrowserAcceptanceRequirementSource[],
|
|
331
|
+
schema?: BrowserSchemaRequirementSource,
|
|
332
|
+
sectionInventory: readonly ToolcraftControlSectionInventoryEntry[] = [],
|
|
333
|
+
): ToolcraftBrowserRuntimeRequirement[] {
|
|
334
|
+
return acceptance.flatMap((entry) => {
|
|
335
|
+
const templates = deriveUnqualifiedToolcraftBrowserRuntimeRequirements(
|
|
336
|
+
[entry],
|
|
337
|
+
schema,
|
|
338
|
+
);
|
|
339
|
+
return expandToolcraftControlApplicabilityRequirements({
|
|
340
|
+
entry,
|
|
341
|
+
schema,
|
|
342
|
+
sectionInventory,
|
|
343
|
+
templates,
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const pathProductOutcomeInteractions = new Set<
|
|
349
|
+
ToolcraftPerformancePath["interaction"]
|
|
350
|
+
>([
|
|
325
351
|
"control-change",
|
|
326
352
|
"control-drag",
|
|
327
353
|
"mask-drag",
|
|
@@ -332,6 +358,7 @@ const pathProductOutcomeInteractions = new Set<ToolcraftPerformancePath["interac
|
|
|
332
358
|
|
|
333
359
|
export function deriveToolcraftPerformancePathRuntimeRequirements(
|
|
334
360
|
paths: readonly ToolcraftPerformancePath[],
|
|
361
|
+
schema: ResolvedToolcraftAppSchema,
|
|
335
362
|
): ToolcraftBrowserRuntimeRequirement[] {
|
|
336
363
|
return paths.flatMap((path) => {
|
|
337
364
|
const evidenceTypes: ToolcraftBrowserRuntimeRequirement["evidenceType"][] = [
|
|
@@ -353,19 +380,29 @@ export function deriveToolcraftPerformancePathRuntimeRequirements(
|
|
|
353
380
|
if (path.interaction === "animation-frame") {
|
|
354
381
|
evidenceTypes.push("performance-animation-frames");
|
|
355
382
|
}
|
|
356
|
-
if (
|
|
383
|
+
if (
|
|
384
|
+
path.interaction === "viewport-drag" ||
|
|
385
|
+
path.interaction === "viewport-zoom"
|
|
386
|
+
) {
|
|
357
387
|
evidenceTypes.push("performance-viewport");
|
|
358
388
|
}
|
|
359
|
-
if (isToolcraftRenderScalePerformancePath(path)) {
|
|
360
|
-
evidenceTypes.push("performance-render-scale");
|
|
361
|
-
}
|
|
362
|
-
|
|
363
389
|
const target = path.targets.length === 1 ? path.targets[0] : undefined;
|
|
364
|
-
|
|
390
|
+
const requirements = evidenceTypes.map((evidenceType) => ({
|
|
365
391
|
evidenceType,
|
|
366
392
|
requirementId: path.id,
|
|
367
393
|
target,
|
|
368
394
|
testName: getToolcraftPerformancePathTestName(path),
|
|
369
395
|
}));
|
|
396
|
+
if (schema.canvas.renderScale.enabled) {
|
|
397
|
+
for (const phase of TOOLCRAFT_PERFORMANCE_PIPELINE_PHASES) {
|
|
398
|
+
requirements.push({
|
|
399
|
+
evidenceType: "performance-render-scale",
|
|
400
|
+
requirementId: `${path.id}#${phase}`,
|
|
401
|
+
target,
|
|
402
|
+
testName: getToolcraftPerformancePathTestName(path),
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return requirements;
|
|
370
407
|
});
|
|
371
408
|
}
|
|
@@ -55,3 +55,28 @@ export async function setSyntheticControlOwner(
|
|
|
55
55
|
{ target, visible },
|
|
56
56
|
);
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
export async function setSyntheticSwitchControlOwner(
|
|
60
|
+
page: Page,
|
|
61
|
+
target: string,
|
|
62
|
+
checked: boolean,
|
|
63
|
+
): Promise<void> {
|
|
64
|
+
await setSyntheticControlOwner(page, target, true);
|
|
65
|
+
await page.locator("[data-synthetic-target]").evaluateAll(
|
|
66
|
+
(owners, entry) => {
|
|
67
|
+
const owner = owners.find(
|
|
68
|
+
(candidate) =>
|
|
69
|
+
candidate.getAttribute("data-synthetic-target") === entry.target,
|
|
70
|
+
);
|
|
71
|
+
const button = owner?.querySelector("button");
|
|
72
|
+
|
|
73
|
+
if (!button) {
|
|
74
|
+
throw new Error(`Missing synthetic switch owner ${entry.target}.`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
button.setAttribute("aria-checked", String(entry.checked));
|
|
78
|
+
button.setAttribute("role", "switch");
|
|
79
|
+
},
|
|
80
|
+
{ checked, target },
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { expect } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
import { attachToolcraftBrowserRuntimeEvidence } from "./browser-runtime-evidence";
|
|
4
|
+
import {
|
|
5
|
+
getToolcraftBrowserProofPage,
|
|
6
|
+
type ToolcraftBrowserProofSession,
|
|
7
|
+
} from "./browser-proof-session";
|
|
8
|
+
|
|
9
|
+
async function readMarkerSignature(
|
|
10
|
+
page: Awaited<ReturnType<typeof getToolcraftBrowserProofPage>>,
|
|
11
|
+
markerSelector: string,
|
|
12
|
+
): Promise<string> {
|
|
13
|
+
return page.locator(markerSelector).evaluate((element) => {
|
|
14
|
+
const node = element as HTMLElement;
|
|
15
|
+
return `${node.dataset.timelineProgress ?? "missing"}:${node.style.transform || node.style.left}`;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function expectToolcraftStandardTimelinePlayback(
|
|
20
|
+
session: ToolcraftBrowserProofSession,
|
|
21
|
+
options: Readonly<{
|
|
22
|
+
markerSelector: string;
|
|
23
|
+
requirementId: string;
|
|
24
|
+
}>,
|
|
25
|
+
): Promise<void> {
|
|
26
|
+
const page = await getToolcraftBrowserProofPage(session);
|
|
27
|
+
const scrubber = page.getByRole("slider", { name: "Playback position" });
|
|
28
|
+
if (!(await scrubber.isVisible())) {
|
|
29
|
+
await page
|
|
30
|
+
.locator('[data-toolcraft-control-target="panels.timeline.extended"]')
|
|
31
|
+
.getByRole("switch")
|
|
32
|
+
.click();
|
|
33
|
+
await expect(scrubber).toBeVisible();
|
|
34
|
+
}
|
|
35
|
+
const pause = page.getByRole("button", { name: "Pause playback" });
|
|
36
|
+
if (await pause.isVisible()) await pause.click();
|
|
37
|
+
|
|
38
|
+
await scrubber.press("Home");
|
|
39
|
+
await expect(scrubber).toHaveAttribute("aria-valuenow", "0");
|
|
40
|
+
const initialStart = await readMarkerSignature(page, options.markerSelector);
|
|
41
|
+
await scrubber.press("End");
|
|
42
|
+
const initialEnd = await readMarkerSignature(page, options.markerSelector);
|
|
43
|
+
expect(initialEnd).toBe(initialStart);
|
|
44
|
+
await scrubber.press("ArrowLeft");
|
|
45
|
+
const scrubbed = await readMarkerSignature(page, options.markerSelector);
|
|
46
|
+
expect(scrubbed).not.toBe(initialStart);
|
|
47
|
+
await attachToolcraftBrowserRuntimeEvidence({
|
|
48
|
+
evidenceType: "timeline-scrub",
|
|
49
|
+
requirementId: options.requirementId,
|
|
50
|
+
target: "timeline.playback",
|
|
51
|
+
});
|
|
52
|
+
await attachToolcraftBrowserRuntimeEvidence({
|
|
53
|
+
evidenceType: "timeline-rendered-frame",
|
|
54
|
+
requirementId: options.requirementId,
|
|
55
|
+
target: "timeline.playback",
|
|
56
|
+
});
|
|
57
|
+
await attachToolcraftBrowserRuntimeEvidence({
|
|
58
|
+
evidenceType: "product-observable-change",
|
|
59
|
+
requirementId: options.requirementId,
|
|
60
|
+
target: "timeline.playback",
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await page.getByRole("button", { name: "Edit timeline duration" }).click();
|
|
64
|
+
const durationEditor = page.getByRole("textbox", { name: "timeline duration" });
|
|
65
|
+
await durationEditor.fill("2s");
|
|
66
|
+
await durationEditor.press("Enter");
|
|
67
|
+
await expect(scrubber).toHaveAttribute("aria-valuemax", "2");
|
|
68
|
+
await scrubber.press("Home");
|
|
69
|
+
const resizedStart = await readMarkerSignature(page, options.markerSelector);
|
|
70
|
+
await scrubber.press("End");
|
|
71
|
+
const resizedEnd = await readMarkerSignature(page, options.markerSelector);
|
|
72
|
+
expect(resizedEnd).toBe(resizedStart);
|
|
73
|
+
await attachToolcraftBrowserRuntimeEvidence({
|
|
74
|
+
evidenceType: "timeline-duration",
|
|
75
|
+
requirementId: options.requirementId,
|
|
76
|
+
target: "timeline.playback",
|
|
77
|
+
});
|
|
78
|
+
await attachToolcraftBrowserRuntimeEvidence({
|
|
79
|
+
evidenceType: "timeline-loop",
|
|
80
|
+
requirementId: options.requirementId,
|
|
81
|
+
target: "timeline.playback",
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
await scrubber.press("Home");
|
|
85
|
+
await page.getByRole("button", { name: "Play playback" }).click();
|
|
86
|
+
await expect
|
|
87
|
+
.poll(() => scrubber.getAttribute("aria-valuenow"))
|
|
88
|
+
.not.toBe("0");
|
|
89
|
+
await page.getByRole("button", { name: "Pause playback" }).click();
|
|
90
|
+
const pausedTime = await scrubber.getAttribute("aria-valuenow");
|
|
91
|
+
const pausedSignature = await readMarkerSignature(page, options.markerSelector);
|
|
92
|
+
await page.waitForTimeout(100);
|
|
93
|
+
expect(await scrubber.getAttribute("aria-valuenow")).toBe(pausedTime);
|
|
94
|
+
expect(await readMarkerSignature(page, options.markerSelector)).toBe(
|
|
95
|
+
pausedSignature,
|
|
96
|
+
);
|
|
97
|
+
await page.getByRole("button", { name: "Play playback" }).click();
|
|
98
|
+
await expect
|
|
99
|
+
.poll(() => scrubber.getAttribute("aria-valuenow"))
|
|
100
|
+
.not.toBe(pausedTime);
|
|
101
|
+
await attachToolcraftBrowserRuntimeEvidence({
|
|
102
|
+
evidenceType: "timeline-pause-resume",
|
|
103
|
+
requirementId: options.requirementId,
|
|
104
|
+
target: "timeline.playback",
|
|
105
|
+
});
|
|
106
|
+
}
|