@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
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineToolcraft,
|
|
3
|
+
type ToolcraftControlSchema,
|
|
4
|
+
} from "@repo/toolcraft-runtime";
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
|
|
7
|
+
import { getToolcraftControlApplicabilityErrors } from "./acceptance/control-applicability";
|
|
8
|
+
import type { ToolcraftProductReadiness } from "./acceptance/types";
|
|
9
|
+
import { collectToolcraftVisibleAcceptanceControls } from "./acceptance/validate-coverage";
|
|
10
|
+
|
|
11
|
+
const productReadiness: ToolcraftProductReadiness = {
|
|
12
|
+
exportIntent: {
|
|
13
|
+
image: { mode: "toolcraft-default" },
|
|
14
|
+
video: { mode: "not-requested" },
|
|
15
|
+
},
|
|
16
|
+
interactionOwnership: [],
|
|
17
|
+
mode: "product",
|
|
18
|
+
productName: "Shape fixture",
|
|
19
|
+
productSummary: "Neutral applicability contract fixture.",
|
|
20
|
+
requestedBehavior: "Show only controls that apply to the selected shape.",
|
|
21
|
+
viewInteraction: { mode: "non-spatial", reason: "Schema-only fixture." },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const shapeKind: ToolcraftControlSchema = {
|
|
25
|
+
applicability: { mode: "always" },
|
|
26
|
+
defaultValue: "circle",
|
|
27
|
+
options: [
|
|
28
|
+
{ label: "Circle", value: "circle" },
|
|
29
|
+
{ label: "Square", value: "square" },
|
|
30
|
+
{ label: "Polygon", value: "polygon" },
|
|
31
|
+
{ label: "Star", value: "star" },
|
|
32
|
+
],
|
|
33
|
+
target: "shape.kind",
|
|
34
|
+
type: "segmented",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const alwaysControls: Record<string, ToolcraftControlSchema> = {
|
|
38
|
+
kind: shapeKind,
|
|
39
|
+
cornerRadius: {
|
|
40
|
+
applicability: {
|
|
41
|
+
all: [
|
|
42
|
+
{
|
|
43
|
+
oneOf: ["square", "polygon", "star"],
|
|
44
|
+
target: "shape.kind",
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
mode: "conditional",
|
|
48
|
+
},
|
|
49
|
+
target: "shape.cornerRadius",
|
|
50
|
+
type: "slider",
|
|
51
|
+
},
|
|
52
|
+
depth: {
|
|
53
|
+
applicability: {
|
|
54
|
+
all: [{ equals: "star", target: "shape.kind" }],
|
|
55
|
+
mode: "conditional",
|
|
56
|
+
},
|
|
57
|
+
target: "shape.depth",
|
|
58
|
+
type: "slider",
|
|
59
|
+
},
|
|
60
|
+
sides: {
|
|
61
|
+
applicability: {
|
|
62
|
+
all: [
|
|
63
|
+
{ oneOf: ["polygon", "star"], target: "shape.kind" },
|
|
64
|
+
],
|
|
65
|
+
mode: "conditional",
|
|
66
|
+
},
|
|
67
|
+
target: "shape.sides",
|
|
68
|
+
type: "slider",
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
function validateProduct(
|
|
73
|
+
controls: Record<string, ToolcraftControlSchema>,
|
|
74
|
+
): string[] {
|
|
75
|
+
const schema = defineToolcraft({
|
|
76
|
+
canvas: { enabled: true },
|
|
77
|
+
panels: {
|
|
78
|
+
controls: {
|
|
79
|
+
sections: [{ controls, id: "shape", title: "Shape" }],
|
|
80
|
+
title: "Controls",
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return getToolcraftControlApplicabilityErrors({
|
|
86
|
+
controls: collectToolcraftVisibleAcceptanceControls(schema),
|
|
87
|
+
productReadiness,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
describe("starter product control applicability", () => {
|
|
92
|
+
it("requires explicit product applicability and rejects legacy visibility", () => {
|
|
93
|
+
expect(
|
|
94
|
+
validateProduct({
|
|
95
|
+
kind: shapeKind,
|
|
96
|
+
sides: { target: "shape.sides", type: "slider" },
|
|
97
|
+
}),
|
|
98
|
+
).toContainEqual(
|
|
99
|
+
expect.stringContaining("shape.sides must declare explicit applicability"),
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
expect(
|
|
103
|
+
validateProduct({
|
|
104
|
+
kind: shapeKind,
|
|
105
|
+
sides: {
|
|
106
|
+
target: "shape.sides",
|
|
107
|
+
type: "slider",
|
|
108
|
+
visibleWhen: { equals: "star", target: "shape.kind" },
|
|
109
|
+
},
|
|
110
|
+
}),
|
|
111
|
+
).toContainEqual(
|
|
112
|
+
expect.stringContaining("shape.sides uses legacy visibleWhen"),
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("rejects missing, invalid, contradictory, and unsupported selectors", () => {
|
|
117
|
+
expect(
|
|
118
|
+
validateProduct({
|
|
119
|
+
kind: shapeKind,
|
|
120
|
+
sides: {
|
|
121
|
+
applicability: {
|
|
122
|
+
all: [{ equals: true, target: "shape.missing" }],
|
|
123
|
+
mode: "conditional",
|
|
124
|
+
},
|
|
125
|
+
target: "shape.sides",
|
|
126
|
+
type: "slider",
|
|
127
|
+
},
|
|
128
|
+
}),
|
|
129
|
+
).toContainEqual(
|
|
130
|
+
expect.stringContaining('predicate target "shape.missing" does not exist'),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
expect(
|
|
134
|
+
validateProduct({
|
|
135
|
+
kind: shapeKind,
|
|
136
|
+
sides: {
|
|
137
|
+
applicability: {
|
|
138
|
+
all: [{ equals: "triangle", target: "shape.kind" }],
|
|
139
|
+
mode: "conditional",
|
|
140
|
+
},
|
|
141
|
+
target: "shape.sides",
|
|
142
|
+
type: "slider",
|
|
143
|
+
},
|
|
144
|
+
}),
|
|
145
|
+
).toContainEqual(
|
|
146
|
+
expect.stringContaining(
|
|
147
|
+
'value "triangle" is not an option of shape.kind',
|
|
148
|
+
),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
expect(
|
|
152
|
+
validateProduct({
|
|
153
|
+
kind: shapeKind,
|
|
154
|
+
sides: {
|
|
155
|
+
applicability: {
|
|
156
|
+
all: [
|
|
157
|
+
{ equals: "polygon", target: "shape.kind" },
|
|
158
|
+
{ equals: "star", target: "shape.kind" },
|
|
159
|
+
],
|
|
160
|
+
mode: "conditional",
|
|
161
|
+
},
|
|
162
|
+
target: "shape.sides",
|
|
163
|
+
type: "slider",
|
|
164
|
+
},
|
|
165
|
+
}),
|
|
166
|
+
).toContainEqual(
|
|
167
|
+
expect.stringContaining("shape.sides applicability is unsatisfiable"),
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
expect(
|
|
171
|
+
validateProduct({
|
|
172
|
+
kind: shapeKind,
|
|
173
|
+
name: {
|
|
174
|
+
applicability: { mode: "always" },
|
|
175
|
+
target: "shape.name",
|
|
176
|
+
type: "text",
|
|
177
|
+
},
|
|
178
|
+
sides: {
|
|
179
|
+
applicability: {
|
|
180
|
+
all: [{ equals: "named", target: "shape.name" }],
|
|
181
|
+
mode: "conditional",
|
|
182
|
+
},
|
|
183
|
+
target: "shape.sides",
|
|
184
|
+
type: "slider",
|
|
185
|
+
},
|
|
186
|
+
}),
|
|
187
|
+
).toContainEqual(
|
|
188
|
+
expect.stringContaining(
|
|
189
|
+
"shape.name is not a supported applicability selector",
|
|
190
|
+
),
|
|
191
|
+
);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("rejects numeric gates with no satisfying selector value", () => {
|
|
195
|
+
expect(
|
|
196
|
+
validateProduct({
|
|
197
|
+
count: {
|
|
198
|
+
applicability: { mode: "always" },
|
|
199
|
+
defaultValue: 2,
|
|
200
|
+
max: 3,
|
|
201
|
+
min: 1,
|
|
202
|
+
step: 1,
|
|
203
|
+
target: "shape.count",
|
|
204
|
+
type: "slider",
|
|
205
|
+
variant: "discrete",
|
|
206
|
+
},
|
|
207
|
+
sides: {
|
|
208
|
+
applicability: {
|
|
209
|
+
all: [{ greaterThan: 10, target: "shape.count" }],
|
|
210
|
+
mode: "conditional",
|
|
211
|
+
},
|
|
212
|
+
target: "shape.sides",
|
|
213
|
+
type: "slider",
|
|
214
|
+
},
|
|
215
|
+
}),
|
|
216
|
+
).toContainEqual(
|
|
217
|
+
expect.stringContaining("shape.sides has no satisfying value in shape.count"),
|
|
218
|
+
);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("accepts a complete finite applicability declaration", () => {
|
|
222
|
+
expect(validateProduct(alwaysControls)).toEqual([]);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
getToolcraftSegmentedStaticFitError,
|
|
4
|
+
type ToolcraftCollectionItemControlType,
|
|
4
5
|
} from "@repo/toolcraft-runtime";
|
|
5
6
|
|
|
6
7
|
import {
|
|
@@ -18,7 +19,7 @@ const SCREENSHOT_LABELS = ["Default", "Ink Drops", "Solar", "Background"];
|
|
|
18
19
|
const BOUNDARY_LABELS = ["Ink Drops", "Default", "Solar", "RGB"];
|
|
19
20
|
|
|
20
21
|
function createRawCollectionModesSchema(
|
|
21
|
-
itemControlType:
|
|
22
|
+
itemControlType: ToolcraftCollectionItemControlType,
|
|
22
23
|
labels: readonly string[],
|
|
23
24
|
) {
|
|
24
25
|
return {
|
|
@@ -64,6 +65,11 @@ const collectionModesAcceptance = [
|
|
|
64
65
|
browser: true,
|
|
65
66
|
browserTestName: "browser: collection modes update rendered output",
|
|
66
67
|
componentType: "collectionActions",
|
|
68
|
+
controlPartCoverage: [
|
|
69
|
+
"collectionActions.add",
|
|
70
|
+
"collectionActions.remove",
|
|
71
|
+
"collectionActions.items",
|
|
72
|
+
] as const,
|
|
67
73
|
evidence: "rendered-pixels" as const,
|
|
68
74
|
expectedObservable: "Adding and editing modes changes rendered output.",
|
|
69
75
|
fixture: "collection modes fixture",
|
|
@@ -339,7 +345,7 @@ describe("starter acceptance control order contract", () => {
|
|
|
339
345
|
it("reports canonical fit guidance for an overwide collectionActions itemControl", () => {
|
|
340
346
|
const itemControl = {
|
|
341
347
|
options: SCREENSHOT_LABELS.map((label) => ({ label })),
|
|
342
|
-
type: "segmented",
|
|
348
|
+
type: "segmented" as const,
|
|
343
349
|
};
|
|
344
350
|
const fitGuidance = getToolcraftSegmentedStaticFitError(itemControl);
|
|
345
351
|
|
|
@@ -359,10 +365,59 @@ describe("starter acceptance control order contract", () => {
|
|
|
359
365
|
);
|
|
360
366
|
});
|
|
361
367
|
|
|
368
|
+
it("reports canonical fit guidance for every compound itemControls field", () => {
|
|
369
|
+
const schema = createRawCollectionModesSchema("segmented", SCREENSHOT_LABELS);
|
|
370
|
+
const modes = schema.panels.controls.sections[0]!.controls.modes;
|
|
371
|
+
const compoundSchema = {
|
|
372
|
+
...schema,
|
|
373
|
+
panels: {
|
|
374
|
+
...schema.panels,
|
|
375
|
+
controls: {
|
|
376
|
+
...schema.panels.controls,
|
|
377
|
+
sections: [
|
|
378
|
+
{
|
|
379
|
+
...schema.panels.controls.sections[0],
|
|
380
|
+
controls: {
|
|
381
|
+
modes: {
|
|
382
|
+
...modes,
|
|
383
|
+
defaultValue: [{ enabled: true, mode: "default" }],
|
|
384
|
+
itemControl: undefined,
|
|
385
|
+
itemControls: {
|
|
386
|
+
enabled: {
|
|
387
|
+
defaultValue: true,
|
|
388
|
+
label: "Enabled",
|
|
389
|
+
type: "switch" as const,
|
|
390
|
+
},
|
|
391
|
+
mode: modes.itemControl,
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
],
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
};
|
|
400
|
+
const fitGuidance = getToolcraftSegmentedStaticFitError(
|
|
401
|
+
modes.itemControl,
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
expect(fitGuidance).not.toBeNull();
|
|
405
|
+
expect(
|
|
406
|
+
validateContractAcceptance({
|
|
407
|
+
schema: compoundSchema,
|
|
408
|
+
acceptance: collectionModesAcceptance,
|
|
409
|
+
}),
|
|
410
|
+
).toEqual(
|
|
411
|
+
expect.arrayContaining([
|
|
412
|
+
`Style / modes (appearance.modes) itemControls.mode ${fitGuidance}`,
|
|
413
|
+
]),
|
|
414
|
+
);
|
|
415
|
+
});
|
|
416
|
+
|
|
362
417
|
it.each([
|
|
363
418
|
{ labels: BOUNDARY_LABELS, type: "segmented" },
|
|
364
419
|
{ labels: SCREENSHOT_LABELS, type: "select" },
|
|
365
|
-
])(
|
|
420
|
+
] as const)(
|
|
366
421
|
"does not report itemControl fit guidance for nested $type",
|
|
367
422
|
({ labels, type }) => {
|
|
368
423
|
const errors = validateContractAcceptance({
|
|
@@ -160,115 +160,4 @@ describe("starter acceptance control state contract", () => {
|
|
|
160
160
|
);
|
|
161
161
|
});
|
|
162
162
|
|
|
163
|
-
it("requires visibleWhen controls to reference a real target and prove hidden behavior", () => {
|
|
164
|
-
const schemaWithVisibleDependency = defineContractSchemaFixture({
|
|
165
|
-
canvas: { enabled: true },
|
|
166
|
-
panels: {
|
|
167
|
-
controls: {
|
|
168
|
-
sections: [
|
|
169
|
-
{
|
|
170
|
-
controls: {
|
|
171
|
-
shadeCount: {
|
|
172
|
-
defaultValue: 2,
|
|
173
|
-
label: "Shades",
|
|
174
|
-
max: 5,
|
|
175
|
-
min: 1,
|
|
176
|
-
step: 1,
|
|
177
|
-
target: "shapes.shadeCount",
|
|
178
|
-
type: "slider",
|
|
179
|
-
variant: "discrete",
|
|
180
|
-
},
|
|
181
|
-
shade3: {
|
|
182
|
-
defaultValue: { hex: "#BBBBBB" },
|
|
183
|
-
label: "Shade 3",
|
|
184
|
-
target: "shapes.color3",
|
|
185
|
-
type: "color",
|
|
186
|
-
visibleWhen: {
|
|
187
|
-
greaterThanOrEqual: 3,
|
|
188
|
-
target: "shapes.count",
|
|
189
|
-
},
|
|
190
|
-
},
|
|
191
|
-
},
|
|
192
|
-
title: "Shapes",
|
|
193
|
-
},
|
|
194
|
-
],
|
|
195
|
-
title: "Controls",
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
expect(
|
|
201
|
-
validateContractAcceptance({
|
|
202
|
-
schema: schemaWithVisibleDependency,
|
|
203
|
-
acceptance: [
|
|
204
|
-
makeControlAcceptance("shapes.shadeCount", "slider"),
|
|
205
|
-
makeControlAcceptance("shapes.color3", "color"),
|
|
206
|
-
],
|
|
207
|
-
}),
|
|
208
|
-
).toEqual(
|
|
209
|
-
expect.arrayContaining([
|
|
210
|
-
expect.stringContaining(
|
|
211
|
-
"visibleWhen target shapes.count does not match another schema control target",
|
|
212
|
-
),
|
|
213
|
-
expect.stringContaining(
|
|
214
|
-
"uses visibleWhen and must declare visibilityCoverage",
|
|
215
|
-
),
|
|
216
|
-
]),
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
const schemaWithValidVisibleDependency = defineContractSchemaFixture({
|
|
220
|
-
canvas: { enabled: true },
|
|
221
|
-
panels: {
|
|
222
|
-
controls: {
|
|
223
|
-
sections: [
|
|
224
|
-
{
|
|
225
|
-
controls: {
|
|
226
|
-
shadeCount: {
|
|
227
|
-
defaultValue: 2,
|
|
228
|
-
label: "Shades",
|
|
229
|
-
max: 5,
|
|
230
|
-
min: 1,
|
|
231
|
-
step: 1,
|
|
232
|
-
target: "shapes.shadeCount",
|
|
233
|
-
type: "slider",
|
|
234
|
-
variant: "discrete",
|
|
235
|
-
},
|
|
236
|
-
shade3: {
|
|
237
|
-
defaultValue: { hex: "#BBBBBB" },
|
|
238
|
-
label: "Shade 3",
|
|
239
|
-
target: "shapes.color3",
|
|
240
|
-
type: "color",
|
|
241
|
-
visibleWhen: {
|
|
242
|
-
greaterThanOrEqual: 3,
|
|
243
|
-
target: "shapes.shadeCount",
|
|
244
|
-
},
|
|
245
|
-
},
|
|
246
|
-
},
|
|
247
|
-
title: "Shapes",
|
|
248
|
-
},
|
|
249
|
-
],
|
|
250
|
-
title: "Controls",
|
|
251
|
-
},
|
|
252
|
-
},
|
|
253
|
-
});
|
|
254
|
-
const errors = validateContractAcceptance({
|
|
255
|
-
schema: schemaWithValidVisibleDependency,
|
|
256
|
-
acceptance: [
|
|
257
|
-
makeControlAcceptance("shapes.shadeCount", "slider"),
|
|
258
|
-
{
|
|
259
|
-
...makeControlAcceptance("shapes.color3", "color"),
|
|
260
|
-
expectedObservable: "Третий цвет доступен только для соответствующего состояния продукта.",
|
|
261
|
-
userAction: "Переключить количество оттенков и проверить оба состояния.",
|
|
262
|
-
visibilityCoverage: ["hidden", "visible"],
|
|
263
|
-
},
|
|
264
|
-
],
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
expect(errors).not.toEqual(
|
|
268
|
-
expect.arrayContaining([
|
|
269
|
-
expect.stringContaining("visibleWhen target"),
|
|
270
|
-
expect.stringContaining("uses visibleWhen and must declare visibilityCoverage"),
|
|
271
|
-
]),
|
|
272
|
-
);
|
|
273
|
-
});
|
|
274
163
|
});
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "./starter-acceptance.contract-fixtures";
|
|
7
7
|
|
|
8
8
|
describe("starter acceptance custom control collection contract", () => {
|
|
9
|
-
it("requires collection-like custom controls to compare
|
|
9
|
+
it("requires collection-like custom controls to compare both cardinality owners and actions", () => {
|
|
10
10
|
const schema = defineContractSchemaFixture({
|
|
11
11
|
canvas: { enabled: true },
|
|
12
12
|
panels: {
|
|
@@ -71,6 +71,7 @@ describe("starter acceptance custom control collection contract", () => {
|
|
|
71
71
|
],
|
|
72
72
|
}),
|
|
73
73
|
).toEqual([
|
|
74
|
+
"Masks / maskEditor (masks) builtInFitCheck.checkedBuiltIns must include sourceCollection when the custom control owns a repeated runtime item set whose cardinality could be source-owned.",
|
|
74
75
|
"Masks / maskEditor (masks) builtInFitCheck.checkedBuiltIns must include collectionActions when the custom control owns a growable, removable, selectable, or reorderable runtime item set.",
|
|
75
76
|
"Masks / maskEditor (masks) builtInFitCheck.checkedBuiltIns must include actions when the custom control exposes local command buttons such as add, remove, delete, duplicate, sort, normalize, or clear.",
|
|
76
77
|
]);
|
|
@@ -135,6 +136,7 @@ describe("starter acceptance custom control collection contract", () => {
|
|
|
135
136
|
],
|
|
136
137
|
}),
|
|
137
138
|
).toEqual([
|
|
139
|
+
"Pattern / patternSet (pattern.set) builtInFitCheck.checkedBuiltIns must include sourceCollection when the custom control owns a repeated runtime item set whose cardinality could be source-owned.",
|
|
138
140
|
"Pattern / patternSet (pattern.set) builtInFitCheck.checkedBuiltIns must include collectionActions when the custom control owns a growable, removable, selectable, or reorderable runtime item set.",
|
|
139
141
|
]);
|
|
140
142
|
});
|
|
@@ -48,7 +48,7 @@ describe("starter acceptance valid custom control contract", () => {
|
|
|
48
48
|
"reorder",
|
|
49
49
|
"selection",
|
|
50
50
|
],
|
|
51
|
-
checkedBuiltIns: ["actions", "collectionActions", "fileDrop", "imagePicker", "select"],
|
|
51
|
+
checkedBuiltIns: ["actions", "collectionActions", "fileDrop", "imagePicker", "select", "sourceCollection"],
|
|
52
52
|
closestBuiltIn: "fileDrop",
|
|
53
53
|
productObservable: "Ordering uploaded glyphs changes the rendered glyph ramp output.",
|
|
54
54
|
whyInsufficient: "FileDrop imports source files, but it does not provide density ordering, per-glyph preview, reorder, and remove behavior in one runtime value.",
|
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ToolcraftArtifactExportIntent,
|
|
3
|
+
ToolcraftProductReadiness,
|
|
4
|
+
} from "./acceptance/types";
|
|
5
|
+
|
|
6
|
+
export function makeExportSettingsProductReadiness(
|
|
7
|
+
exportIntent: ToolcraftArtifactExportIntent,
|
|
8
|
+
): Extract<ToolcraftProductReadiness, { mode: "product" }> {
|
|
9
|
+
return {
|
|
10
|
+
exportIntent,
|
|
11
|
+
interactionOwnership: [],
|
|
12
|
+
mode: "product",
|
|
13
|
+
productName: "Export settings fixture",
|
|
14
|
+
productSummary: "A synthetic product for image and video export settings.",
|
|
15
|
+
requestedBehavior: "Export the explicitly requested artifact types.",
|
|
16
|
+
viewInteraction: {
|
|
17
|
+
mode: "non-spatial",
|
|
18
|
+
reason: "The synthetic output is two-dimensional.",
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
1
23
|
export function makeBackgroundSection() {
|
|
2
24
|
return {
|
|
3
25
|
controls: {
|
|
@@ -3,12 +3,26 @@ import { describe, expect, it } from "vitest";
|
|
|
3
3
|
import { defineContractSchemaFixture, validateContractAcceptance } from "./starter-acceptance.contract-fixtures";
|
|
4
4
|
import {
|
|
5
5
|
makeBackgroundSection,
|
|
6
|
+
makeExportSettingsProductReadiness,
|
|
6
7
|
makeImageExportSection,
|
|
7
8
|
makeVideoExportSection,
|
|
8
9
|
} from "./starter-acceptance.export-test-utils";
|
|
9
10
|
import { makeControlAcceptance } from "./starter-acceptance.test-utils";
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
const imageOnlyProductReadiness = makeExportSettingsProductReadiness({
|
|
13
|
+
image: { mode: "toolcraft-default" },
|
|
14
|
+
video: { mode: "not-requested" },
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const imageAndVideoProductReadiness = makeExportSettingsProductReadiness({
|
|
18
|
+
image: { mode: "toolcraft-default" },
|
|
19
|
+
video: {
|
|
20
|
+
evidence: "The user explicitly requested video delivery.",
|
|
21
|
+
mode: "user-requested",
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe("Toolcraft image export settings acceptance contract", () => {
|
|
12
26
|
it("requires still-output apps to expose image export format and resolution settings", () => {
|
|
13
27
|
const schemaWithoutImageExportSettings = defineContractSchemaFixture({
|
|
14
28
|
canvas: {
|
|
@@ -58,13 +72,15 @@ describe("Toolcraft image and video export settings acceptance contract", () =>
|
|
|
58
72
|
componentType: "panelActions",
|
|
59
73
|
evidence: "exported-bytes",
|
|
60
74
|
expectedObservable: "Export PNG creates output bytes and reads image format, image resolution, background color, and include-background state.",
|
|
75
|
+
exportArtifactCoverage: "all-required-image-export-behavior",
|
|
61
76
|
fixture: "export fixture",
|
|
62
77
|
id: "actions.output",
|
|
63
78
|
kind: "control",
|
|
64
79
|
target: "actions.output",
|
|
65
|
-
userAction: "Toggle Include off, verify preview has no product background, export PNG with alpha, and verify
|
|
80
|
+
userAction: "Toggle Include off, verify preview has no product background, export PNG with alpha, and verify the image artifact preserves transparency.",
|
|
66
81
|
},
|
|
67
82
|
],
|
|
83
|
+
productReadiness: imageOnlyProductReadiness,
|
|
68
84
|
}),
|
|
69
85
|
).toEqual(
|
|
70
86
|
expect.arrayContaining([
|
|
@@ -142,6 +158,7 @@ describe("Toolcraft image and video export settings acceptance contract", () =>
|
|
|
142
158
|
componentType: "panelActions",
|
|
143
159
|
evidence: "exported-bytes",
|
|
144
160
|
expectedObservable: "Export PNG creates output bytes and reads image format, image resolution, background color, and include-background state. JPG changes file type; 8K changes exported pixel dimensions to an 8192px long edge.",
|
|
161
|
+
exportArtifactCoverage: "all-required-image-export-behavior",
|
|
145
162
|
fixture: "export fixture",
|
|
146
163
|
id: "actions.output",
|
|
147
164
|
kind: "control",
|
|
@@ -149,6 +166,7 @@ describe("Toolcraft image and video export settings acceptance contract", () =>
|
|
|
149
166
|
userAction: "Set format to JPG and resolution to 8K, then export and decode the output image to verify file type and long-edge dimensions.",
|
|
150
167
|
},
|
|
151
168
|
],
|
|
169
|
+
productReadiness: imageOnlyProductReadiness,
|
|
152
170
|
}),
|
|
153
171
|
).not.toEqual(
|
|
154
172
|
expect.arrayContaining([
|
|
@@ -159,7 +177,7 @@ describe("Toolcraft image and video export settings acceptance contract", () =>
|
|
|
159
177
|
);
|
|
160
178
|
});
|
|
161
179
|
|
|
162
|
-
it("requires
|
|
180
|
+
it("requires explicit image-plus-video delivery to expose Image Export before Video Export", () => {
|
|
163
181
|
const schemaWithoutImageSettings = defineContractSchemaFixture({
|
|
164
182
|
canvas: {
|
|
165
183
|
enabled: true,
|
|
@@ -211,19 +229,24 @@ describe("Toolcraft image and video export settings acceptance contract", () =>
|
|
|
211
229
|
{
|
|
212
230
|
actionCoverage: ["export.video", "export.png"],
|
|
213
231
|
automated: true,
|
|
214
|
-
automatedTestName: "exports
|
|
232
|
+
automatedTestName: "exports image and explicitly requested video output",
|
|
215
233
|
browser: true,
|
|
216
234
|
browserTestName: "browser: exports video and image output",
|
|
217
235
|
componentType: "panelActions",
|
|
218
236
|
evidence: "exported-bytes",
|
|
219
237
|
expectedObservable: "Export Video and Export PNG both create output bytes and read their runtime export settings.",
|
|
220
|
-
|
|
238
|
+
exportArtifactCoverage: [
|
|
239
|
+
"all-required-image-export-behavior",
|
|
240
|
+
"all-required-video-export-behavior",
|
|
241
|
+
],
|
|
242
|
+
fixture: "explicit image-plus-video export fixture",
|
|
221
243
|
id: "actions.output",
|
|
222
244
|
kind: "control",
|
|
223
245
|
target: "actions.output",
|
|
224
|
-
userAction: "Export video and PNG
|
|
246
|
+
userAction: "Export video and PNG with their configured settings, then verify both files exist.",
|
|
225
247
|
},
|
|
226
248
|
],
|
|
249
|
+
productReadiness: imageAndVideoProductReadiness,
|
|
227
250
|
}),
|
|
228
251
|
).toEqual(
|
|
229
252
|
expect.arrayContaining([
|
|
@@ -234,7 +257,7 @@ describe("Toolcraft image and video export settings acceptance contract", () =>
|
|
|
234
257
|
);
|
|
235
258
|
});
|
|
236
259
|
|
|
237
|
-
it("accepts
|
|
260
|
+
it("accepts explicit image-plus-video delivery with Image Export immediately before Video Export", () => {
|
|
238
261
|
const schemaWithDualExportSettings = defineContractSchemaFixture({
|
|
239
262
|
canvas: {
|
|
240
263
|
enabled: true,
|
|
@@ -303,19 +326,24 @@ describe("Toolcraft image and video export settings acceptance contract", () =>
|
|
|
303
326
|
{
|
|
304
327
|
actionCoverage: ["export.video", "export.png"],
|
|
305
328
|
automated: true,
|
|
306
|
-
automatedTestName: "exports
|
|
329
|
+
automatedTestName: "exports image and explicitly requested video output",
|
|
307
330
|
browser: true,
|
|
308
331
|
browserTestName: "browser: exports video and image output",
|
|
309
332
|
componentType: "panelActions",
|
|
310
333
|
evidence: "exported-bytes",
|
|
311
334
|
expectedObservable: "Export Video and Export PNG both create output bytes and read their runtime export settings.",
|
|
312
|
-
|
|
335
|
+
exportArtifactCoverage: [
|
|
336
|
+
"all-required-image-export-behavior",
|
|
337
|
+
"all-required-video-export-behavior",
|
|
338
|
+
],
|
|
339
|
+
fixture: "explicit image-plus-video export fixture",
|
|
313
340
|
id: "actions.output",
|
|
314
341
|
kind: "control",
|
|
315
342
|
target: "actions.output",
|
|
316
343
|
userAction: "Choose JPG and 8K, choose MP4 and Current, then export PNG and video and verify both outputs use their selected settings.",
|
|
317
344
|
},
|
|
318
345
|
],
|
|
346
|
+
productReadiness: imageAndVideoProductReadiness,
|
|
319
347
|
}),
|
|
320
348
|
).not.toEqual(
|
|
321
349
|
expect.arrayContaining([
|
|
@@ -100,6 +100,10 @@ function readiness(
|
|
|
100
100
|
interactionOwnership: readonly ToolcraftInteractionOwnershipEntry[],
|
|
101
101
|
): ToolcraftProductReadiness {
|
|
102
102
|
return {
|
|
103
|
+
exportIntent: {
|
|
104
|
+
image: { mode: "toolcraft-default" },
|
|
105
|
+
video: { mode: "not-requested" },
|
|
106
|
+
},
|
|
103
107
|
interactionOwnership,
|
|
104
108
|
mode: "product",
|
|
105
109
|
productName: "Interaction fixture",
|
|
@@ -151,6 +155,10 @@ function acceptance({
|
|
|
151
155
|
describe("Toolcraft interaction surface ownership", () => {
|
|
152
156
|
it("runs ownership validation through the protected acceptance pipeline", () => {
|
|
153
157
|
const productReadiness = {
|
|
158
|
+
exportIntent: {
|
|
159
|
+
image: { mode: "toolcraft-default" },
|
|
160
|
+
video: { mode: "not-requested" },
|
|
161
|
+
},
|
|
154
162
|
mode: "product",
|
|
155
163
|
productName: "Legacy fixture",
|
|
156
164
|
productSummary: "A product declaration created before interaction ownership.",
|
|
@@ -172,6 +180,10 @@ describe("Toolcraft interaction surface ownership", () => {
|
|
|
172
180
|
|
|
173
181
|
it("rejects product readiness that omits the ownership inventory", () => {
|
|
174
182
|
const productReadiness = {
|
|
183
|
+
exportIntent: {
|
|
184
|
+
image: { mode: "toolcraft-default" },
|
|
185
|
+
video: { mode: "not-requested" },
|
|
186
|
+
},
|
|
175
187
|
mode: "product",
|
|
176
188
|
productName: "Legacy fixture",
|
|
177
189
|
productSummary: "A product declaration created before interaction ownership.",
|