@pixel-point/toolcraft 0.0.8 → 0.0.9
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.mjs +34 -5
- package/src/generate.test.mjs +12 -0
- package/src/package-json.mjs +15 -0
- package/src/package-json.test.mjs +14 -1
- package/templates/runtime/contracts/component-contracts.test.ts +104 -14
- package/templates/runtime/contracts/component-contracts.ts +54 -22
- package/templates/runtime/contracts/decision-contracts.test.ts +5 -0
- package/templates/runtime/contracts/decision-contracts.ts +3 -3
- package/templates/runtime/react/controls-panel.test.tsx +374 -13
- package/templates/runtime/react/controls-panel.tsx +65 -4
- package/templates/runtime/schema/define-toolcraft.test.ts +45 -1
- package/templates/runtime/schema/define-toolcraft.ts +25 -1
- package/templates/runtime/schema/types.ts +3 -0
- package/templates/runtime/testing/performance.test.ts +134 -0
- package/templates/runtime/testing/performance.ts +34 -4
- package/templates/starter/AGENTS.md +4 -4
- package/templates/starter/docs/toolcraft/README.md +1 -1
- package/templates/starter/docs/toolcraft/acceptance-testing.md +5 -3
- package/templates/starter/docs/toolcraft/assembly-workflow.md +9 -5
- package/templates/starter/docs/toolcraft/component-rules.md +32 -11
- package/templates/starter/docs/toolcraft/performance.md +7 -1
- package/templates/starter/docs/toolcraft/schema-reference.md +43 -14
- package/templates/starter/gitignore +1 -0
- package/templates/starter/package.json +2 -0
- package/templates/starter/scripts/run-vite-on-free-port.mjs +39 -4
- package/templates/starter/scripts/toolcraft-port.mjs +102 -0
- package/templates/starter/scripts/toolcraft-port.test.mjs +60 -1
- package/templates/starter/src/app/starter-acceptance.test.ts +739 -66
- package/templates/starter/src/app/starter-acceptance.ts +471 -12
- package/templates/ui/components/control-layout/index.tsx +8 -3
- package/templates/ui/components/controls/actions/actions-control.tsx +11 -3
- package/templates/ui/components/controls/code-textarea/code-textarea-control.tsx +7 -3
- package/templates/ui/components/controls/color/index.ts +4 -1
- package/templates/ui/components/controls/color/style-guide-color-picker-logic.ts +7 -2
- package/templates/ui/components/controls/color/style-guide-color-picker.tsx +2 -2
- package/templates/ui/components/controls/index.ts +2 -0
- package/templates/ui/components/controls/range-input/range-input-control.tsx +12 -4
- package/templates/ui/components/controls/select/select-control.tsx +9 -4
- package/templates/ui/components/controls/slider/slider-value.ts +0 -1
- package/templates/ui/components/controls/text-input/text-input-control.tsx +4 -1
- package/templates/ui/components/controls/vector/index.ts +1 -0
- package/templates/ui/components/controls/vector/vector-control.tsx +84 -8
- package/templates/ui/components/panel/panel-section.tsx +29 -5
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
getToolcraftControlOrderTargets,
|
|
14
14
|
type ToolcraftComponentAcceptance,
|
|
15
15
|
starterAcceptance,
|
|
16
|
+
starterControlSectionInventory,
|
|
16
17
|
starterProductReadiness,
|
|
17
18
|
starterTransferMode,
|
|
18
19
|
validateToolcraftAcceptanceCoverage,
|
|
@@ -806,6 +807,26 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
806
807
|
expect(validateToolcraftAcceptanceCoverage(starterSchema, starterAcceptance)).toEqual([]);
|
|
807
808
|
});
|
|
808
809
|
|
|
810
|
+
it("requires generated product apps to publish a control section inventory", () => {
|
|
811
|
+
if (!schemaHasProductSurface()) {
|
|
812
|
+
expect(starterControlSectionInventory).toEqual([]);
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
expect(
|
|
817
|
+
starterControlSectionInventory.length,
|
|
818
|
+
"Product apps must export starterControlSectionInventory so section grouping decisions are machine-checkable.",
|
|
819
|
+
).toBeGreaterThan(0);
|
|
820
|
+
expect(
|
|
821
|
+
validateToolcraftAcceptanceCoverage(
|
|
822
|
+
starterSchema,
|
|
823
|
+
starterAcceptance,
|
|
824
|
+
starterTransferMode,
|
|
825
|
+
starterControlSectionInventory,
|
|
826
|
+
),
|
|
827
|
+
).toEqual([]);
|
|
828
|
+
});
|
|
829
|
+
|
|
809
830
|
it("requires fileDrop acceptance to prove upload, clear, and reset lifecycle", () => {
|
|
810
831
|
const fileDropSchema = defineToolcraft({
|
|
811
832
|
canvas: { enabled: true },
|
|
@@ -994,7 +1015,7 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
994
1015
|
|
|
995
1016
|
expect(validateToolcraftAcceptanceCoverage(fixedOutputSchema, starterAcceptance)).toEqual(
|
|
996
1017
|
expect.arrayContaining([
|
|
997
|
-
'canvas.sizing mode "fixed-output" requires a runtime acceptance entry with canvasSizingCoverage "fixed-output-size" explaining why width and height are intentionally non-editable.
|
|
1018
|
+
'canvas.sizing mode "fixed-output" requires a runtime acceptance entry with canvasSizingCoverage "fixed-output-size" explaining why width and height are intentionally non-editable. Product/output apps must use "editable-output"; user-provided, reference, fixed-format, or base/default sizes belong in canvas.size as editable initial values.',
|
|
998
1019
|
]),
|
|
999
1020
|
);
|
|
1000
1021
|
});
|
|
@@ -1047,7 +1068,118 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
1047
1068
|
]),
|
|
1048
1069
|
).toEqual(
|
|
1049
1070
|
expect.arrayContaining([
|
|
1050
|
-
'canvas.sizing canvasSizingCoverage "fixed-output-size" must explain why the
|
|
1071
|
+
'canvas.sizing canvasSizingCoverage "fixed-output-size" must explain why the output dimensions are intentionally fixed for a non-product/internal fixture, not merely initialized from a default size.',
|
|
1072
|
+
]),
|
|
1073
|
+
);
|
|
1074
|
+
});
|
|
1075
|
+
|
|
1076
|
+
it("rejects fixed canvas sizing justified only by a missing reference size editor", () => {
|
|
1077
|
+
const fixedOutputSchema = defineToolcraft({
|
|
1078
|
+
canvas: {
|
|
1079
|
+
enabled: true,
|
|
1080
|
+
size: { height: 1080, unit: "px", width: 1920 },
|
|
1081
|
+
sizing: { mode: "fixed-output" },
|
|
1082
|
+
},
|
|
1083
|
+
panels: {
|
|
1084
|
+
controls: {
|
|
1085
|
+
sections: [
|
|
1086
|
+
{
|
|
1087
|
+
controls: {
|
|
1088
|
+
prompt: {
|
|
1089
|
+
defaultValue: "Describe the effect",
|
|
1090
|
+
label: "Prompt",
|
|
1091
|
+
orderRole: "input",
|
|
1092
|
+
target: "generation.prompt",
|
|
1093
|
+
type: "text",
|
|
1094
|
+
},
|
|
1095
|
+
},
|
|
1096
|
+
title: "Generation",
|
|
1097
|
+
},
|
|
1098
|
+
],
|
|
1099
|
+
title: "Controls",
|
|
1100
|
+
},
|
|
1101
|
+
},
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
expect(
|
|
1105
|
+
validateToolcraftAcceptanceCoverage(fixedOutputSchema, [
|
|
1106
|
+
...starterAcceptance,
|
|
1107
|
+
{
|
|
1108
|
+
automated: true,
|
|
1109
|
+
automatedTestName: "canvas output remains fixed",
|
|
1110
|
+
browser: true,
|
|
1111
|
+
browserTestName: "browser: canvas output remains fixed",
|
|
1112
|
+
canvasSizingCoverage: "fixed-output-size",
|
|
1113
|
+
componentType: "fixed-output canvas",
|
|
1114
|
+
evidence: "product-output",
|
|
1115
|
+
expectedObservable:
|
|
1116
|
+
"The WebGL output remains fixed at 1920x1080 because the reference app has no user-facing output size editor.",
|
|
1117
|
+
fixture: "default canvas fixture",
|
|
1118
|
+
id: "canvas.sizing",
|
|
1119
|
+
kind: "runtime",
|
|
1120
|
+
userAction: "Open the app.",
|
|
1121
|
+
},
|
|
1122
|
+
]),
|
|
1123
|
+
).toEqual(
|
|
1124
|
+
expect.arrayContaining([
|
|
1125
|
+
expect.stringContaining("cannot be justified by the reference or previous app lacking a size editor"),
|
|
1126
|
+
]),
|
|
1127
|
+
);
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1130
|
+
it("rejects fixed canvas sizing for exportable product apps even when reference dimensions are fixed", () => {
|
|
1131
|
+
const fixedExportSchema = defineToolcraft({
|
|
1132
|
+
canvas: {
|
|
1133
|
+
enabled: true,
|
|
1134
|
+
size: { height: 900, unit: "px", width: 1440 },
|
|
1135
|
+
sizing: { mode: "fixed-output" },
|
|
1136
|
+
},
|
|
1137
|
+
panels: {
|
|
1138
|
+
controls: {
|
|
1139
|
+
sections: [
|
|
1140
|
+
{
|
|
1141
|
+
controls: {
|
|
1142
|
+
outputActions: {
|
|
1143
|
+
actions: [
|
|
1144
|
+
{
|
|
1145
|
+
icon: "export",
|
|
1146
|
+
label: "Export PNG",
|
|
1147
|
+
value: "export.png",
|
|
1148
|
+
},
|
|
1149
|
+
],
|
|
1150
|
+
target: "actions.output",
|
|
1151
|
+
type: "panelActions",
|
|
1152
|
+
},
|
|
1153
|
+
},
|
|
1154
|
+
},
|
|
1155
|
+
],
|
|
1156
|
+
title: "Controls",
|
|
1157
|
+
},
|
|
1158
|
+
},
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
expect(
|
|
1162
|
+
validateToolcraftAcceptanceCoverage(fixedExportSchema, [
|
|
1163
|
+
...starterAcceptance,
|
|
1164
|
+
{
|
|
1165
|
+
automated: true,
|
|
1166
|
+
automatedTestName: "fixed reference size is preserved",
|
|
1167
|
+
browser: true,
|
|
1168
|
+
browserTestName: "browser: fixed reference size is preserved",
|
|
1169
|
+
canvasSizingCoverage: "fixed-output-size",
|
|
1170
|
+
componentType: "fixed-output canvas",
|
|
1171
|
+
evidence: "product-output",
|
|
1172
|
+
expectedObservable:
|
|
1173
|
+
"The exported shader canvas remains reference-defined and fixed at 1440x900.",
|
|
1174
|
+
fixture: "shader reference fixture",
|
|
1175
|
+
id: "canvas.sizing",
|
|
1176
|
+
kind: "runtime",
|
|
1177
|
+
userAction: "Open the app.",
|
|
1178
|
+
},
|
|
1179
|
+
]),
|
|
1180
|
+
).toEqual(
|
|
1181
|
+
expect.arrayContaining([
|
|
1182
|
+
'Product/output apps with export actions must use canvas.sizing mode "editable-output" so Aspect ratio, Canvas width, and Canvas height are always available. Put reference, fixed-format, or user-requested dimensions in canvas.size as the initial value instead of hiding size controls with "fixed-output".',
|
|
1051
1183
|
]),
|
|
1052
1184
|
);
|
|
1053
1185
|
});
|
|
@@ -2109,7 +2241,6 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
2109
2241
|
step: 0.1,
|
|
2110
2242
|
target: "field.speed",
|
|
2111
2243
|
type: "slider",
|
|
2112
|
-
unit: "x",
|
|
2113
2244
|
},
|
|
2114
2245
|
},
|
|
2115
2246
|
layoutGroups: [
|
|
@@ -2167,6 +2298,57 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
2167
2298
|
);
|
|
2168
2299
|
});
|
|
2169
2300
|
|
|
2301
|
+
it("rejects x units on slider value labels", () => {
|
|
2302
|
+
const schema = defineToolcraft({
|
|
2303
|
+
canvas: { enabled: true },
|
|
2304
|
+
panels: {
|
|
2305
|
+
controls: {
|
|
2306
|
+
sections: [
|
|
2307
|
+
{
|
|
2308
|
+
controls: {
|
|
2309
|
+
strength: {
|
|
2310
|
+
defaultValue: 0.4,
|
|
2311
|
+
label: "Strength",
|
|
2312
|
+
max: 1,
|
|
2313
|
+
min: 0,
|
|
2314
|
+
step: 0.01,
|
|
2315
|
+
target: "glass.strength",
|
|
2316
|
+
type: "slider",
|
|
2317
|
+
unit: "x",
|
|
2318
|
+
},
|
|
2319
|
+
},
|
|
2320
|
+
title: "Glass",
|
|
2321
|
+
},
|
|
2322
|
+
],
|
|
2323
|
+
title: "Controls",
|
|
2324
|
+
},
|
|
2325
|
+
},
|
|
2326
|
+
});
|
|
2327
|
+
|
|
2328
|
+
expect(
|
|
2329
|
+
validateToolcraftAcceptanceCoverage(schema, [
|
|
2330
|
+
{
|
|
2331
|
+
automated: true,
|
|
2332
|
+
automatedTestName: "strength changes glass output",
|
|
2333
|
+
browser: true,
|
|
2334
|
+
browserTestName: "browser: strength slider changes glass output",
|
|
2335
|
+
componentType: "slider",
|
|
2336
|
+
evidence: "rendered-pixels",
|
|
2337
|
+
expectedObservable: "Changing Strength changes the rendered glass strength.",
|
|
2338
|
+
fixture: "glass strength fixture",
|
|
2339
|
+
id: "glass.strength",
|
|
2340
|
+
kind: "control",
|
|
2341
|
+
target: "glass.strength",
|
|
2342
|
+
userAction: "Drag the Strength slider.",
|
|
2343
|
+
},
|
|
2344
|
+
]),
|
|
2345
|
+
).toEqual(
|
|
2346
|
+
expect.arrayContaining([
|
|
2347
|
+
'Glass / strength (glass.strength) uses unit "x", but Toolcraft slider values do not use x suffixes. Omit unit for scale, multiplier, intensity, opacity, strength, depth, and shader amount values unless a real measurement unit applies.',
|
|
2348
|
+
]),
|
|
2349
|
+
);
|
|
2350
|
+
});
|
|
2351
|
+
|
|
2170
2352
|
it("accepts compound controls only when every semantic value part is declared", () => {
|
|
2171
2353
|
const gradientSchema = defineToolcraft({
|
|
2172
2354
|
canvas: { enabled: true },
|
|
@@ -3872,6 +4054,78 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
3872
4054
|
);
|
|
3873
4055
|
});
|
|
3874
4056
|
|
|
4057
|
+
it("rejects single Actions controls that duplicate their only button label", () => {
|
|
4058
|
+
const schemaWithDuplicateActionLabel = defineToolcraft({
|
|
4059
|
+
canvas: { enabled: true },
|
|
4060
|
+
panels: {
|
|
4061
|
+
controls: {
|
|
4062
|
+
sections: [
|
|
4063
|
+
{
|
|
4064
|
+
controls: {
|
|
4065
|
+
wash: {
|
|
4066
|
+
actions: [{ label: "Wash", value: "wash" }],
|
|
4067
|
+
defaultValue: null,
|
|
4068
|
+
label: "Wash",
|
|
4069
|
+
target: "flow.washSignal",
|
|
4070
|
+
type: "actions",
|
|
4071
|
+
},
|
|
4072
|
+
},
|
|
4073
|
+
title: "Flow",
|
|
4074
|
+
},
|
|
4075
|
+
],
|
|
4076
|
+
title: "Controls",
|
|
4077
|
+
},
|
|
4078
|
+
},
|
|
4079
|
+
});
|
|
4080
|
+
|
|
4081
|
+
expect(
|
|
4082
|
+
validateToolcraftAcceptanceCoverage(schemaWithDuplicateActionLabel, [
|
|
4083
|
+
makeControlAcceptance("flow.washSignal", "actions"),
|
|
4084
|
+
]),
|
|
4085
|
+
).toEqual(
|
|
4086
|
+
expect.arrayContaining([
|
|
4087
|
+
expect.stringContaining(
|
|
4088
|
+
'flow.washSignal) single Actions control label "Wash" duplicates its only button label "Wash". Keep the button as the command and use a short context label such as "Ink wash", "Palette action", or "Current layer".',
|
|
4089
|
+
),
|
|
4090
|
+
]),
|
|
4091
|
+
);
|
|
4092
|
+
});
|
|
4093
|
+
|
|
4094
|
+
it("allows single Actions controls with a concise context label", () => {
|
|
4095
|
+
const schemaWithContextActionLabel = defineToolcraft({
|
|
4096
|
+
canvas: { enabled: true },
|
|
4097
|
+
panels: {
|
|
4098
|
+
controls: {
|
|
4099
|
+
sections: [
|
|
4100
|
+
{
|
|
4101
|
+
controls: {
|
|
4102
|
+
wash: {
|
|
4103
|
+
actions: [{ label: "Wash", value: "wash" }],
|
|
4104
|
+
defaultValue: null,
|
|
4105
|
+
label: "Ink wash",
|
|
4106
|
+
target: "flow.washSignal",
|
|
4107
|
+
type: "actions",
|
|
4108
|
+
},
|
|
4109
|
+
},
|
|
4110
|
+
title: "Flow",
|
|
4111
|
+
},
|
|
4112
|
+
],
|
|
4113
|
+
title: "Controls",
|
|
4114
|
+
},
|
|
4115
|
+
},
|
|
4116
|
+
});
|
|
4117
|
+
|
|
4118
|
+
const errors = validateToolcraftAcceptanceCoverage(schemaWithContextActionLabel, [
|
|
4119
|
+
makeControlAcceptance("flow.washSignal", "actions"),
|
|
4120
|
+
]);
|
|
4121
|
+
|
|
4122
|
+
expect(errors).not.toEqual(
|
|
4123
|
+
expect.arrayContaining([
|
|
4124
|
+
expect.stringContaining("single Actions control label"),
|
|
4125
|
+
]),
|
|
4126
|
+
);
|
|
4127
|
+
});
|
|
4128
|
+
|
|
3875
4129
|
it("allows short Include toggle plus an unlabeled background color in the required row", () => {
|
|
3876
4130
|
const schema = defineToolcraft({
|
|
3877
4131
|
canvas: { enabled: true },
|
|
@@ -3941,7 +4195,7 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
3941
4195
|
},
|
|
3942
4196
|
duration: {
|
|
3943
4197
|
defaultValue: "8",
|
|
3944
|
-
label:
|
|
4198
|
+
label: false,
|
|
3945
4199
|
target: "animation.duration",
|
|
3946
4200
|
type: "text",
|
|
3947
4201
|
},
|
|
@@ -3971,7 +4225,7 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
3971
4225
|
);
|
|
3972
4226
|
});
|
|
3973
4227
|
|
|
3974
|
-
it("rejects
|
|
4228
|
+
it("rejects CodeTextarea for short single-line text content", () => {
|
|
3975
4229
|
const schema = defineToolcraft({
|
|
3976
4230
|
canvas: { enabled: true },
|
|
3977
4231
|
panels: {
|
|
@@ -3979,27 +4233,14 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
3979
4233
|
sections: [
|
|
3980
4234
|
{
|
|
3981
4235
|
controls: {
|
|
3982
|
-
|
|
3983
|
-
defaultValue:
|
|
3984
|
-
label: "
|
|
3985
|
-
target: "
|
|
3986
|
-
type: "
|
|
3987
|
-
},
|
|
3988
|
-
background: {
|
|
3989
|
-
defaultValue: "#0F0F0F",
|
|
3990
|
-
label: "Background",
|
|
3991
|
-
target: "appearance.background",
|
|
3992
|
-
type: "color",
|
|
4236
|
+
buttonText: {
|
|
4237
|
+
defaultValue: "Glass",
|
|
4238
|
+
label: "Text",
|
|
4239
|
+
target: "button.text",
|
|
4240
|
+
type: "code",
|
|
3993
4241
|
},
|
|
3994
4242
|
},
|
|
3995
|
-
|
|
3996
|
-
{
|
|
3997
|
-
columns: 2,
|
|
3998
|
-
controls: ["transparentBackground", "background"],
|
|
3999
|
-
layout: "inline",
|
|
4000
|
-
},
|
|
4001
|
-
],
|
|
4002
|
-
title: "Background",
|
|
4243
|
+
title: "Button",
|
|
4003
4244
|
},
|
|
4004
4245
|
],
|
|
4005
4246
|
title: "Controls",
|
|
@@ -4009,19 +4250,16 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
4009
4250
|
|
|
4010
4251
|
expect(
|
|
4011
4252
|
validateToolcraftAcceptanceCoverage(schema, [
|
|
4012
|
-
makeControlAcceptance("
|
|
4013
|
-
makeControlAcceptance("appearance.background", "color"),
|
|
4253
|
+
makeControlAcceptance("button.text", "code"),
|
|
4014
4254
|
]),
|
|
4015
4255
|
).toEqual(
|
|
4016
4256
|
expect.arrayContaining([
|
|
4017
|
-
expect.stringContaining(
|
|
4018
|
-
'Background layoutGroups inline row "transparentBackground, background" includes toggle label transparentBackground "Transparent background" that is too long for a compact toggle-plus-parameter row.',
|
|
4019
|
-
),
|
|
4257
|
+
expect.stringContaining("uses CodeTextarea for short single-line text"),
|
|
4020
4258
|
]),
|
|
4021
4259
|
);
|
|
4022
4260
|
});
|
|
4023
4261
|
|
|
4024
|
-
it("allows
|
|
4262
|
+
it("allows CodeTextarea when a short default documents long multiline intent", () => {
|
|
4025
4263
|
const schema = defineToolcraft({
|
|
4026
4264
|
canvas: { enabled: true },
|
|
4027
4265
|
panels: {
|
|
@@ -4029,27 +4267,16 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
4029
4267
|
sections: [
|
|
4030
4268
|
{
|
|
4031
4269
|
controls: {
|
|
4032
|
-
|
|
4033
|
-
defaultValue:
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
defaultValue: false,
|
|
4040
|
-
label: "Loop",
|
|
4041
|
-
target: "animation.loop",
|
|
4042
|
-
type: "switch",
|
|
4270
|
+
prompt: {
|
|
4271
|
+
defaultValue: "Describe the scene",
|
|
4272
|
+
description:
|
|
4273
|
+
"Long multiline prompt content for generated output.",
|
|
4274
|
+
label: "Prompt",
|
|
4275
|
+
target: "generation.prompt",
|
|
4276
|
+
type: "code",
|
|
4043
4277
|
},
|
|
4044
4278
|
},
|
|
4045
|
-
|
|
4046
|
-
{
|
|
4047
|
-
columns: 2,
|
|
4048
|
-
controls: ["glow", "loop"],
|
|
4049
|
-
layout: "inline",
|
|
4050
|
-
},
|
|
4051
|
-
],
|
|
4052
|
-
title: "Style",
|
|
4279
|
+
title: "Generation",
|
|
4053
4280
|
},
|
|
4054
4281
|
],
|
|
4055
4282
|
title: "Controls",
|
|
@@ -4057,10 +4284,211 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
4057
4284
|
},
|
|
4058
4285
|
});
|
|
4059
4286
|
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4287
|
+
expect(
|
|
4288
|
+
validateToolcraftAcceptanceCoverage(schema, [
|
|
4289
|
+
makeControlAcceptance("generation.prompt", "code"),
|
|
4290
|
+
]),
|
|
4291
|
+
).not.toEqual(
|
|
4292
|
+
expect.arrayContaining([
|
|
4293
|
+
expect.stringContaining("uses CodeTextarea for short single-line text"),
|
|
4294
|
+
]),
|
|
4295
|
+
);
|
|
4296
|
+
});
|
|
4297
|
+
|
|
4298
|
+
it("rejects visible parameter labels beside one related toggle", () => {
|
|
4299
|
+
const schema = defineToolcraft({
|
|
4300
|
+
canvas: { enabled: true },
|
|
4301
|
+
panels: {
|
|
4302
|
+
controls: {
|
|
4303
|
+
sections: [
|
|
4304
|
+
{
|
|
4305
|
+
controls: {
|
|
4306
|
+
loop: {
|
|
4307
|
+
defaultValue: true,
|
|
4308
|
+
label: "Loop",
|
|
4309
|
+
target: "animation.loop",
|
|
4310
|
+
type: "switch",
|
|
4311
|
+
},
|
|
4312
|
+
duration: {
|
|
4313
|
+
defaultValue: "8",
|
|
4314
|
+
label: "Duration",
|
|
4315
|
+
target: "animation.duration",
|
|
4316
|
+
type: "text",
|
|
4317
|
+
},
|
|
4318
|
+
},
|
|
4319
|
+
layoutGroups: [
|
|
4320
|
+
{
|
|
4321
|
+
columns: 2,
|
|
4322
|
+
controls: ["loop", "duration"],
|
|
4323
|
+
layout: "inline",
|
|
4324
|
+
},
|
|
4325
|
+
],
|
|
4326
|
+
title: "Playback",
|
|
4327
|
+
},
|
|
4328
|
+
],
|
|
4329
|
+
title: "Controls",
|
|
4330
|
+
},
|
|
4331
|
+
},
|
|
4332
|
+
});
|
|
4333
|
+
|
|
4334
|
+
expect(
|
|
4335
|
+
validateToolcraftAcceptanceCoverage(schema, [
|
|
4336
|
+
makeControlAcceptance("animation.loop", "switch"),
|
|
4337
|
+
makeControlAcceptance("animation.duration", "text"),
|
|
4338
|
+
]),
|
|
4339
|
+
).toEqual(
|
|
4340
|
+
expect.arrayContaining([
|
|
4341
|
+
expect.stringContaining(
|
|
4342
|
+
'Playback layoutGroups inline row "loop, duration" pairs a toggle with parameter labels duration "Duration". In toggle-plus-parameter rows, the non-toggle parameter must use label false; if that label is needed, stack the controls instead.',
|
|
4343
|
+
),
|
|
4344
|
+
]),
|
|
4345
|
+
);
|
|
4346
|
+
});
|
|
4347
|
+
|
|
4348
|
+
it("rejects segmented controls in inline half-width layout rows", () => {
|
|
4349
|
+
const schema = defineToolcraft({
|
|
4350
|
+
canvas: { enabled: true },
|
|
4351
|
+
panels: {
|
|
4352
|
+
controls: {
|
|
4353
|
+
sections: [
|
|
4354
|
+
{
|
|
4355
|
+
controls: {
|
|
4356
|
+
includeText: {
|
|
4357
|
+
defaultValue: true,
|
|
4358
|
+
label: "Include",
|
|
4359
|
+
target: "text.enabled",
|
|
4360
|
+
type: "switch",
|
|
4361
|
+
},
|
|
4362
|
+
dragTarget: {
|
|
4363
|
+
defaultValue: "glass",
|
|
4364
|
+
label: "Drag",
|
|
4365
|
+
options: [
|
|
4366
|
+
{ label: "Glass", value: "glass" },
|
|
4367
|
+
{ label: "Text", value: "text" },
|
|
4368
|
+
],
|
|
4369
|
+
target: "text.dragTarget",
|
|
4370
|
+
type: "segmented",
|
|
4371
|
+
},
|
|
4372
|
+
},
|
|
4373
|
+
layoutGroups: [
|
|
4374
|
+
{
|
|
4375
|
+
columns: 2,
|
|
4376
|
+
controls: ["includeText", "dragTarget"],
|
|
4377
|
+
layout: "inline",
|
|
4378
|
+
},
|
|
4379
|
+
],
|
|
4380
|
+
title: "Glass Text",
|
|
4381
|
+
},
|
|
4382
|
+
],
|
|
4383
|
+
title: "Controls",
|
|
4384
|
+
},
|
|
4385
|
+
},
|
|
4386
|
+
});
|
|
4387
|
+
|
|
4388
|
+
expect(
|
|
4389
|
+
validateToolcraftAcceptanceCoverage(schema, [
|
|
4390
|
+
makeControlAcceptance("text.enabled", "switch"),
|
|
4391
|
+
makeControlAcceptance("text.dragTarget", "segmented"),
|
|
4392
|
+
]),
|
|
4393
|
+
).toEqual(
|
|
4394
|
+
expect.arrayContaining([
|
|
4395
|
+
expect.stringContaining(
|
|
4396
|
+
'Glass Text layoutGroups inline row "includeText, dragTarget" includes segmented control dragTarget. Segmented is full-width and must not share a two-column or half-width row; use Select when a finite choice must fit beside another control.',
|
|
4397
|
+
),
|
|
4398
|
+
]),
|
|
4399
|
+
);
|
|
4400
|
+
});
|
|
4401
|
+
|
|
4402
|
+
it("rejects long visible toggle labels beside one related parameter", () => {
|
|
4403
|
+
const schema = defineToolcraft({
|
|
4404
|
+
canvas: { enabled: true },
|
|
4405
|
+
panels: {
|
|
4406
|
+
controls: {
|
|
4407
|
+
sections: [
|
|
4408
|
+
{
|
|
4409
|
+
controls: {
|
|
4410
|
+
transparentBackground: {
|
|
4411
|
+
defaultValue: true,
|
|
4412
|
+
label: "Transparent background",
|
|
4413
|
+
target: "export.transparentBackground",
|
|
4414
|
+
type: "switch",
|
|
4415
|
+
},
|
|
4416
|
+
background: {
|
|
4417
|
+
defaultValue: "#0F0F0F",
|
|
4418
|
+
label: "Background",
|
|
4419
|
+
target: "appearance.background",
|
|
4420
|
+
type: "color",
|
|
4421
|
+
},
|
|
4422
|
+
},
|
|
4423
|
+
layoutGroups: [
|
|
4424
|
+
{
|
|
4425
|
+
columns: 2,
|
|
4426
|
+
controls: ["transparentBackground", "background"],
|
|
4427
|
+
layout: "inline",
|
|
4428
|
+
},
|
|
4429
|
+
],
|
|
4430
|
+
title: "Background",
|
|
4431
|
+
},
|
|
4432
|
+
],
|
|
4433
|
+
title: "Controls",
|
|
4434
|
+
},
|
|
4435
|
+
},
|
|
4436
|
+
});
|
|
4437
|
+
|
|
4438
|
+
expect(
|
|
4439
|
+
validateToolcraftAcceptanceCoverage(schema, [
|
|
4440
|
+
makeControlAcceptance("export.transparentBackground", "switch"),
|
|
4441
|
+
makeControlAcceptance("appearance.background", "color"),
|
|
4442
|
+
]),
|
|
4443
|
+
).toEqual(
|
|
4444
|
+
expect.arrayContaining([
|
|
4445
|
+
expect.stringContaining(
|
|
4446
|
+
'Background layoutGroups inline row "transparentBackground, background" includes toggle label transparentBackground "Transparent background" that is too long for a compact toggle-plus-parameter row.',
|
|
4447
|
+
),
|
|
4448
|
+
]),
|
|
4449
|
+
);
|
|
4450
|
+
});
|
|
4451
|
+
|
|
4452
|
+
it("allows inline switch pairs when both labels are compact", () => {
|
|
4453
|
+
const schema = defineToolcraft({
|
|
4454
|
+
canvas: { enabled: true },
|
|
4455
|
+
panels: {
|
|
4456
|
+
controls: {
|
|
4457
|
+
sections: [
|
|
4458
|
+
{
|
|
4459
|
+
controls: {
|
|
4460
|
+
glow: {
|
|
4461
|
+
defaultValue: true,
|
|
4462
|
+
label: "Glow",
|
|
4463
|
+
target: "style.glow",
|
|
4464
|
+
type: "switch",
|
|
4465
|
+
},
|
|
4466
|
+
loop: {
|
|
4467
|
+
defaultValue: false,
|
|
4468
|
+
label: "Loop",
|
|
4469
|
+
target: "animation.loop",
|
|
4470
|
+
type: "switch",
|
|
4471
|
+
},
|
|
4472
|
+
},
|
|
4473
|
+
layoutGroups: [
|
|
4474
|
+
{
|
|
4475
|
+
columns: 2,
|
|
4476
|
+
controls: ["glow", "loop"],
|
|
4477
|
+
layout: "inline",
|
|
4478
|
+
},
|
|
4479
|
+
],
|
|
4480
|
+
title: "Style",
|
|
4481
|
+
},
|
|
4482
|
+
],
|
|
4483
|
+
title: "Controls",
|
|
4484
|
+
},
|
|
4485
|
+
},
|
|
4486
|
+
});
|
|
4487
|
+
|
|
4488
|
+
const errors = validateToolcraftAcceptanceCoverage(schema, [
|
|
4489
|
+
makeControlAcceptance("style.glow", "switch"),
|
|
4490
|
+
makeControlAcceptance("animation.loop", "switch"),
|
|
4491
|
+
]);
|
|
4064
4492
|
|
|
4065
4493
|
expect(errors).not.toEqual(
|
|
4066
4494
|
expect.arrayContaining([expect.stringContaining("two-column toggle row")]),
|
|
@@ -5252,7 +5680,6 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
5252
5680
|
step: 0.1,
|
|
5253
5681
|
target: "animation.speed",
|
|
5254
5682
|
type: "slider",
|
|
5255
|
-
unit: "x",
|
|
5256
5683
|
variant: "continuous",
|
|
5257
5684
|
},
|
|
5258
5685
|
depth: {
|
|
@@ -6145,7 +6572,7 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
6145
6572
|
]),
|
|
6146
6573
|
).toEqual(
|
|
6147
6574
|
expect.arrayContaining([
|
|
6148
|
-
'Controls for product entity "squares.right" are split across sections: Square 1 (Right), Appearance. Keep controls for the same product entity in one semantic section unless the
|
|
6575
|
+
'Controls for product entity "squares.right" are split across sections: Square 1 (Right), Appearance. Keep controls for the same product entity in one semantic section unless the Control Section Inventory declares workflowStage and splitReason for every split section.',
|
|
6149
6576
|
]),
|
|
6150
6577
|
);
|
|
6151
6578
|
});
|
|
@@ -6201,6 +6628,252 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
6201
6628
|
).toEqual([]);
|
|
6202
6629
|
});
|
|
6203
6630
|
|
|
6631
|
+
it("rejects stale control section inventory entries", () => {
|
|
6632
|
+
const schemaWithInventoryMismatch = defineToolcraft({
|
|
6633
|
+
canvas: { enabled: true },
|
|
6634
|
+
panels: {
|
|
6635
|
+
controls: {
|
|
6636
|
+
sections: [
|
|
6637
|
+
{
|
|
6638
|
+
controls: {
|
|
6639
|
+
kind: {
|
|
6640
|
+
defaultValue: "soft",
|
|
6641
|
+
label: "Kind",
|
|
6642
|
+
options: [
|
|
6643
|
+
{ label: "Soft", value: "soft" },
|
|
6644
|
+
{ label: "Sharp", value: "sharp" },
|
|
6645
|
+
],
|
|
6646
|
+
orderRole: "mode",
|
|
6647
|
+
target: "shape.kind",
|
|
6648
|
+
type: "select",
|
|
6649
|
+
},
|
|
6650
|
+
count: {
|
|
6651
|
+
defaultValue: 12,
|
|
6652
|
+
label: "Count",
|
|
6653
|
+
max: 40,
|
|
6654
|
+
min: 1,
|
|
6655
|
+
orderRole: "detail",
|
|
6656
|
+
target: "shape.count",
|
|
6657
|
+
type: "slider",
|
|
6658
|
+
variant: "continuous",
|
|
6659
|
+
},
|
|
6660
|
+
},
|
|
6661
|
+
title: "Shape",
|
|
6662
|
+
},
|
|
6663
|
+
],
|
|
6664
|
+
title: "Controls",
|
|
6665
|
+
},
|
|
6666
|
+
},
|
|
6667
|
+
});
|
|
6668
|
+
|
|
6669
|
+
expect(
|
|
6670
|
+
validateToolcraftAcceptanceCoverage(
|
|
6671
|
+
schemaWithInventoryMismatch,
|
|
6672
|
+
[
|
|
6673
|
+
makeControlAcceptance("shape.kind", "select"),
|
|
6674
|
+
makeControlAcceptance("shape.count", "slider"),
|
|
6675
|
+
],
|
|
6676
|
+
starterTransferMode,
|
|
6677
|
+
[
|
|
6678
|
+
{
|
|
6679
|
+
entity: "Shape",
|
|
6680
|
+
groupingReason: "Shape setup",
|
|
6681
|
+
targets: ["shape.kind"],
|
|
6682
|
+
title: "Shape",
|
|
6683
|
+
},
|
|
6684
|
+
],
|
|
6685
|
+
),
|
|
6686
|
+
).toEqual(
|
|
6687
|
+
expect.arrayContaining([
|
|
6688
|
+
'Control Section Inventory entry "Shape" must include a concrete groupingReason explaining why these controls belong together.',
|
|
6689
|
+
'Control Section Inventory entry "Shape" is missing rendered target "shape.count". The inventory must cover every product control in the section.',
|
|
6690
|
+
]),
|
|
6691
|
+
);
|
|
6692
|
+
});
|
|
6693
|
+
|
|
6694
|
+
it("allows explicit workflow split evidence for one target entity", () => {
|
|
6695
|
+
const schemaWithWorkflowSplit = defineToolcraft({
|
|
6696
|
+
canvas: { enabled: true },
|
|
6697
|
+
panels: {
|
|
6698
|
+
controls: {
|
|
6699
|
+
sections: [
|
|
6700
|
+
{
|
|
6701
|
+
controls: {
|
|
6702
|
+
size: {
|
|
6703
|
+
defaultValue: 64,
|
|
6704
|
+
label: "Size",
|
|
6705
|
+
max: 128,
|
|
6706
|
+
min: 16,
|
|
6707
|
+
orderRole: "primary",
|
|
6708
|
+
target: "object.shape.size",
|
|
6709
|
+
type: "slider",
|
|
6710
|
+
unit: "px",
|
|
6711
|
+
variant: "continuous",
|
|
6712
|
+
},
|
|
6713
|
+
},
|
|
6714
|
+
title: "Shape Structure",
|
|
6715
|
+
},
|
|
6716
|
+
{
|
|
6717
|
+
controls: {
|
|
6718
|
+
count: {
|
|
6719
|
+
defaultValue: 12,
|
|
6720
|
+
label: "Count",
|
|
6721
|
+
max: 40,
|
|
6722
|
+
min: 1,
|
|
6723
|
+
orderRole: "detail",
|
|
6724
|
+
target: "object.shape.count",
|
|
6725
|
+
type: "slider",
|
|
6726
|
+
variant: "continuous",
|
|
6727
|
+
},
|
|
6728
|
+
},
|
|
6729
|
+
title: "Shape Density",
|
|
6730
|
+
},
|
|
6731
|
+
],
|
|
6732
|
+
title: "Controls",
|
|
6733
|
+
},
|
|
6734
|
+
},
|
|
6735
|
+
});
|
|
6736
|
+
|
|
6737
|
+
expect(
|
|
6738
|
+
validateToolcraftAcceptanceCoverage(
|
|
6739
|
+
schemaWithWorkflowSplit,
|
|
6740
|
+
[
|
|
6741
|
+
makeControlAcceptance("object.shape.size", "slider"),
|
|
6742
|
+
makeControlAcceptance("object.shape.count", "slider"),
|
|
6743
|
+
],
|
|
6744
|
+
starterTransferMode,
|
|
6745
|
+
[
|
|
6746
|
+
{
|
|
6747
|
+
entity: "Object shape",
|
|
6748
|
+
groupingReason: "Structure controls tune the physical footprint of the object.",
|
|
6749
|
+
splitReason:
|
|
6750
|
+
"Structure and density are separate workflow stages in this editor.",
|
|
6751
|
+
targets: ["object.shape.size"],
|
|
6752
|
+
title: "Shape Structure",
|
|
6753
|
+
workflowStage: "structure",
|
|
6754
|
+
},
|
|
6755
|
+
{
|
|
6756
|
+
entity: "Object shape",
|
|
6757
|
+
groupingReason: "Density controls tune how many objects appear after structure is set.",
|
|
6758
|
+
splitReason:
|
|
6759
|
+
"Density is separated from structure because users set count after the shape footprint.",
|
|
6760
|
+
targets: ["object.shape.count"],
|
|
6761
|
+
title: "Shape Density",
|
|
6762
|
+
workflowStage: "density",
|
|
6763
|
+
},
|
|
6764
|
+
],
|
|
6765
|
+
),
|
|
6766
|
+
).toEqual([]);
|
|
6767
|
+
});
|
|
6768
|
+
|
|
6769
|
+
it("rejects mode-gated controls split away from their selector section", () => {
|
|
6770
|
+
const schemaWithSplitModeBranch = defineToolcraft({
|
|
6771
|
+
canvas: { enabled: true },
|
|
6772
|
+
panels: {
|
|
6773
|
+
controls: {
|
|
6774
|
+
sections: [
|
|
6775
|
+
{
|
|
6776
|
+
controls: {
|
|
6777
|
+
sourceMode: {
|
|
6778
|
+
defaultValue: "preset",
|
|
6779
|
+
label: "Source",
|
|
6780
|
+
options: [
|
|
6781
|
+
{ label: "Preset", value: "preset" },
|
|
6782
|
+
{ label: "Image", value: "image" },
|
|
6783
|
+
],
|
|
6784
|
+
orderRole: "mode",
|
|
6785
|
+
target: "source.mode",
|
|
6786
|
+
type: "segmented",
|
|
6787
|
+
},
|
|
6788
|
+
},
|
|
6789
|
+
title: "Source",
|
|
6790
|
+
},
|
|
6791
|
+
{
|
|
6792
|
+
controls: {
|
|
6793
|
+
sourceUpload: {
|
|
6794
|
+
accept: "image/*",
|
|
6795
|
+
assetKind: "image",
|
|
6796
|
+
defaultValue: null,
|
|
6797
|
+
label: "Image",
|
|
6798
|
+
orderRole: "input",
|
|
6799
|
+
target: "source.upload",
|
|
6800
|
+
type: "fileDrop",
|
|
6801
|
+
visibleWhen: { equals: "image", target: "source.mode" },
|
|
6802
|
+
},
|
|
6803
|
+
},
|
|
6804
|
+
title: "Image",
|
|
6805
|
+
},
|
|
6806
|
+
],
|
|
6807
|
+
title: "Controls",
|
|
6808
|
+
},
|
|
6809
|
+
},
|
|
6810
|
+
});
|
|
6811
|
+
|
|
6812
|
+
expect(
|
|
6813
|
+
validateToolcraftAcceptanceCoverage(schemaWithSplitModeBranch, [
|
|
6814
|
+
makeControlAcceptance("source.mode", "segmented"),
|
|
6815
|
+
makeControlAcceptance("source.upload", "fileDrop"),
|
|
6816
|
+
]),
|
|
6817
|
+
).toEqual(
|
|
6818
|
+
expect.arrayContaining([
|
|
6819
|
+
'Image / sourceUpload is gated by visibleWhen 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 visibleWhen/disabledWhen inside that section instead of splitting branch controls into their own section.',
|
|
6820
|
+
]),
|
|
6821
|
+
);
|
|
6822
|
+
});
|
|
6823
|
+
|
|
6824
|
+
it("rejects selector branch sections even when targets do not share a prefix", () => {
|
|
6825
|
+
const schemaWithSplitOptionBranch = defineToolcraft({
|
|
6826
|
+
canvas: { enabled: true },
|
|
6827
|
+
panels: {
|
|
6828
|
+
controls: {
|
|
6829
|
+
sections: [
|
|
6830
|
+
{
|
|
6831
|
+
controls: {
|
|
6832
|
+
shapeKind: {
|
|
6833
|
+
defaultValue: "generated",
|
|
6834
|
+
label: "Shape",
|
|
6835
|
+
options: [
|
|
6836
|
+
{ label: "Generated", value: "generated" },
|
|
6837
|
+
{ label: "Library", value: "library" },
|
|
6838
|
+
],
|
|
6839
|
+
orderRole: "mode",
|
|
6840
|
+
target: "shape.kind",
|
|
6841
|
+
type: "segmented",
|
|
6842
|
+
},
|
|
6843
|
+
},
|
|
6844
|
+
title: "Shape",
|
|
6845
|
+
},
|
|
6846
|
+
{
|
|
6847
|
+
controls: {
|
|
6848
|
+
libraryAsset: {
|
|
6849
|
+
defaultValue: null,
|
|
6850
|
+
label: "Library",
|
|
6851
|
+
orderRole: "input",
|
|
6852
|
+
target: "asset.upload",
|
|
6853
|
+
type: "fileDrop",
|
|
6854
|
+
visibleWhen: { equals: "library", target: "shape.kind" },
|
|
6855
|
+
},
|
|
6856
|
+
},
|
|
6857
|
+
title: "Library",
|
|
6858
|
+
},
|
|
6859
|
+
],
|
|
6860
|
+
title: "Controls",
|
|
6861
|
+
},
|
|
6862
|
+
},
|
|
6863
|
+
});
|
|
6864
|
+
|
|
6865
|
+
expect(
|
|
6866
|
+
validateToolcraftAcceptanceCoverage(schemaWithSplitOptionBranch, [
|
|
6867
|
+
makeControlAcceptance("shape.kind", "segmented"),
|
|
6868
|
+
makeControlAcceptance("asset.upload", "fileDrop"),
|
|
6869
|
+
]),
|
|
6870
|
+
).toEqual(
|
|
6871
|
+
expect.arrayContaining([
|
|
6872
|
+
'Library / libraryAsset is gated by visibleWhen 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 visibleWhen/disabledWhen inside that section instead of splitting branch controls into their own section.',
|
|
6873
|
+
]),
|
|
6874
|
+
);
|
|
6875
|
+
});
|
|
6876
|
+
|
|
6204
6877
|
it("rejects splitting FontPicker-owned typography into sibling controls", () => {
|
|
6205
6878
|
const schemaWithSplitTypographyBlock = defineToolcraft({
|
|
6206
6879
|
canvas: { enabled: true },
|
|
@@ -6580,15 +7253,15 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
6580
7253
|
type: "slider",
|
|
6581
7254
|
variant: "continuous",
|
|
6582
7255
|
},
|
|
6583
|
-
|
|
7256
|
+
mode: {
|
|
6584
7257
|
defaultValue: "liquid",
|
|
6585
|
-
label: "
|
|
7258
|
+
label: "Mode",
|
|
6586
7259
|
options: [
|
|
6587
7260
|
{ label: "Silk", value: "silk" },
|
|
6588
7261
|
{ label: "Liquid", value: "liquid" },
|
|
6589
7262
|
{ label: "Crystal", value: "crystal" },
|
|
6590
7263
|
],
|
|
6591
|
-
target: "shader.
|
|
7264
|
+
target: "shader.mode",
|
|
6592
7265
|
type: "segmented",
|
|
6593
7266
|
},
|
|
6594
7267
|
},
|
|
@@ -6618,23 +7291,23 @@ describe("Toolcraft template app acceptance coverage", () => {
|
|
|
6618
7291
|
},
|
|
6619
7292
|
{
|
|
6620
7293
|
automated: true,
|
|
6621
|
-
automatedTestName: "
|
|
7294
|
+
automatedTestName: "mode changes rendered output",
|
|
6622
7295
|
browser: true,
|
|
6623
|
-
browserTestName: "browser:
|
|
7296
|
+
browserTestName: "browser: mode selector changes rendered output",
|
|
6624
7297
|
componentType: "segmented",
|
|
6625
7298
|
evidence: "rendered-pixels",
|
|
6626
|
-
expectedObservable: "Changing
|
|
6627
|
-
fixture: "
|
|
6628
|
-
id: "shader.
|
|
7299
|
+
expectedObservable: "Changing Mode switches shader pattern.",
|
|
7300
|
+
fixture: "mode fixture",
|
|
7301
|
+
id: "shader.mode",
|
|
6629
7302
|
kind: "control",
|
|
6630
7303
|
optionCoverage: "each-visible-item",
|
|
6631
|
-
target: "shader.
|
|
6632
|
-
userAction: "Select each
|
|
7304
|
+
target: "shader.mode",
|
|
7305
|
+
userAction: "Select each Mode option.",
|
|
6633
7306
|
},
|
|
6634
7307
|
]),
|
|
6635
7308
|
).toEqual(
|
|
6636
7309
|
expect.arrayContaining([
|
|
6637
|
-
'Volume /
|
|
7310
|
+
'Volume / mode (shader.mode) has orderRole "mode" after depth (shader.depth) with orderRole "strength". Move mode/input/primary controls before dependent strength/detail/advanced controls or split them into an earlier section.',
|
|
6638
7311
|
]),
|
|
6639
7312
|
);
|
|
6640
7313
|
});
|