@pixel-point/toolcraft 0.0.17 → 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-test-doc-assertions.mjs +58 -68
- package/src/generate-test-doc-assertions.test.mjs +43 -0
- package/src/generate-test-doc-policy-assertions.mjs +92 -0
- package/src/generate-test-file-assertions.mjs +26 -75
- package/src/generate-test-product-iteration.test.mjs +17 -0
- package/src/generate-test-runtime-boundary-assertions.mjs +158 -0
- package/src/generate-test-standalone-assertions.mjs +10 -0
- package/templates/runtime/contracts/component-contracts.choices.test.ts +47 -3
- package/templates/runtime/contracts/component-contracts.choices.ts +48 -3
- 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 +4 -4
- package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +7 -1
- package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +3 -0
- package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +3 -0
- package/templates/runtime/contracts/component-contracts.runtime.ts +12 -8
- package/templates/runtime/contracts/component-contracts.test.ts +2 -0
- package/templates/runtime/contracts/decision-contracts.test.ts +18 -0
- package/templates/runtime/contracts/decision-contracts.ts +10 -10
- package/templates/runtime/export/export-background.ts +0 -19
- package/templates/runtime/export/export.test.ts +45 -42
- package/templates/runtime/export/index.ts +44 -16
- package/templates/runtime/index.ts +2 -0
- package/templates/runtime/model-import/model-import-limits.ts +15 -4
- package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +11 -1
- package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +29 -0
- package/templates/runtime/react/app-shell/toolcraft-app.tsx +18 -8
- 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.scene-export-actions.test.tsx +1 -1
- 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 +2 -4
- package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +10 -4
- 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/scene/scene-bounds.test.ts +23 -0
- package/templates/runtime/scene/scene-bounds.ts +31 -17
- package/templates/runtime/schema/app-capabilities.test.ts +4 -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-layout.ts +14 -9
- package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +59 -0
- 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-canvas.test.ts +16 -3
- package/templates/runtime/schema/define-toolcraft.source-collection.test.ts +79 -0
- package/templates/runtime/schema/runtime-setup-section.ts +24 -5
- package/templates/runtime/schema/types.ts +68 -13
- package/templates/starter/AGENTS.md +12 -10
- package/templates/starter/docs/toolcraft/acceptance-testing.md +17 -31
- package/templates/starter/docs/toolcraft/agent-worklog.md +15 -0
- package/templates/starter/docs/toolcraft/assembly-workflow.md +10 -3
- 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 +2 -0
- package/templates/starter/docs/toolcraft/core/runtime-boundary.md +13 -2
- package/templates/starter/docs/toolcraft/core/setup-export.md +33 -7
- 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/renderer-technique.md +4 -0
- package/templates/starter/docs/toolcraft/schema-reference.md +21 -19
- package/templates/starter/e2e/app-browser-control-applicability-requirements.spec.ts +163 -0
- package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +7 -2
- package/templates/starter/e2e/app-browser-orientation-evidence.spec.ts +174 -21
- package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +1 -33
- package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +61 -15
- 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 +20 -11
- 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-runtime-applicability-requirements.ts +84 -0
- package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +9 -2
- package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +29 -26
- package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +25 -0
- package/templates/starter/scripts/toolcraft-contract-manifest.json +1 -0
- package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +85 -115
- package/templates/starter/scripts/toolcraft-product-boundary-module-policy.mjs +101 -0
- package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +0 -72
- 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-export-boundary.mjs +6 -17
- package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +196 -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.mjs +2 -0
- 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/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 +22 -10
- package/templates/starter/src/app/acceptance/output-video-export-rules.ts +99 -0
- package/templates/starter/src/app/acceptance/types.ts +23 -8
- package/templates/starter/src/app/acceptance/validate-coverage.ts +19 -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-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.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 +4 -0
- 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 +11 -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/test-evidence/browser-runtime-contract.ts +2 -2
- package/templates/starter/src/routes/index.tsx +1 -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/starter/src/app/acceptance/condition-exclusivity.test.ts +0 -60
- package/templates/starter/src/app/acceptance/condition-exclusivity.ts +0 -221
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { resolveToolcraftArtifactExportIntent } from "./acceptance/artifact-export-intent";
|
|
4
4
|
import { starterProductReadiness } from "./starter-acceptance";
|
|
5
5
|
import {
|
|
6
6
|
textLooksLikePngExport,
|
|
@@ -14,38 +14,37 @@ import {
|
|
|
14
14
|
getSchemaVideoExportSection,
|
|
15
15
|
getSectionControlByTarget,
|
|
16
16
|
getSectionControlIdByTarget,
|
|
17
|
-
schemaHasProductSurface,
|
|
18
17
|
} from "./starter-acceptance.schema-test-utils";
|
|
19
|
-
import { starterSchema } from "./starter-schema";
|
|
20
18
|
|
|
21
19
|
describe("Toolcraft output export acceptance contract", () => {
|
|
22
20
|
it("requires product output apps to expose export actions in the sticky footer", () => {
|
|
23
|
-
if (starterProductReadiness.mode
|
|
21
|
+
if (starterProductReadiness.mode === "starter") {
|
|
24
22
|
return;
|
|
25
23
|
}
|
|
26
24
|
|
|
25
|
+
const delivery = resolveToolcraftArtifactExportIntent(
|
|
26
|
+
starterProductReadiness.exportIntent,
|
|
27
|
+
);
|
|
27
28
|
const panelActionTexts = getSchemaPanelActionSearchTexts();
|
|
28
29
|
const backgroundColorTargets = getSchemaBackgroundControlTargets(new Set(["color"]));
|
|
29
30
|
const backgroundToggleTargets = getSchemaBackgroundControlTargets(
|
|
30
31
|
new Set(["checkbox", "select", "segmented", "switch"]),
|
|
31
32
|
);
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
'Every product app with Export PNG must expose export.includeBackground in runtime Setup as a Switch labeled "Background".',
|
|
48
|
-
).toBeGreaterThan(0);
|
|
34
|
+
if (delivery.imageEnabled || delivery.videoEnabled) {
|
|
35
|
+
expect(
|
|
36
|
+
panelActionTexts.length,
|
|
37
|
+
"Product apps with artifact delivery must define panelActions in the controls panel sticky footer.",
|
|
38
|
+
).toBeGreaterThan(0);
|
|
39
|
+
expect(
|
|
40
|
+
backgroundColorTargets.length,
|
|
41
|
+
"Product apps with artifact delivery must expose a user-facing background color control.",
|
|
42
|
+
).toBeGreaterThan(0);
|
|
43
|
+
expect(
|
|
44
|
+
backgroundToggleTargets.length,
|
|
45
|
+
'Product apps with artifact delivery must expose export.includeBackground in runtime Setup as a Switch labeled "Background".',
|
|
46
|
+
).toBeGreaterThan(0);
|
|
47
|
+
}
|
|
49
48
|
|
|
50
49
|
const imageExportSection = getSchemaImageExportSection();
|
|
51
50
|
const imageFormatControl = getSectionControlByTarget(
|
|
@@ -78,47 +77,51 @@ describe("Toolcraft output export acceptance contract", () => {
|
|
|
78
77
|
) === true;
|
|
79
78
|
|
|
80
79
|
expect(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
).
|
|
84
|
-
expect(
|
|
85
|
-
imageFormatControl,
|
|
86
|
-
'The separate "Image Export" section must include a format control with target "export.image.format".',
|
|
87
|
-
).toBeDefined();
|
|
88
|
-
expect(
|
|
89
|
-
imageFormatControl?.type,
|
|
90
|
-
"Image Export format must use the same Select/dropdown structure as Video Export.",
|
|
91
|
-
).toBe("select");
|
|
92
|
-
expect(
|
|
93
|
-
imageFormatOptionValues,
|
|
94
|
-
'Image format options must include "png" and "jpg".',
|
|
95
|
-
).toEqual(expect.arrayContaining(["png", "jpg"]));
|
|
96
|
-
expect(
|
|
97
|
-
imageFormatControl?.defaultValue,
|
|
98
|
-
'Image format must default to "png".',
|
|
99
|
-
).toBe("png");
|
|
100
|
-
expect(
|
|
101
|
-
imageResolutionControl,
|
|
102
|
-
'The separate "Image Export" section must include a resolution control with target "export.image.resolution".',
|
|
103
|
-
).toBeDefined();
|
|
104
|
-
expect(
|
|
105
|
-
imageResolutionControl?.type,
|
|
106
|
-
"Image Export resolution must use the same Select/dropdown structure as Video Export.",
|
|
107
|
-
).toBe("select");
|
|
108
|
-
expect(
|
|
109
|
-
imageResolutionOptionValues,
|
|
110
|
-
'Image resolution options must include "2k", "4k", and "8k".',
|
|
111
|
-
).toEqual(expect.arrayContaining(["2k", "4k", "8k"]));
|
|
112
|
-
expect(
|
|
113
|
-
imageResolutionControl?.defaultValue,
|
|
114
|
-
'Image resolution must default to "4k".',
|
|
115
|
-
).toBe("4k");
|
|
80
|
+
panelActionTexts.some(textLooksLikePngExport),
|
|
81
|
+
"Image export action presence must match resolved product export intent.",
|
|
82
|
+
).toBe(delivery.imageEnabled);
|
|
116
83
|
expect(
|
|
117
|
-
|
|
118
|
-
"Image Export
|
|
119
|
-
).toBe(
|
|
120
|
-
|
|
121
|
-
|
|
84
|
+
imageExportSection !== undefined,
|
|
85
|
+
'"Image Export" section presence must match resolved product export intent.',
|
|
86
|
+
).toBe(delivery.imageEnabled);
|
|
87
|
+
|
|
88
|
+
if (delivery.imageEnabled) {
|
|
89
|
+
expect(
|
|
90
|
+
imageFormatControl,
|
|
91
|
+
'The separate "Image Export" section must include a format control with target "export.image.format".',
|
|
92
|
+
).toBeDefined();
|
|
93
|
+
expect(
|
|
94
|
+
imageFormatControl?.type,
|
|
95
|
+
"Image Export format must use the same Select/dropdown structure as Video Export.",
|
|
96
|
+
).toBe("select");
|
|
97
|
+
expect(
|
|
98
|
+
imageFormatOptionValues,
|
|
99
|
+
'Image format options must include "png" and "jpg".',
|
|
100
|
+
).toEqual(expect.arrayContaining(["png", "jpg"]));
|
|
101
|
+
expect(
|
|
102
|
+
imageFormatControl?.defaultValue,
|
|
103
|
+
'Image format must default to "png".',
|
|
104
|
+
).toBe("png");
|
|
105
|
+
expect(
|
|
106
|
+
imageResolutionControl,
|
|
107
|
+
'The separate "Image Export" section must include a resolution control with target "export.image.resolution".',
|
|
108
|
+
).toBeDefined();
|
|
109
|
+
expect(
|
|
110
|
+
imageResolutionControl?.type,
|
|
111
|
+
"Image Export resolution must use the same Select/dropdown structure as Video Export.",
|
|
112
|
+
).toBe("select");
|
|
113
|
+
expect(
|
|
114
|
+
imageResolutionOptionValues,
|
|
115
|
+
'Image resolution options must include "2k", "4k", and "8k".',
|
|
116
|
+
).toEqual(expect.arrayContaining(["2k", "4k", "8k"]));
|
|
117
|
+
expect(
|
|
118
|
+
imageResolutionControl?.defaultValue,
|
|
119
|
+
'Image resolution must default to "4k".',
|
|
120
|
+
).toBe("4k");
|
|
121
|
+
expect(
|
|
122
|
+
imageExportHasInlinePair,
|
|
123
|
+
"Image Export format and resolution must render as a compact inline pair.",
|
|
124
|
+
).toBe(true);
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
const videoExportSection = getSchemaVideoExportSection();
|
|
@@ -134,48 +137,12 @@ describe("Toolcraft output export acceptance contract", () => {
|
|
|
134
137
|
const videoResolutionOptionValues = getControlOptionValues(videoResolutionControl);
|
|
135
138
|
expect(
|
|
136
139
|
panelActionTexts.some(textLooksLikeVideoExport),
|
|
137
|
-
"
|
|
138
|
-
).toBe(
|
|
139
|
-
expect(
|
|
140
|
-
panelActionTexts.length,
|
|
141
|
-
"Apps with image and video delivery need separate footer actions for Export Video and Export PNG.",
|
|
142
|
-
).toBeGreaterThanOrEqual(2);
|
|
143
|
-
expect(
|
|
144
|
-
videoExportSection,
|
|
145
|
-
'Apps with Export Video must expose video settings in a separate controls section titled "Video Export".',
|
|
146
|
-
).toBeDefined();
|
|
147
|
-
expect(
|
|
148
|
-
videoFormatControl,
|
|
149
|
-
'The separate "Video Export" section must include a format control with target "export.video.format".',
|
|
150
|
-
).toBeDefined();
|
|
151
|
-
expect(
|
|
152
|
-
["select", "segmented"],
|
|
153
|
-
"Video format must be a Select or Segmented control so the user chooses a supported container instead of typing a freeform value.",
|
|
154
|
-
).toContain(videoFormatControl?.type);
|
|
140
|
+
"Video export action presence must match resolved product export intent.",
|
|
141
|
+
).toBe(delivery.videoEnabled);
|
|
155
142
|
expect(
|
|
156
|
-
|
|
157
|
-
'Video
|
|
158
|
-
).
|
|
159
|
-
expect(
|
|
160
|
-
videoResolutionControl,
|
|
161
|
-
'The separate "Video Export" section must include a resolution control with target "export.video.resolution".',
|
|
162
|
-
).toBeDefined();
|
|
163
|
-
expect(
|
|
164
|
-
["select"],
|
|
165
|
-
"Video resolution must be a Select control with explicit output-size choices.",
|
|
166
|
-
).toContain(videoResolutionControl?.type);
|
|
167
|
-
expect(
|
|
168
|
-
videoResolutionOptionValues,
|
|
169
|
-
'Video resolution options must include "current" and "4k".',
|
|
170
|
-
).toEqual(expect.arrayContaining(["current", "4k"]));
|
|
171
|
-
expect(
|
|
172
|
-
videoResolutionControl?.defaultValue,
|
|
173
|
-
'Video resolution must default to "current".',
|
|
174
|
-
).toBe("current");
|
|
175
|
-
expect(
|
|
176
|
-
videoFormatControl?.defaultValue,
|
|
177
|
-
'Video format must default to "mp4".',
|
|
178
|
-
).toBe("mp4");
|
|
143
|
+
videoExportSection !== undefined,
|
|
144
|
+
'"Video Export" section presence must match resolved product export intent.',
|
|
145
|
+
).toBe(delivery.videoEnabled);
|
|
179
146
|
const videoFormatControlId = getSectionControlIdByTarget(
|
|
180
147
|
videoExportSection,
|
|
181
148
|
"export.video.format",
|
|
@@ -194,9 +161,49 @@ describe("Toolcraft output export acceptance contract", () => {
|
|
|
194
161
|
group.controls.includes(videoResolutionControlId),
|
|
195
162
|
) === true;
|
|
196
163
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
164
|
+
if (delivery.videoEnabled) {
|
|
165
|
+
if (delivery.imageEnabled) {
|
|
166
|
+
expect(
|
|
167
|
+
panelActionTexts.length,
|
|
168
|
+
"Apps with image and video delivery need separate footer actions for Export Video and Export PNG.",
|
|
169
|
+
).toBeGreaterThanOrEqual(2);
|
|
170
|
+
}
|
|
171
|
+
expect(
|
|
172
|
+
videoFormatControl,
|
|
173
|
+
'The separate "Video Export" section must include a format control with target "export.video.format".',
|
|
174
|
+
).toBeDefined();
|
|
175
|
+
expect(
|
|
176
|
+
["select", "segmented"],
|
|
177
|
+
"Video format must be a Select or Segmented control so the user chooses a supported container instead of typing a freeform value.",
|
|
178
|
+
).toContain(videoFormatControl?.type);
|
|
179
|
+
expect(
|
|
180
|
+
videoFormatOptionValues,
|
|
181
|
+
'Video format options must include safe browser baseline choices: "webm" and "mp4".',
|
|
182
|
+
).toEqual(expect.arrayContaining(["webm", "mp4"]));
|
|
183
|
+
expect(
|
|
184
|
+
videoResolutionControl,
|
|
185
|
+
'The separate "Video Export" section must include a resolution control with target "export.video.resolution".',
|
|
186
|
+
).toBeDefined();
|
|
187
|
+
expect(
|
|
188
|
+
["select"],
|
|
189
|
+
"Video resolution must be a Select control with explicit output-size choices.",
|
|
190
|
+
).toContain(videoResolutionControl?.type);
|
|
191
|
+
expect(
|
|
192
|
+
videoResolutionOptionValues,
|
|
193
|
+
'Video resolution options must include "current" and "4k".',
|
|
194
|
+
).toEqual(expect.arrayContaining(["current", "4k"]));
|
|
195
|
+
expect(
|
|
196
|
+
videoResolutionControl?.defaultValue,
|
|
197
|
+
'Video resolution must default to "current".',
|
|
198
|
+
).toBe("current");
|
|
199
|
+
expect(
|
|
200
|
+
videoFormatControl?.defaultValue,
|
|
201
|
+
'Video format must default to "mp4".',
|
|
202
|
+
).toBe("mp4");
|
|
203
|
+
expect(
|
|
204
|
+
videoExportHasInlinePair,
|
|
205
|
+
"Video Export format and resolution must render as a compact inline pair unless a documented fit fallback is used.",
|
|
206
|
+
).toBe(true);
|
|
207
|
+
}
|
|
201
208
|
});
|
|
202
209
|
});
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
starterProductReadiness,
|
|
5
5
|
starterTransferMode,
|
|
6
6
|
} from "./starter-acceptance";
|
|
7
|
+
import { schemaHasVideoExportPanelAction } from "./acceptance/output-export";
|
|
7
8
|
import { isNeutralTemplateProject } from "./starter-acceptance.product-readiness-test-utils";
|
|
8
9
|
import { schemaHasProductSurface } from "./starter-acceptance.schema-test-utils";
|
|
9
10
|
import { starterSchema } from "./starter-schema";
|
|
@@ -22,6 +23,17 @@ describe("Toolcraft product readiness", () => {
|
|
|
22
23
|
|
|
23
24
|
it("allows neutral readiness only for the source starter/template folder", () => {
|
|
24
25
|
if (starterProductReadiness.mode === "product") {
|
|
26
|
+
expect(starterProductReadiness.exportIntent).toBeDefined();
|
|
27
|
+
if (starterProductReadiness.exportIntent.image.mode === "toolcraft-default") {
|
|
28
|
+
expect(starterProductReadiness.exportIntent.image).toEqual({
|
|
29
|
+
mode: "toolcraft-default",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
expect(starterProductReadiness.exportIntent.video.mode).toBe(
|
|
33
|
+
schemaHasVideoExportPanelAction(starterSchema)
|
|
34
|
+
? "user-requested"
|
|
35
|
+
: "not-requested",
|
|
36
|
+
);
|
|
25
37
|
expect(starterProductReadiness.productName.trim()).not.toBe("");
|
|
26
38
|
expect(starterProductReadiness.productSummary.trim()).not.toBe("");
|
|
27
39
|
expect(starterProductReadiness.requestedBehavior.trim()).not.toBe("");
|
|
@@ -311,7 +311,7 @@ describe("starter acceptance section cohesion contract", () => {
|
|
|
311
311
|
}),
|
|
312
312
|
).toEqual(
|
|
313
313
|
expect.arrayContaining([
|
|
314
|
-
'Controls for
|
|
314
|
+
'Controls for target family "squares.right" are split across sections: Square 1 (Right), Appearance. Assign one shared entityId when the sections edit one logical entity; the entity cohesion validator decides whether that split is allowed.',
|
|
315
315
|
]),
|
|
316
316
|
);
|
|
317
317
|
});
|
|
@@ -58,6 +58,7 @@ describe("starter acceptance section dependency contract", () => {
|
|
|
58
58
|
sectionInventory: [
|
|
59
59
|
{
|
|
60
60
|
entity: "Shape",
|
|
61
|
+
entityId: "shape",
|
|
61
62
|
groupingReason: "Shape setup",
|
|
62
63
|
id: "shape",
|
|
63
64
|
targets: ["shape.kind"],
|
|
@@ -73,7 +74,7 @@ describe("starter acceptance section dependency contract", () => {
|
|
|
73
74
|
);
|
|
74
75
|
});
|
|
75
76
|
|
|
76
|
-
it("
|
|
77
|
+
it("rejects workflow splitting when one entity fits in one section", () => {
|
|
77
78
|
const schemaWithWorkflowSplit = defineContractSchemaFixture({
|
|
78
79
|
canvas: { enabled: true },
|
|
79
80
|
panels: {
|
|
@@ -118,6 +119,33 @@ describe("starter acceptance section dependency contract", () => {
|
|
|
118
119
|
},
|
|
119
120
|
});
|
|
120
121
|
|
|
122
|
+
const workflowSplitInventory = [
|
|
123
|
+
{
|
|
124
|
+
entity: "Object shape",
|
|
125
|
+
entityId: "object-shape",
|
|
126
|
+
groupingReason:
|
|
127
|
+
"Structure controls tune the physical footprint of the object.",
|
|
128
|
+
id: "shape-structure",
|
|
129
|
+
splitReason:
|
|
130
|
+
"Structure and density are separate workflow stages in this editor.",
|
|
131
|
+
targets: ["object.shape.size"],
|
|
132
|
+
title: "Shape Structure",
|
|
133
|
+
workflowStage: "structure",
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
entity: "Object shape",
|
|
137
|
+
entityId: "object-shape",
|
|
138
|
+
groupingReason:
|
|
139
|
+
"Density controls tune how many objects appear after structure is set.",
|
|
140
|
+
id: "shape-density",
|
|
141
|
+
splitReason:
|
|
142
|
+
"Density is separated from structure because users set count after the shape footprint.",
|
|
143
|
+
targets: ["object.shape.count"],
|
|
144
|
+
title: "Shape Density",
|
|
145
|
+
workflowStage: "density",
|
|
146
|
+
},
|
|
147
|
+
] as const;
|
|
148
|
+
|
|
121
149
|
expect(
|
|
122
150
|
validateContractAcceptance({
|
|
123
151
|
schema: schemaWithWorkflowSplit,
|
|
@@ -126,28 +154,11 @@ describe("starter acceptance section dependency contract", () => {
|
|
|
126
154
|
makeControlAcceptance("object.shape.count", "slider"),
|
|
127
155
|
],
|
|
128
156
|
transferMode: contractTransferModeFixture,
|
|
129
|
-
sectionInventory:
|
|
130
|
-
{
|
|
131
|
-
entity: "Object shape",
|
|
132
|
-
groupingReason: "Structure controls tune the physical footprint of the object.",
|
|
133
|
-
id: "shape-structure",
|
|
134
|
-
splitReason: "Structure and density are separate workflow stages in this editor.",
|
|
135
|
-
targets: ["object.shape.size"],
|
|
136
|
-
title: "Shape Structure",
|
|
137
|
-
workflowStage: "structure",
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
entity: "Object shape",
|
|
141
|
-
groupingReason: "Density controls tune how many objects appear after structure is set.",
|
|
142
|
-
id: "shape-density",
|
|
143
|
-
splitReason: "Density is separated from structure because users set count after the shape footprint.",
|
|
144
|
-
targets: ["object.shape.count"],
|
|
145
|
-
title: "Shape Density",
|
|
146
|
-
workflowStage: "density",
|
|
147
|
-
},
|
|
148
|
-
],
|
|
157
|
+
sectionInventory: workflowSplitInventory,
|
|
149
158
|
}),
|
|
150
|
-
).
|
|
159
|
+
).toContain(
|
|
160
|
+
'Control Section Inventory entity "object-shape" owns 2 controls across 2 sections (Shape Structure, Shape Density). Entities with 10 or fewer controls must stay in one section.',
|
|
161
|
+
);
|
|
151
162
|
});
|
|
152
163
|
|
|
153
164
|
it("rejects mode-gated controls split away from their selector section", () => {
|
|
@@ -203,7 +214,7 @@ describe("starter acceptance section dependency contract", () => {
|
|
|
203
214
|
}),
|
|
204
215
|
).toEqual(
|
|
205
216
|
expect.arrayContaining([
|
|
206
|
-
'Image / sourceUpload is gated by
|
|
217
|
+
'Image / sourceUpload is gated by applicability target "source.mode" in Source, but it belongs to the same dependency group. Keep selectors and their dependent controls in one semantic section when they describe one product entity or branch; use conditional applicability for branch-specific controls inside that section instead of splitting branch controls into their own section. Do not use disabledWhen for product controls.',
|
|
207
218
|
]),
|
|
208
219
|
);
|
|
209
220
|
});
|
|
@@ -259,7 +270,7 @@ describe("starter acceptance section dependency contract", () => {
|
|
|
259
270
|
}),
|
|
260
271
|
).toEqual(
|
|
261
272
|
expect.arrayContaining([
|
|
262
|
-
'Library / libraryAsset is gated by
|
|
273
|
+
'Library / libraryAsset is gated by applicability target "shape.kind" in Shape, but it belongs to the same dependency group. Keep selectors and their dependent controls in one semantic section when they describe one product entity or branch; use conditional applicability for branch-specific controls inside that section instead of splitting branch controls into their own section. Do not use disabledWhen for product controls.',
|
|
263
274
|
]),
|
|
264
275
|
);
|
|
265
276
|
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { defineToolcraft } from "@repo/toolcraft-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { getToolcraftControlSectionInvariantErrors } from "./acceptance/control-layout";
|
|
5
|
+
|
|
6
|
+
function makeSliderControls(count: number, includeSemanticGroup: boolean) {
|
|
7
|
+
return Object.fromEntries(
|
|
8
|
+
Array.from({ length: count }, (_, index) => {
|
|
9
|
+
const control = {
|
|
10
|
+
defaultValue: 0,
|
|
11
|
+
label: `Value ${index + 1}`,
|
|
12
|
+
max: 1,
|
|
13
|
+
min: 0,
|
|
14
|
+
orderRole: "detail" as const,
|
|
15
|
+
target: `dense.value${index + 1}`,
|
|
16
|
+
type: "slider" as const,
|
|
17
|
+
variant: "continuous" as const,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return [
|
|
21
|
+
`value${index + 1}`,
|
|
22
|
+
includeSemanticGroup
|
|
23
|
+
? { ...control, semanticGroup: "dense-entity" }
|
|
24
|
+
: control,
|
|
25
|
+
];
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function makeDenseSchema(count: number, includeSemanticGroup = true) {
|
|
31
|
+
return defineToolcraft({
|
|
32
|
+
canvas: { enabled: true },
|
|
33
|
+
panels: {
|
|
34
|
+
controls: {
|
|
35
|
+
sections: [
|
|
36
|
+
{
|
|
37
|
+
controls: makeSliderControls(count, includeSemanticGroup),
|
|
38
|
+
id: "dense-entity",
|
|
39
|
+
title: "Dense Entity",
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
title: "Controls",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
describe("starter acceptance section size boundaries", () => {
|
|
49
|
+
it("does not require semanticGroup at seven controls", () => {
|
|
50
|
+
expect(
|
|
51
|
+
getToolcraftControlSectionInvariantErrors(makeDenseSchema(7, false)),
|
|
52
|
+
).toEqual([]);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("accepts ten grouped controls in one section", () => {
|
|
56
|
+
expect(
|
|
57
|
+
getToolcraftControlSectionInvariantErrors(makeDenseSchema(10)),
|
|
58
|
+
).toEqual([]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("requires semanticGroup beginning at eight controls", () => {
|
|
62
|
+
expect(
|
|
63
|
+
getToolcraftControlSectionInvariantErrors(makeDenseSchema(8, false)),
|
|
64
|
+
).toEqual(
|
|
65
|
+
expect.arrayContaining([
|
|
66
|
+
expect.stringContaining(
|
|
67
|
+
"has 8 controls and must declare semanticGroup for every control",
|
|
68
|
+
),
|
|
69
|
+
]),
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -4,6 +4,17 @@ import {
|
|
|
4
4
|
} from "@repo/toolcraft-runtime";
|
|
5
5
|
|
|
6
6
|
import { getRequiredToolcraftControlPartCoverage } from "./acceptance/control-parts";
|
|
7
|
+
export {
|
|
8
|
+
getToolcraftApplicabilitySelectorDomain,
|
|
9
|
+
getToolcraftControlApplicabilityErrors,
|
|
10
|
+
type ToolcraftApplicabilitySelectorDomain,
|
|
11
|
+
type ToolcraftApplicabilitySelectorValue,
|
|
12
|
+
} from "./acceptance/control-applicability";
|
|
13
|
+
export {
|
|
14
|
+
getToolcraftApplicabilityRequirementId,
|
|
15
|
+
getToolcraftControlApplicabilityCases,
|
|
16
|
+
type ToolcraftControlApplicabilityCase,
|
|
17
|
+
} from "./acceptance/control-applicability-cases";
|
|
7
18
|
import {
|
|
8
19
|
getToolcraftControlOrder as getToolcraftControlOrderForSchema,
|
|
9
20
|
getToolcraftControlOrderTargets as getToolcraftControlOrderTargetsForSchema,
|
|
@@ -17,7 +28,6 @@ import type {
|
|
|
17
28
|
ToolcraftBuiltInFitCheck,
|
|
18
29
|
ToolcraftBackgroundOutputCoverage,
|
|
19
30
|
ToolcraftCanvasSizingCoverage,
|
|
20
|
-
ToolcraftConditionalVisibilityCoverage,
|
|
21
31
|
ToolcraftComponentAcceptance,
|
|
22
32
|
ToolcraftControlOrderItem,
|
|
23
33
|
ToolcraftControlPartCoverage,
|
|
@@ -91,7 +101,6 @@ export type {
|
|
|
91
101
|
ToolcraftBuiltInFitCheck,
|
|
92
102
|
ToolcraftBackgroundOutputCoverage,
|
|
93
103
|
ToolcraftCanvasSizingCoverage,
|
|
94
|
-
ToolcraftConditionalVisibilityCoverage,
|
|
95
104
|
ToolcraftComponentAcceptance,
|
|
96
105
|
ToolcraftControlOrderItem,
|
|
97
106
|
ToolcraftControlPartCoverage,
|