@cosmicdrift/kumiko-framework 0.258.0 → 0.259.0
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 +3 -3
- package/src/__tests__/anonymous-access.integration.test.ts +3 -3
- package/src/__tests__/derived-fields.integration.test.ts +1 -1
- package/src/__tests__/entity-list-limits.integration.test.ts +1 -1
- package/src/__tests__/error-contract.integration.test.ts +1 -1
- package/src/__tests__/ownership-where-write-path.integration.test.ts +1 -1
- package/src/__tests__/ownership.integration.test.ts +7 -3
- package/src/__tests__/schema-cli-rebuild.integration.test.ts +2 -2
- package/src/__tests__/transition-guard.integration.test.ts +3 -3
- package/src/api/__tests__/api.test.ts +21 -3
- package/src/api/__tests__/batch.integration.test.ts +3 -3
- package/src/api/__tests__/body-limit.test.ts +7 -1
- package/src/api/__tests__/dispatcher-live.integration.test.ts +1 -1
- package/src/api/__tests__/http-route-rate-limit.integration.test.ts +7 -1
- package/src/api/__tests__/metrics-endpoint.test.ts +7 -1
- package/src/api/__tests__/nested-write.integration.test.ts +3 -3
- package/src/api/__tests__/server-boot-guards.test.ts +11 -4
- package/src/bun-db/__tests__/write-brand.test.ts +4 -1
- package/src/changes.json +6 -0
- package/src/db/__tests__/apply-entity-event-tenant.integration.test.ts +1 -1
- package/src/db/__tests__/assert-exists-in.integration.test.ts +1 -1
- package/src/db/__tests__/assert-no-unreachable-live-rows.integration.test.ts +2 -2
- package/src/db/__tests__/collect-table-metas.test.ts +9 -5
- package/src/db/__tests__/compound-types.test.ts +1 -1
- package/src/db/__tests__/config-seed.integration.test.ts +3 -3
- package/src/db/__tests__/eagerload.integration.test.ts +7 -7
- package/src/db/__tests__/entity-table-from-registry.test.ts +8 -2
- package/src/db/__tests__/entity-table-meta-source.test.ts +7 -3
- package/src/db/__tests__/entity-table-types.test.ts +4 -4
- package/src/db/__tests__/event-store-executor-list.integration.test.ts +9 -2
- package/src/db/__tests__/event-store-executor-reference-search.integration.test.ts +4 -4
- package/src/db/__tests__/event-store-executor-reference-sort.integration.test.ts +3 -3
- package/src/db/__tests__/event-store-executor-write-verbs.integration.test.ts +4 -4
- package/src/db/__tests__/event-store-executor.integration.test.ts +11 -6
- package/src/db/__tests__/event-store-system-stream.integration.test.ts +2 -2
- package/src/db/__tests__/implicit-projection-equivalence.integration.test.ts +6 -4
- package/src/db/__tests__/located-timestamp.test.ts +1 -1
- package/src/db/__tests__/money.test.ts +1 -1
- package/src/db/__tests__/multi-row-insert.integration.test.ts +3 -3
- package/src/db/__tests__/schema-migration.integration.test.ts +30 -14
- package/src/db/__tests__/source-shadow-create.integration.test.ts +1 -1
- package/src/db/__tests__/table-builder-indexes.test.ts +14 -12
- package/src/db/__tests__/table-builder-required.test.ts +2 -2
- package/src/db/__tests__/tenant-db-where-merge.integration.test.ts +1 -1
- package/src/db/__tests__/tenant-db-where-merge.test.ts +5 -2
- package/src/db/__tests__/tenant-db.integration.test.ts +2 -2
- package/src/db/__tests__/unique-violation-mapping.integration.test.ts +2 -2
- package/src/engine/__tests__/boot-validator-action-wiring.test.ts +50 -8
- package/src/engine/__tests__/boot-validator-dashboard.test.ts +138 -1
- package/src/engine/__tests__/boot-validator-detail-for.test.ts +28 -4
- package/src/engine/__tests__/boot-validator-entity-list.test.ts +20 -4
- package/src/engine/__tests__/boot-validator-i18n-keys.test.ts +9 -3
- package/src/engine/__tests__/boot-validator.test.ts +488 -91
- package/src/engine/__tests__/define-feature-entity-mapping.test.ts +2 -2
- package/src/engine/__tests__/engine.test.ts +128 -37
- package/src/engine/__tests__/entity-handlers.test.ts +3 -3
- package/src/engine/__tests__/entity-presave-wiring.integration.test.ts +4 -4
- package/src/engine/__tests__/entity-restore-tenant-isolation.integration.test.ts +1 -1
- package/src/engine/__tests__/entity-write-crosstenant.integration.test.ts +1 -1
- package/src/engine/__tests__/extend-entity-projection.test.ts +1 -1
- package/src/engine/__tests__/extends-registrar.test.ts +13 -3
- package/src/engine/__tests__/factories-long-text.test.ts +10 -6
- package/src/engine/__tests__/feature-crud-shorthand.test.ts +1 -1
- package/src/engine/__tests__/feature-crud-verb-access.integration.test.ts +1 -1
- package/src/engine/__tests__/multiselect-filter.integration.test.ts +1 -1
- package/src/engine/__tests__/nav.test.ts +1 -1
- package/src/engine/__tests__/pipeline-handler.integration.test.ts +1 -1
- package/src/engine/__tests__/pipeline-observability.integration.test.ts +1 -1
- package/src/engine/__tests__/pipeline-performance.integration.test.ts +1 -1
- package/src/engine/__tests__/projection-detail-actions.test.ts +6 -1
- package/src/engine/__tests__/projection-detail-singleton.test.ts +6 -1
- package/src/engine/__tests__/projection-detail-tabs.test.ts +6 -1
- package/src/engine/__tests__/projection-list-filter.integration.test.ts +7 -2
- package/src/engine/__tests__/projection.test.ts +1 -1
- package/src/engine/__tests__/registry.test.ts +13 -3
- package/src/engine/__tests__/schema-builder.test.ts +39 -11
- package/src/engine/__tests__/screen.test.ts +21 -15
- package/src/engine/__tests__/search-payload-extension.test.ts +15 -3
- package/src/engine/__tests__/store-table.test.ts +6 -3
- package/src/engine/__tests__/validate-projection-allowlist.test.ts +12 -4
- package/src/engine/__tests__/validation-hooks.test.ts +7 -1
- package/src/engine/boot-validator/__tests__/ownership.test.ts +2 -2
- package/src/engine/boot-validator/query-refs.ts +11 -0
- package/src/engine/boot-validator/screens.ts +45 -2
- package/src/engine/build-config-feature-schema.ts +2 -2
- package/src/engine/index.ts +2 -0
- package/src/engine/types/index.ts +2 -0
- package/src/es-ops/__tests__/runner.integration.test.ts +1 -1
- package/src/event-store/__tests__/upcaster.integration.test.ts +1 -1
- package/src/files/__tests__/file-field-pipeline.integration.test.ts +1 -1
- package/src/files/__tests__/files.integration.test.ts +1 -1
- package/src/files/file-ref-entity.ts +9 -9
- package/src/i18n/__tests__/i18n.test.ts +7 -1
- package/src/migrations/__tests__/kumiko-drift.integration.test.ts +3 -1
- package/src/migrations/__tests__/pending-rebuilds.integration.test.ts +2 -2
- package/src/pipeline/__tests__/archive-stream.integration.test.ts +1 -1
- package/src/pipeline/__tests__/cascade-handler.integration.test.ts +23 -8
- package/src/pipeline/__tests__/cascade-handler.test.ts +18 -3
- package/src/pipeline/__tests__/causation-chain.integration.test.ts +1 -1
- package/src/pipeline/__tests__/ctx-bridge.integration.test.ts +5 -3
- package/src/pipeline/__tests__/dispatcher.test.ts +42 -6
- package/src/pipeline/__tests__/domain-events-projections.integration.test.ts +2 -2
- package/src/pipeline/__tests__/fetch-for-writing.integration.test.ts +1 -1
- package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +42 -6
- package/src/pipeline/__tests__/load-aggregate-query.integration.test.ts +2 -2
- package/src/pipeline/__tests__/msp-multi-hop.integration.test.ts +1 -1
- package/src/pipeline/__tests__/msp-rebuild.integration.test.ts +6 -2
- package/src/pipeline/__tests__/multi-stream-projection.integration.test.ts +6 -2
- package/src/pipeline/__tests__/perf-rebuild.integration.test.ts +1 -1
- package/src/pipeline/__tests__/post-query-hook.integration.test.ts +3 -3
- package/src/pipeline/__tests__/projection-rebuild.integration.test.ts +3 -3
- package/src/pipeline/__tests__/query-projection.integration.test.ts +1 -1
- package/src/pipeline/__tests__/rebuild-poison-quarantine.integration.test.ts +2 -2
- package/src/pipeline/__tests__/search-consumer-named-events.integration.test.ts +13 -2
- package/src/pipeline/__tests__/try-append-event.integration.test.ts +1 -1
- package/src/search/__tests__/reindex-entity.integration.test.ts +6 -1
- package/src/search/__tests__/search-pii-derived-index.integration.test.ts +7 -1
- package/src/stack/__tests__/ownership-boot-guard.integration.test.ts +1 -1
- package/src/testing/__tests__/e2e-generator.test.ts +15 -5
- package/src/testing/shared-entities.ts +4 -2
- package/src/ui-types/index.ts +2 -0
|
@@ -50,7 +50,13 @@ describe("boot-validator", () => {
|
|
|
50
50
|
test("passes for valid features with no issues", () => {
|
|
51
51
|
const features = [
|
|
52
52
|
defineFeature("a", (r) => {
|
|
53
|
-
r.entity(
|
|
53
|
+
r.entity(
|
|
54
|
+
"user",
|
|
55
|
+
createEntity({
|
|
56
|
+
table: "Users",
|
|
57
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
54
60
|
}),
|
|
55
61
|
];
|
|
56
62
|
expect(() => validateBoot(features)).not.toThrow();
|
|
@@ -404,7 +410,7 @@ describe("boot-validator", () => {
|
|
|
404
410
|
"item",
|
|
405
411
|
createEntity({
|
|
406
412
|
table: "Items",
|
|
407
|
-
fields: { name: createTextField() },
|
|
413
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
408
414
|
}),
|
|
409
415
|
);
|
|
410
416
|
r.extendsRegistrar("custom", {
|
|
@@ -426,7 +432,7 @@ describe("boot-validator", () => {
|
|
|
426
432
|
"item",
|
|
427
433
|
createEntity({
|
|
428
434
|
table: "Items",
|
|
429
|
-
fields: { status: createTextField() },
|
|
435
|
+
fields: { status: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
430
436
|
derivedFields: {
|
|
431
437
|
status: createDerivedField({ valueType: "text", derive: () => "computed" }),
|
|
432
438
|
},
|
|
@@ -446,7 +452,7 @@ describe("boot-validator", () => {
|
|
|
446
452
|
"item",
|
|
447
453
|
createEntity({
|
|
448
454
|
table: "Items",
|
|
449
|
-
fields: { status: createTextField() },
|
|
455
|
+
fields: { status: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
450
456
|
derivedFields: {
|
|
451
457
|
statusLabel: createDerivedField({ valueType: "text", derive: () => "computed" }),
|
|
452
458
|
},
|
|
@@ -498,7 +504,7 @@ describe("boot-validator", () => {
|
|
|
498
504
|
"item",
|
|
499
505
|
createEntity({
|
|
500
506
|
table: "Items",
|
|
501
|
-
fields: { name: createTextField() },
|
|
507
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
502
508
|
}),
|
|
503
509
|
);
|
|
504
510
|
r.extendsRegistrar("custom", {
|
|
@@ -514,7 +520,13 @@ describe("boot-validator", () => {
|
|
|
514
520
|
test("accepts bare CRUD write handler when feature name matches entity", () => {
|
|
515
521
|
const features = [
|
|
516
522
|
defineFeature("credit", (r) => {
|
|
517
|
-
r.entity(
|
|
523
|
+
r.entity(
|
|
524
|
+
"credit",
|
|
525
|
+
createEntity({
|
|
526
|
+
table: "Credits",
|
|
527
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
528
|
+
}),
|
|
529
|
+
);
|
|
518
530
|
r.writeHandler(
|
|
519
531
|
"create",
|
|
520
532
|
z.object({ name: z.string() }),
|
|
@@ -540,7 +552,13 @@ describe("boot-validator", () => {
|
|
|
540
552
|
});
|
|
541
553
|
const consumer = defineFeature("money-horse", (r) => {
|
|
542
554
|
r.requires("cap-ext");
|
|
543
|
-
r.entity(
|
|
555
|
+
r.entity(
|
|
556
|
+
"credit",
|
|
557
|
+
createEntity({
|
|
558
|
+
table: "Credits",
|
|
559
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
560
|
+
}),
|
|
561
|
+
);
|
|
544
562
|
r.writeHandler(
|
|
545
563
|
"doSomething",
|
|
546
564
|
z.object({}),
|
|
@@ -583,7 +601,9 @@ describe("boot-validator", () => {
|
|
|
583
601
|
test("registerEntityCrud without access options fails boot (no implicit openToAll)", () => {
|
|
584
602
|
const widgetEntity = createEntity({
|
|
585
603
|
table: "phase0_widgets",
|
|
586
|
-
fields: {
|
|
604
|
+
fields: {
|
|
605
|
+
name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
|
|
606
|
+
},
|
|
587
607
|
});
|
|
588
608
|
const features = [
|
|
589
609
|
defineFeature("phase0", (r) => {
|
|
@@ -948,7 +968,13 @@ describe("boot-validator", () => {
|
|
|
948
968
|
"order",
|
|
949
969
|
createEntity({
|
|
950
970
|
table: "orders",
|
|
951
|
-
fields: {
|
|
971
|
+
fields: {
|
|
972
|
+
teamId: createTextField({
|
|
973
|
+
required: true,
|
|
974
|
+
personal: false,
|
|
975
|
+
reason: "test_fixture",
|
|
976
|
+
}),
|
|
977
|
+
},
|
|
952
978
|
access: {
|
|
953
979
|
read: { Admin: "all", TeamMember: from("claim:teams:teamId") },
|
|
954
980
|
},
|
|
@@ -966,7 +992,13 @@ describe("boot-validator", () => {
|
|
|
966
992
|
"order",
|
|
967
993
|
createEntity({
|
|
968
994
|
table: "orders",
|
|
969
|
-
fields: {
|
|
995
|
+
fields: {
|
|
996
|
+
teamId: createTextField({
|
|
997
|
+
required: true,
|
|
998
|
+
personal: false,
|
|
999
|
+
reason: "test_fixture",
|
|
1000
|
+
}),
|
|
1001
|
+
},
|
|
970
1002
|
access: {
|
|
971
1003
|
// No "teams" feature registered — claim doesn't exist.
|
|
972
1004
|
read: { TeamMember: from("claim:teams:teamId") },
|
|
@@ -990,7 +1022,13 @@ describe("boot-validator", () => {
|
|
|
990
1022
|
"order",
|
|
991
1023
|
createEntity({
|
|
992
1024
|
table: "orders",
|
|
993
|
-
fields: {
|
|
1025
|
+
fields: {
|
|
1026
|
+
teamId: createTextField({
|
|
1027
|
+
required: true,
|
|
1028
|
+
personal: false,
|
|
1029
|
+
reason: "test_fixture",
|
|
1030
|
+
}),
|
|
1031
|
+
},
|
|
994
1032
|
access: {
|
|
995
1033
|
read: {
|
|
996
1034
|
// column "nonExistentColumn" not on entity
|
|
@@ -1017,12 +1055,18 @@ describe("boot-validator", () => {
|
|
|
1017
1055
|
createEntity({
|
|
1018
1056
|
table: "contracts",
|
|
1019
1057
|
fields: {
|
|
1020
|
-
teamId: createTextField({
|
|
1058
|
+
teamId: createTextField({
|
|
1059
|
+
required: true,
|
|
1060
|
+
personal: false,
|
|
1061
|
+
reason: "test_fixture",
|
|
1062
|
+
}),
|
|
1021
1063
|
propC: createTextField({
|
|
1022
1064
|
access: {
|
|
1023
1065
|
read: { Admin: "all", TeamMember: from("claim:teams:teamId") },
|
|
1024
1066
|
write: { Admin: "all", TeamMember: from("claim:teams:teamId") },
|
|
1025
1067
|
},
|
|
1068
|
+
personal: false,
|
|
1069
|
+
reason: "test_fixture",
|
|
1026
1070
|
}),
|
|
1027
1071
|
},
|
|
1028
1072
|
}),
|
|
@@ -1040,12 +1084,18 @@ describe("boot-validator", () => {
|
|
|
1040
1084
|
createEntity({
|
|
1041
1085
|
table: "contracts",
|
|
1042
1086
|
fields: {
|
|
1043
|
-
teamId: createTextField({
|
|
1087
|
+
teamId: createTextField({
|
|
1088
|
+
required: true,
|
|
1089
|
+
personal: false,
|
|
1090
|
+
reason: "test_fixture",
|
|
1091
|
+
}),
|
|
1044
1092
|
propC: createTextField({
|
|
1045
1093
|
access: {
|
|
1046
1094
|
// claim not declared anywhere
|
|
1047
1095
|
read: { TeamMember: from("claim:nowhere:teamId") },
|
|
1048
1096
|
},
|
|
1097
|
+
personal: false,
|
|
1098
|
+
reason: "test_fixture",
|
|
1049
1099
|
}),
|
|
1050
1100
|
},
|
|
1051
1101
|
}),
|
|
@@ -1064,7 +1114,7 @@ describe("boot-validator", () => {
|
|
|
1064
1114
|
"order",
|
|
1065
1115
|
createEntity({
|
|
1066
1116
|
table: "orders",
|
|
1067
|
-
fields: { assigneeId: createTextField() },
|
|
1117
|
+
fields: { assigneeId: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
1068
1118
|
access: {
|
|
1069
1119
|
read: { Driver: from("user:id", "assigneeId") },
|
|
1070
1120
|
},
|
|
@@ -1082,7 +1132,7 @@ describe("boot-validator", () => {
|
|
|
1082
1132
|
"order",
|
|
1083
1133
|
createEntity({
|
|
1084
1134
|
table: "orders",
|
|
1085
|
-
fields: { assigneeId: createTextField() },
|
|
1135
|
+
fields: { assigneeId: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
1086
1136
|
access: {
|
|
1087
1137
|
read: {
|
|
1088
1138
|
Admin: "all",
|
|
@@ -1106,7 +1156,13 @@ describe("boot-validator", () => {
|
|
|
1106
1156
|
"order",
|
|
1107
1157
|
createEntity({
|
|
1108
1158
|
table: "orders",
|
|
1109
|
-
fields: {
|
|
1159
|
+
fields: {
|
|
1160
|
+
entityId: createTextField({
|
|
1161
|
+
required: true,
|
|
1162
|
+
personal: false,
|
|
1163
|
+
reason: "test_fixture",
|
|
1164
|
+
}),
|
|
1165
|
+
},
|
|
1110
1166
|
access: {
|
|
1111
1167
|
read: {
|
|
1112
1168
|
Auditor: {
|
|
@@ -1132,7 +1188,13 @@ describe("boot-validator", () => {
|
|
|
1132
1188
|
"order",
|
|
1133
1189
|
createEntity({
|
|
1134
1190
|
table: "orders",
|
|
1135
|
-
fields: {
|
|
1191
|
+
fields: {
|
|
1192
|
+
entityId: createTextField({
|
|
1193
|
+
required: true,
|
|
1194
|
+
personal: false,
|
|
1195
|
+
reason: "test_fixture",
|
|
1196
|
+
}),
|
|
1197
|
+
},
|
|
1136
1198
|
access: {
|
|
1137
1199
|
read: {
|
|
1138
1200
|
Auditor: {
|
|
@@ -1196,7 +1258,13 @@ describe("boot-validator", () => {
|
|
|
1196
1258
|
"order",
|
|
1197
1259
|
createEntity({
|
|
1198
1260
|
table: "orders",
|
|
1199
|
-
fields: {
|
|
1261
|
+
fields: {
|
|
1262
|
+
teamId: createTextField({
|
|
1263
|
+
required: true,
|
|
1264
|
+
personal: false,
|
|
1265
|
+
reason: "test_fixture",
|
|
1266
|
+
}),
|
|
1267
|
+
},
|
|
1200
1268
|
access: {
|
|
1201
1269
|
read: { Admi: "all" },
|
|
1202
1270
|
},
|
|
@@ -1225,7 +1293,11 @@ describe("boot-validator", () => {
|
|
|
1225
1293
|
createEntity({
|
|
1226
1294
|
table: "orders",
|
|
1227
1295
|
fields: {
|
|
1228
|
-
secret: createTextField({
|
|
1296
|
+
secret: createTextField({
|
|
1297
|
+
access: { read: ["Admni"] },
|
|
1298
|
+
personal: false,
|
|
1299
|
+
reason: "test_fixture",
|
|
1300
|
+
}),
|
|
1229
1301
|
},
|
|
1230
1302
|
}),
|
|
1231
1303
|
);
|
|
@@ -1251,7 +1323,13 @@ describe("boot-validator", () => {
|
|
|
1251
1323
|
"order",
|
|
1252
1324
|
createEntity({
|
|
1253
1325
|
table: "orders",
|
|
1254
|
-
fields: {
|
|
1326
|
+
fields: {
|
|
1327
|
+
teamId: createTextField({
|
|
1328
|
+
required: true,
|
|
1329
|
+
personal: false,
|
|
1330
|
+
reason: "test_fixture",
|
|
1331
|
+
}),
|
|
1332
|
+
},
|
|
1255
1333
|
access: {
|
|
1256
1334
|
read: { Admin: "all", TeamMember: "all" },
|
|
1257
1335
|
},
|
|
@@ -1273,7 +1351,13 @@ describe("boot-validator", () => {
|
|
|
1273
1351
|
"order",
|
|
1274
1352
|
createEntity({
|
|
1275
1353
|
table: "orders",
|
|
1276
|
-
fields: {
|
|
1354
|
+
fields: {
|
|
1355
|
+
teamId: createTextField({
|
|
1356
|
+
required: true,
|
|
1357
|
+
personal: false,
|
|
1358
|
+
reason: "test_fixture",
|
|
1359
|
+
}),
|
|
1360
|
+
},
|
|
1277
1361
|
access: {
|
|
1278
1362
|
read: { AnyRole: "all" },
|
|
1279
1363
|
},
|
|
@@ -1807,7 +1891,12 @@ describe("boot-validator", () => {
|
|
|
1807
1891
|
describe("entityList column renderer form", () => {
|
|
1808
1892
|
function shopFeature(renderer: unknown) {
|
|
1809
1893
|
return defineFeature("shop", (r) => {
|
|
1810
|
-
r.entity(
|
|
1894
|
+
r.entity(
|
|
1895
|
+
"product",
|
|
1896
|
+
createEntity({
|
|
1897
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
1898
|
+
}),
|
|
1899
|
+
);
|
|
1811
1900
|
r.screen({
|
|
1812
1901
|
id: "product-list",
|
|
1813
1902
|
type: "entityList",
|
|
@@ -1970,7 +2059,12 @@ describe("boot-validator", () => {
|
|
|
1970
2059
|
describe("entityList virtual labeled column", () => {
|
|
1971
2060
|
function noteFeature(column: unknown) {
|
|
1972
2061
|
return defineFeature("notes", (r) => {
|
|
1973
|
-
r.entity(
|
|
2062
|
+
r.entity(
|
|
2063
|
+
"note",
|
|
2064
|
+
createEntity({
|
|
2065
|
+
fields: { title: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
2066
|
+
}),
|
|
2067
|
+
);
|
|
1974
2068
|
r.screen({
|
|
1975
2069
|
id: "note-list",
|
|
1976
2070
|
type: "entityList",
|
|
@@ -2030,7 +2124,10 @@ describe("boot-validator", () => {
|
|
|
2030
2124
|
return defineFeature("notes", (r) => {
|
|
2031
2125
|
r.entity(
|
|
2032
2126
|
"note",
|
|
2033
|
-
createEntity({
|
|
2127
|
+
createEntity({
|
|
2128
|
+
fields: { title: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
2129
|
+
softDelete: options?.softDelete,
|
|
2130
|
+
}),
|
|
2034
2131
|
);
|
|
2035
2132
|
r.screen({
|
|
2036
2133
|
id: "note-list",
|
|
@@ -2089,7 +2186,12 @@ describe("boot-validator", () => {
|
|
|
2089
2186
|
for (const typo of typoColumns) {
|
|
2090
2187
|
test(`"${typo}" fails validateScreens (via validateBoot)`, () => {
|
|
2091
2188
|
const feature = defineFeature("notes", (r) => {
|
|
2092
|
-
r.entity(
|
|
2189
|
+
r.entity(
|
|
2190
|
+
"note",
|
|
2191
|
+
createEntity({
|
|
2192
|
+
fields: { title: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
2193
|
+
}),
|
|
2194
|
+
);
|
|
2093
2195
|
r.screen({
|
|
2094
2196
|
id: "note-list",
|
|
2095
2197
|
type: "entityList",
|
|
@@ -2104,7 +2206,12 @@ describe("boot-validator", () => {
|
|
|
2104
2206
|
|
|
2105
2207
|
test(`"${typo}" fails validateEntityListScreens directly ("unknown column field")`, () => {
|
|
2106
2208
|
const feature = defineFeature("notes", (r) => {
|
|
2107
|
-
r.entity(
|
|
2209
|
+
r.entity(
|
|
2210
|
+
"note",
|
|
2211
|
+
createEntity({
|
|
2212
|
+
fields: { title: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
2213
|
+
}),
|
|
2214
|
+
);
|
|
2108
2215
|
r.screen({
|
|
2109
2216
|
id: "note-list",
|
|
2110
2217
|
type: "entityList",
|
|
@@ -2137,11 +2244,11 @@ describe("boot-validator", () => {
|
|
|
2137
2244
|
"product",
|
|
2138
2245
|
createEntity({
|
|
2139
2246
|
fields: {
|
|
2140
|
-
name: createTextField({ sortable: true }),
|
|
2247
|
+
name: createTextField({ sortable: true, personal: false, reason: "test_fixture" }),
|
|
2141
2248
|
// Bewusst NICHT sortable: bestätigt dass Validator das
|
|
2142
2249
|
// unterscheidet und nur sortable-Felder als defaultSort
|
|
2143
2250
|
// akzeptiert.
|
|
2144
|
-
description: createTextField(),
|
|
2251
|
+
description: createTextField({ personal: false, reason: "test_fixture" }),
|
|
2145
2252
|
},
|
|
2146
2253
|
}),
|
|
2147
2254
|
);
|
|
@@ -2956,7 +3063,12 @@ describe("boot-validator", () => {
|
|
|
2956
3063
|
describe("entityEdit extension section", () => {
|
|
2957
3064
|
function makeFeature(component: unknown) {
|
|
2958
3065
|
return defineFeature("shop", (r) => {
|
|
2959
|
-
r.entity(
|
|
3066
|
+
r.entity(
|
|
3067
|
+
"product",
|
|
3068
|
+
createEntity({
|
|
3069
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3070
|
+
}),
|
|
3071
|
+
);
|
|
2960
3072
|
r.screen({
|
|
2961
3073
|
id: "product-edit",
|
|
2962
3074
|
type: "entityEdit",
|
|
@@ -2997,7 +3109,12 @@ describe("boot-validator", () => {
|
|
|
2997
3109
|
return defineFeature("shop", (r) => {
|
|
2998
3110
|
r.entity(
|
|
2999
3111
|
"product",
|
|
3000
|
-
createEntity({
|
|
3112
|
+
createEntity({
|
|
3113
|
+
fields: {
|
|
3114
|
+
name: createTextField({ personal: false, reason: "test_fixture" }),
|
|
3115
|
+
sku: createTextField({ personal: false, reason: "test_fixture" }),
|
|
3116
|
+
},
|
|
3117
|
+
}),
|
|
3001
3118
|
);
|
|
3002
3119
|
r.screen({
|
|
3003
3120
|
id: "product-edit",
|
|
@@ -3054,7 +3171,12 @@ describe("boot-validator", () => {
|
|
|
3054
3171
|
return defineFeature("shop", (r) => {
|
|
3055
3172
|
r.entity(
|
|
3056
3173
|
"product",
|
|
3057
|
-
createEntity({
|
|
3174
|
+
createEntity({
|
|
3175
|
+
fields: {
|
|
3176
|
+
name: createTextField({ personal: false, reason: "test_fixture" }),
|
|
3177
|
+
sku: createTextField({ personal: false, reason: "test_fixture" }),
|
|
3178
|
+
},
|
|
3179
|
+
}),
|
|
3058
3180
|
);
|
|
3059
3181
|
r.screen({
|
|
3060
3182
|
id: "product-edit",
|
|
@@ -3188,7 +3310,7 @@ describe("boot-validator", () => {
|
|
|
3188
3310
|
"order",
|
|
3189
3311
|
createEntity({
|
|
3190
3312
|
fields: {
|
|
3191
|
-
kind: createTextField(),
|
|
3313
|
+
kind: createTextField({ personal: false, reason: "test_fixture" }),
|
|
3192
3314
|
lines: createEmbeddedField({ note: { type: "text" } }, { required: true }),
|
|
3193
3315
|
},
|
|
3194
3316
|
}),
|
|
@@ -3292,7 +3414,12 @@ describe("boot-validator", () => {
|
|
|
3292
3414
|
test("reference auf bestehende Entity → kein Throw", () => {
|
|
3293
3415
|
const features = [
|
|
3294
3416
|
defineFeature("shop", (r) => {
|
|
3295
|
-
r.entity(
|
|
3417
|
+
r.entity(
|
|
3418
|
+
"customer",
|
|
3419
|
+
createEntity({
|
|
3420
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3421
|
+
}),
|
|
3422
|
+
);
|
|
3296
3423
|
stubListHandler(r, "customer");
|
|
3297
3424
|
r.entity(
|
|
3298
3425
|
"order",
|
|
@@ -3328,7 +3455,12 @@ describe("boot-validator", () => {
|
|
|
3328
3455
|
test("reference labelField auf unknown Field → Throw", () => {
|
|
3329
3456
|
const features = [
|
|
3330
3457
|
defineFeature("shop", (r) => {
|
|
3331
|
-
r.entity(
|
|
3458
|
+
r.entity(
|
|
3459
|
+
"customer",
|
|
3460
|
+
createEntity({
|
|
3461
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3462
|
+
}),
|
|
3463
|
+
);
|
|
3332
3464
|
r.entity(
|
|
3333
3465
|
"order",
|
|
3334
3466
|
createEntity({
|
|
@@ -3347,7 +3479,12 @@ describe("boot-validator", () => {
|
|
|
3347
3479
|
test("reference labelField=id ist immer ok (PK)", () => {
|
|
3348
3480
|
const features = [
|
|
3349
3481
|
defineFeature("shop", (r) => {
|
|
3350
|
-
r.entity(
|
|
3482
|
+
r.entity(
|
|
3483
|
+
"customer",
|
|
3484
|
+
createEntity({
|
|
3485
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3486
|
+
}),
|
|
3487
|
+
);
|
|
3351
3488
|
stubListHandler(r, "customer");
|
|
3352
3489
|
r.entity(
|
|
3353
3490
|
"order",
|
|
@@ -3369,7 +3506,7 @@ describe("boot-validator", () => {
|
|
|
3369
3506
|
"category",
|
|
3370
3507
|
createEntity({
|
|
3371
3508
|
fields: {
|
|
3372
|
-
name: createTextField(),
|
|
3509
|
+
name: createTextField({ personal: false, reason: "test_fixture" }),
|
|
3373
3510
|
parentId: { type: "reference", entity: "category", labelField: "name" },
|
|
3374
3511
|
},
|
|
3375
3512
|
}),
|
|
@@ -3383,13 +3520,18 @@ describe("boot-validator", () => {
|
|
|
3383
3520
|
test("reference mit multiple: true → kein Throw (Tier 2.7e-Multi)", () => {
|
|
3384
3521
|
const features = [
|
|
3385
3522
|
defineFeature("shop", (r) => {
|
|
3386
|
-
r.entity(
|
|
3523
|
+
r.entity(
|
|
3524
|
+
"tag",
|
|
3525
|
+
createEntity({
|
|
3526
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3527
|
+
}),
|
|
3528
|
+
);
|
|
3387
3529
|
stubListHandler(r, "tag");
|
|
3388
3530
|
r.entity(
|
|
3389
3531
|
"post",
|
|
3390
3532
|
createEntity({
|
|
3391
3533
|
fields: {
|
|
3392
|
-
title: createTextField(),
|
|
3534
|
+
title: createTextField({ personal: false, reason: "test_fixture" }),
|
|
3393
3535
|
tagIds: {
|
|
3394
3536
|
type: "reference",
|
|
3395
3537
|
entity: "tag",
|
|
@@ -3408,7 +3550,12 @@ describe("boot-validator", () => {
|
|
|
3408
3550
|
test("cross-feature reference (feature:entity) → kein Throw", () => {
|
|
3409
3551
|
const features = [
|
|
3410
3552
|
defineFeature("users", (r) => {
|
|
3411
|
-
r.entity(
|
|
3553
|
+
r.entity(
|
|
3554
|
+
"user",
|
|
3555
|
+
createEntity({
|
|
3556
|
+
fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3557
|
+
}),
|
|
3558
|
+
);
|
|
3412
3559
|
stubListHandler(r, "user");
|
|
3413
3560
|
}),
|
|
3414
3561
|
defineFeature("shop", (r) => {
|
|
@@ -3428,7 +3575,12 @@ describe("boot-validator", () => {
|
|
|
3428
3575
|
test("Audit-Fix #2: cross-feature reference ohne list-handler → Throw", () => {
|
|
3429
3576
|
const features = [
|
|
3430
3577
|
defineFeature("users", (r) => {
|
|
3431
|
-
r.entity(
|
|
3578
|
+
r.entity(
|
|
3579
|
+
"user",
|
|
3580
|
+
createEntity({
|
|
3581
|
+
fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3582
|
+
}),
|
|
3583
|
+
);
|
|
3432
3584
|
// KEINE stubListHandler — das ist der Punkt des Tests
|
|
3433
3585
|
}),
|
|
3434
3586
|
defineFeature("shop", (r) => {
|
|
@@ -3468,7 +3620,12 @@ describe("boot-validator", () => {
|
|
|
3468
3620
|
test("cross-feature reference auf unknown entity → Throw mit feature-context", () => {
|
|
3469
3621
|
const features = [
|
|
3470
3622
|
defineFeature("users", (r) => {
|
|
3471
|
-
r.entity(
|
|
3623
|
+
r.entity(
|
|
3624
|
+
"user",
|
|
3625
|
+
createEntity({
|
|
3626
|
+
fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3627
|
+
}),
|
|
3628
|
+
);
|
|
3472
3629
|
}),
|
|
3473
3630
|
defineFeature("shop", (r) => {
|
|
3474
3631
|
r.entity(
|
|
@@ -3489,7 +3646,12 @@ describe("boot-validator", () => {
|
|
|
3489
3646
|
test("cross-feature labelField auf unknown Field → Throw", () => {
|
|
3490
3647
|
const features = [
|
|
3491
3648
|
defineFeature("users", (r) => {
|
|
3492
|
-
r.entity(
|
|
3649
|
+
r.entity(
|
|
3650
|
+
"user",
|
|
3651
|
+
createEntity({
|
|
3652
|
+
fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3653
|
+
}),
|
|
3654
|
+
);
|
|
3493
3655
|
}),
|
|
3494
3656
|
defineFeature("shop", (r) => {
|
|
3495
3657
|
r.entity(
|
|
@@ -3540,7 +3702,12 @@ describe("boot-validator", () => {
|
|
|
3540
3702
|
test("reference sub-field with a valid target + registered list-handler → kein Throw", () => {
|
|
3541
3703
|
const features = [
|
|
3542
3704
|
defineFeature("shop", (r) => {
|
|
3543
|
-
r.entity(
|
|
3705
|
+
r.entity(
|
|
3706
|
+
"product",
|
|
3707
|
+
createEntity({
|
|
3708
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3709
|
+
}),
|
|
3710
|
+
);
|
|
3544
3711
|
stubListHandler(r, "product");
|
|
3545
3712
|
r.entity(
|
|
3546
3713
|
"invoice",
|
|
@@ -3560,7 +3727,12 @@ describe("boot-validator", () => {
|
|
|
3560
3727
|
test("reference sub-field with a valid target but no registered list-handler → Throw", () => {
|
|
3561
3728
|
const features = [
|
|
3562
3729
|
defineFeature("shop", (r) => {
|
|
3563
|
-
r.entity(
|
|
3730
|
+
r.entity(
|
|
3731
|
+
"product",
|
|
3732
|
+
createEntity({
|
|
3733
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3734
|
+
}),
|
|
3735
|
+
);
|
|
3564
3736
|
// KEIN stubListHandler — das ist der Punkt des Tests
|
|
3565
3737
|
r.entity(
|
|
3566
3738
|
"invoice",
|
|
@@ -3582,7 +3754,12 @@ describe("boot-validator", () => {
|
|
|
3582
3754
|
test("reference sub-field labelField referencing an unknown field → Throw with the parent.child field path", () => {
|
|
3583
3755
|
const features = [
|
|
3584
3756
|
defineFeature("shop", (r) => {
|
|
3585
|
-
r.entity(
|
|
3757
|
+
r.entity(
|
|
3758
|
+
"product",
|
|
3759
|
+
createEntity({
|
|
3760
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3761
|
+
}),
|
|
3762
|
+
);
|
|
3586
3763
|
stubListHandler(r, "product");
|
|
3587
3764
|
r.entity(
|
|
3588
3765
|
"invoice",
|
|
@@ -3610,7 +3787,12 @@ describe("boot-validator", () => {
|
|
|
3610
3787
|
describe("entityList rowAction kind=navigate (Tier 2.7e-1)", () => {
|
|
3611
3788
|
function makeFeature(targetScreen: string, withTarget: boolean) {
|
|
3612
3789
|
return defineFeature("shop", (r) => {
|
|
3613
|
-
r.entity(
|
|
3790
|
+
r.entity(
|
|
3791
|
+
"product",
|
|
3792
|
+
createEntity({
|
|
3793
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3794
|
+
}),
|
|
3795
|
+
);
|
|
3614
3796
|
r.screen({
|
|
3615
3797
|
id: "product-list",
|
|
3616
3798
|
type: "entityList",
|
|
@@ -3650,7 +3832,12 @@ describe("boot-validator", () => {
|
|
|
3650
3832
|
// Custom-Editor der Consumer-App (anderes Feature). Runtime löst die bare
|
|
3651
3833
|
// id app-weit auf → der Validator muss das erlauben.
|
|
3652
3834
|
const list = defineFeature("shop", (r) => {
|
|
3653
|
-
r.entity(
|
|
3835
|
+
r.entity(
|
|
3836
|
+
"product",
|
|
3837
|
+
createEntity({
|
|
3838
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3839
|
+
}),
|
|
3840
|
+
);
|
|
3654
3841
|
r.screen({
|
|
3655
3842
|
id: "product-list",
|
|
3656
3843
|
type: "entityList",
|
|
@@ -3673,7 +3860,12 @@ describe("boot-validator", () => {
|
|
|
3673
3860
|
// open with no entity context at runtime. The validator must catch it
|
|
3674
3861
|
// at boot instead.
|
|
3675
3862
|
const list = defineFeature("shop", (r) => {
|
|
3676
|
-
r.entity(
|
|
3863
|
+
r.entity(
|
|
3864
|
+
"product",
|
|
3865
|
+
createEntity({
|
|
3866
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3867
|
+
}),
|
|
3868
|
+
);
|
|
3677
3869
|
r.screen({
|
|
3678
3870
|
id: "product-list",
|
|
3679
3871
|
type: "entityList",
|
|
@@ -3685,7 +3877,12 @@ describe("boot-validator", () => {
|
|
|
3685
3877
|
});
|
|
3686
3878
|
});
|
|
3687
3879
|
const consumer = defineFeature("billing", (r) => {
|
|
3688
|
-
r.entity(
|
|
3880
|
+
r.entity(
|
|
3881
|
+
"invoice",
|
|
3882
|
+
createEntity({
|
|
3883
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3884
|
+
}),
|
|
3885
|
+
);
|
|
3689
3886
|
r.screen({
|
|
3690
3887
|
id: "invoice-edit",
|
|
3691
3888
|
type: "entityEdit",
|
|
@@ -3702,7 +3899,12 @@ describe("boot-validator", () => {
|
|
|
3702
3899
|
const list = defineFeature("shop", (r) => {
|
|
3703
3900
|
r.entity(
|
|
3704
3901
|
"product",
|
|
3705
|
-
createEntity({
|
|
3902
|
+
createEntity({
|
|
3903
|
+
fields: {
|
|
3904
|
+
name: createTextField({ personal: false, reason: "test_fixture" }),
|
|
3905
|
+
invoiceId: createTextField({ personal: false, reason: "test_fixture" }),
|
|
3906
|
+
},
|
|
3907
|
+
}),
|
|
3706
3908
|
);
|
|
3707
3909
|
r.screen({
|
|
3708
3910
|
id: "product-list",
|
|
@@ -3721,7 +3923,12 @@ describe("boot-validator", () => {
|
|
|
3721
3923
|
});
|
|
3722
3924
|
});
|
|
3723
3925
|
const consumer = defineFeature("billing", (r) => {
|
|
3724
|
-
r.entity(
|
|
3926
|
+
r.entity(
|
|
3927
|
+
"invoice",
|
|
3928
|
+
createEntity({
|
|
3929
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3930
|
+
}),
|
|
3931
|
+
);
|
|
3725
3932
|
r.screen({
|
|
3726
3933
|
id: "invoice-edit",
|
|
3727
3934
|
type: "entityEdit",
|
|
@@ -3734,7 +3941,12 @@ describe("boot-validator", () => {
|
|
|
3734
3941
|
|
|
3735
3942
|
test("same-feature navigate to entityEdit WITHOUT entityId → kein Throw (same-feature fallback applies)", () => {
|
|
3736
3943
|
const feature = defineFeature("shop", (r) => {
|
|
3737
|
-
r.entity(
|
|
3944
|
+
r.entity(
|
|
3945
|
+
"product",
|
|
3946
|
+
createEntity({
|
|
3947
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3948
|
+
}),
|
|
3949
|
+
);
|
|
3738
3950
|
r.screen({
|
|
3739
3951
|
id: "product-list",
|
|
3740
3952
|
type: "entityList",
|
|
@@ -3759,7 +3971,12 @@ describe("boot-validator", () => {
|
|
|
3759
3971
|
describe("entityList rowAction kind=navigate entity-target (fw#2228)", () => {
|
|
3760
3972
|
test("entity-target resolving via detailFor → kein Throw", () => {
|
|
3761
3973
|
const feature = defineFeature("shop", (r) => {
|
|
3762
|
-
r.entity(
|
|
3974
|
+
r.entity(
|
|
3975
|
+
"product",
|
|
3976
|
+
createEntity({
|
|
3977
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
3978
|
+
}),
|
|
3979
|
+
);
|
|
3763
3980
|
r.screen({
|
|
3764
3981
|
id: "product-list",
|
|
3765
3982
|
type: "entityList",
|
|
@@ -3779,7 +3996,12 @@ describe("boot-validator", () => {
|
|
|
3779
3996
|
|
|
3780
3997
|
test("entity-target with no detailFor screen anywhere → Throw mit klarer Message", () => {
|
|
3781
3998
|
const feature = defineFeature("shop", (r) => {
|
|
3782
|
-
r.entity(
|
|
3999
|
+
r.entity(
|
|
4000
|
+
"product",
|
|
4001
|
+
createEntity({
|
|
4002
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4003
|
+
}),
|
|
4004
|
+
);
|
|
3783
4005
|
r.screen({
|
|
3784
4006
|
id: "product-list",
|
|
3785
4007
|
type: "entityList",
|
|
@@ -3795,7 +4017,12 @@ describe("boot-validator", () => {
|
|
|
3795
4017
|
|
|
3796
4018
|
test("both screen and entity set → Throw", () => {
|
|
3797
4019
|
const feature = defineFeature("shop", (r) => {
|
|
3798
|
-
r.entity(
|
|
4020
|
+
r.entity(
|
|
4021
|
+
"product",
|
|
4022
|
+
createEntity({
|
|
4023
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4024
|
+
}),
|
|
4025
|
+
);
|
|
3799
4026
|
r.screen({
|
|
3800
4027
|
id: "product-list",
|
|
3801
4028
|
type: "entityList",
|
|
@@ -3825,7 +4052,12 @@ describe("boot-validator", () => {
|
|
|
3825
4052
|
|
|
3826
4053
|
test("neither screen nor entity set → Throw", () => {
|
|
3827
4054
|
const feature = defineFeature("shop", (r) => {
|
|
3828
|
-
r.entity(
|
|
4055
|
+
r.entity(
|
|
4056
|
+
"product",
|
|
4057
|
+
createEntity({
|
|
4058
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4059
|
+
}),
|
|
4060
|
+
);
|
|
3829
4061
|
r.screen({
|
|
3830
4062
|
id: "product-list",
|
|
3831
4063
|
type: "entityList",
|
|
@@ -3844,7 +4076,12 @@ describe("boot-validator", () => {
|
|
|
3844
4076
|
// detailFor resolution — the owning feature's list navigates to a
|
|
3845
4077
|
// detail screen a consumer app registers for the entity.
|
|
3846
4078
|
const list = defineFeature("shop", (r) => {
|
|
3847
|
-
r.entity(
|
|
4079
|
+
r.entity(
|
|
4080
|
+
"product",
|
|
4081
|
+
createEntity({
|
|
4082
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4083
|
+
}),
|
|
4084
|
+
);
|
|
3848
4085
|
r.screen({
|
|
3849
4086
|
id: "product-list",
|
|
3850
4087
|
type: "entityList",
|
|
@@ -3871,7 +4108,12 @@ describe("boot-validator", () => {
|
|
|
3871
4108
|
// row["id"]), so the same-feature-fallback gap that check guards
|
|
3872
4109
|
// against doesn't exist here.
|
|
3873
4110
|
const list = defineFeature("shop", (r) => {
|
|
3874
|
-
r.entity(
|
|
4111
|
+
r.entity(
|
|
4112
|
+
"product",
|
|
4113
|
+
createEntity({
|
|
4114
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4115
|
+
}),
|
|
4116
|
+
);
|
|
3875
4117
|
r.screen({
|
|
3876
4118
|
id: "product-list",
|
|
3877
4119
|
type: "entityList",
|
|
@@ -3881,7 +4123,12 @@ describe("boot-validator", () => {
|
|
|
3881
4123
|
});
|
|
3882
4124
|
});
|
|
3883
4125
|
const consumer = defineFeature("billing", (r) => {
|
|
3884
|
-
r.entity(
|
|
4126
|
+
r.entity(
|
|
4127
|
+
"invoice",
|
|
4128
|
+
createEntity({
|
|
4129
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4130
|
+
}),
|
|
4131
|
+
);
|
|
3885
4132
|
r.screen({
|
|
3886
4133
|
id: "invoice-edit",
|
|
3887
4134
|
type: "entityEdit",
|
|
@@ -3898,7 +4145,12 @@ describe("boot-validator", () => {
|
|
|
3898
4145
|
// guaranteed "id" field, unlike entityList rows — an entity-target
|
|
3899
4146
|
// there must name the field to read the id from.
|
|
3900
4147
|
const feature = defineFeature("shop", (r) => {
|
|
3901
|
-
r.entity(
|
|
4148
|
+
r.entity(
|
|
4149
|
+
"product",
|
|
4150
|
+
createEntity({
|
|
4151
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4152
|
+
}),
|
|
4153
|
+
);
|
|
3902
4154
|
r.queryHandler("products", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
3903
4155
|
access: { openToAll: true },
|
|
3904
4156
|
});
|
|
@@ -3923,7 +4175,12 @@ describe("boot-validator", () => {
|
|
|
3923
4175
|
|
|
3924
4176
|
test("projectionList rowAction entity-target with explicit entityId → kein Throw", () => {
|
|
3925
4177
|
const feature = defineFeature("shop", (r) => {
|
|
3926
|
-
r.entity(
|
|
4178
|
+
r.entity(
|
|
4179
|
+
"product",
|
|
4180
|
+
createEntity({
|
|
4181
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4182
|
+
}),
|
|
4183
|
+
);
|
|
3927
4184
|
r.queryHandler("products", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
3928
4185
|
access: { openToAll: true },
|
|
3929
4186
|
});
|
|
@@ -3954,7 +4211,12 @@ describe("boot-validator", () => {
|
|
|
3954
4211
|
|
|
3955
4212
|
test("projectionDetail action entity-target without explicit entityId → Throw", () => {
|
|
3956
4213
|
const feature = defineFeature("shop", (r) => {
|
|
3957
|
-
r.entity(
|
|
4214
|
+
r.entity(
|
|
4215
|
+
"product",
|
|
4216
|
+
createEntity({
|
|
4217
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4218
|
+
}),
|
|
4219
|
+
);
|
|
3958
4220
|
r.screen({
|
|
3959
4221
|
id: "order-detail",
|
|
3960
4222
|
type: "projectionDetail",
|
|
@@ -4004,7 +4266,12 @@ describe("boot-validator", () => {
|
|
|
4004
4266
|
|
|
4005
4267
|
test('entityEdit.actions drawer-target unknown → throw with actionLabel "action"', () => {
|
|
4006
4268
|
const feature = defineFeature("shop", (r) => {
|
|
4007
|
-
r.entity(
|
|
4269
|
+
r.entity(
|
|
4270
|
+
"product",
|
|
4271
|
+
createEntity({
|
|
4272
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4273
|
+
}),
|
|
4274
|
+
);
|
|
4008
4275
|
r.screen({
|
|
4009
4276
|
id: "product-edit",
|
|
4010
4277
|
type: "entityEdit",
|
|
@@ -4022,7 +4289,12 @@ describe("boot-validator", () => {
|
|
|
4022
4289
|
|
|
4023
4290
|
test("entityEdit.actions drawer-target → registered actionForm → no throw", () => {
|
|
4024
4291
|
const feature = defineFeature("shop", (r) => {
|
|
4025
|
-
r.entity(
|
|
4292
|
+
r.entity(
|
|
4293
|
+
"product",
|
|
4294
|
+
createEntity({
|
|
4295
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4296
|
+
}),
|
|
4297
|
+
);
|
|
4026
4298
|
r.writeHandler(
|
|
4027
4299
|
"add-note",
|
|
4028
4300
|
z.object({ note: z.string() }),
|
|
@@ -4187,7 +4459,12 @@ describe("boot-validator", () => {
|
|
|
4187
4459
|
describe("entityList rowAction rowClick", () => {
|
|
4188
4460
|
function makeFeature(rowClickCount: number) {
|
|
4189
4461
|
return defineFeature("shop", (r) => {
|
|
4190
|
-
r.entity(
|
|
4462
|
+
r.entity(
|
|
4463
|
+
"product",
|
|
4464
|
+
createEntity({
|
|
4465
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4466
|
+
}),
|
|
4467
|
+
);
|
|
4191
4468
|
r.screen({ id: "product-editor", type: "custom", renderer: { react: "stub" } });
|
|
4192
4469
|
r.screen({
|
|
4193
4470
|
id: "product-list",
|
|
@@ -4220,7 +4497,12 @@ describe("boot-validator", () => {
|
|
|
4220
4497
|
describe("entityList rowAction kind=writeHandler handler-QN", () => {
|
|
4221
4498
|
function makeFeature(handlerQn: string, register: boolean) {
|
|
4222
4499
|
return defineFeature("shop", (r) => {
|
|
4223
|
-
r.entity(
|
|
4500
|
+
r.entity(
|
|
4501
|
+
"product",
|
|
4502
|
+
createEntity({
|
|
4503
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4504
|
+
}),
|
|
4505
|
+
);
|
|
4224
4506
|
r.screen({
|
|
4225
4507
|
id: "product-list",
|
|
4226
4508
|
type: "entityList",
|
|
@@ -4261,7 +4543,12 @@ describe("boot-validator", () => {
|
|
|
4261
4543
|
describe("entityList rowAction payload pick (Tier 2.7e-3)", () => {
|
|
4262
4544
|
function makeFeature(pick: readonly string[]) {
|
|
4263
4545
|
return defineFeature("shop", (r) => {
|
|
4264
|
-
r.entity(
|
|
4546
|
+
r.entity(
|
|
4547
|
+
"product",
|
|
4548
|
+
createEntity({
|
|
4549
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4550
|
+
}),
|
|
4551
|
+
);
|
|
4265
4552
|
r.screen({
|
|
4266
4553
|
id: "product-list",
|
|
4267
4554
|
type: "entityList",
|
|
@@ -4318,7 +4605,7 @@ describe("boot-validator", () => {
|
|
|
4318
4605
|
r.entity(
|
|
4319
4606
|
"product",
|
|
4320
4607
|
createEntity({
|
|
4321
|
-
fields: { name: createTextField() },
|
|
4608
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4322
4609
|
softDelete: opts.softDelete ?? false,
|
|
4323
4610
|
}),
|
|
4324
4611
|
);
|
|
@@ -4394,7 +4681,12 @@ describe("boot-validator", () => {
|
|
|
4394
4681
|
describe("entityList toolbarAction navigate (Tier 2.7e-2)", () => {
|
|
4395
4682
|
function makeFeature(targetScreen: string, withTarget: boolean) {
|
|
4396
4683
|
return defineFeature("shop", (r) => {
|
|
4397
|
-
r.entity(
|
|
4684
|
+
r.entity(
|
|
4685
|
+
"product",
|
|
4686
|
+
createEntity({
|
|
4687
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4688
|
+
}),
|
|
4689
|
+
);
|
|
4398
4690
|
r.screen({
|
|
4399
4691
|
id: "product-list",
|
|
4400
4692
|
type: "entityList",
|
|
@@ -4422,7 +4714,12 @@ describe("boot-validator", () => {
|
|
|
4422
4714
|
|
|
4423
4715
|
test("navigate-target → screen in ANOTHER feature → kein Throw (cross-feature)", () => {
|
|
4424
4716
|
const list = defineFeature("shop", (r) => {
|
|
4425
|
-
r.entity(
|
|
4717
|
+
r.entity(
|
|
4718
|
+
"product",
|
|
4719
|
+
createEntity({
|
|
4720
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4721
|
+
}),
|
|
4722
|
+
);
|
|
4426
4723
|
r.screen({
|
|
4427
4724
|
id: "product-list",
|
|
4428
4725
|
type: "entityList",
|
|
@@ -4443,7 +4740,12 @@ describe("boot-validator", () => {
|
|
|
4443
4740
|
describe("entityList toolbarAction writeHandler handler-QN (Tier 2.7e-2)", () => {
|
|
4444
4741
|
function makeFeature(handlerQn: string, register: boolean) {
|
|
4445
4742
|
return defineFeature("shop", (r) => {
|
|
4446
|
-
r.entity(
|
|
4743
|
+
r.entity(
|
|
4744
|
+
"product",
|
|
4745
|
+
createEntity({
|
|
4746
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4747
|
+
}),
|
|
4748
|
+
);
|
|
4447
4749
|
r.screen({
|
|
4448
4750
|
id: "product-list",
|
|
4449
4751
|
type: "entityList",
|
|
@@ -4485,7 +4787,12 @@ describe("boot-validator", () => {
|
|
|
4485
4787
|
}) {
|
|
4486
4788
|
const targetId = opts.targetId ?? "restock-form";
|
|
4487
4789
|
return defineFeature("shop", (r) => {
|
|
4488
|
-
r.entity(
|
|
4790
|
+
r.entity(
|
|
4791
|
+
"product",
|
|
4792
|
+
createEntity({
|
|
4793
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4794
|
+
}),
|
|
4795
|
+
);
|
|
4489
4796
|
r.screen({
|
|
4490
4797
|
id: "product-list",
|
|
4491
4798
|
type: "entityList",
|
|
@@ -4542,7 +4849,12 @@ describe("boot-validator", () => {
|
|
|
4542
4849
|
|
|
4543
4850
|
test("drawer-target → actionForm in ANOTHER feature → throw (drawer resolves same-feature only)", () => {
|
|
4544
4851
|
const list = defineFeature("shop", (r) => {
|
|
4545
|
-
r.entity(
|
|
4852
|
+
r.entity(
|
|
4853
|
+
"product",
|
|
4854
|
+
createEntity({
|
|
4855
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4856
|
+
}),
|
|
4857
|
+
);
|
|
4546
4858
|
r.screen({
|
|
4547
4859
|
id: "product-list",
|
|
4548
4860
|
type: "entityList",
|
|
@@ -4582,7 +4894,12 @@ describe("boot-validator", () => {
|
|
|
4582
4894
|
}) {
|
|
4583
4895
|
const targetId = opts.targetId ?? "restock-form";
|
|
4584
4896
|
return defineFeature("shop", (r) => {
|
|
4585
|
-
r.entity(
|
|
4897
|
+
r.entity(
|
|
4898
|
+
"product",
|
|
4899
|
+
createEntity({
|
|
4900
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
4901
|
+
}),
|
|
4902
|
+
);
|
|
4586
4903
|
r.screen({
|
|
4587
4904
|
id: "product-list",
|
|
4588
4905
|
type: "entityList",
|
|
@@ -4804,7 +5121,12 @@ describe("boot-validator", () => {
|
|
|
4804
5121
|
test('screen.id mit "." → defineFeature throws (kebab-case)', () => {
|
|
4805
5122
|
expect(() =>
|
|
4806
5123
|
defineFeature("shop", (r) => {
|
|
4807
|
-
r.entity(
|
|
5124
|
+
r.entity(
|
|
5125
|
+
"product",
|
|
5126
|
+
createEntity({
|
|
5127
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5128
|
+
}),
|
|
5129
|
+
);
|
|
4808
5130
|
r.screen({
|
|
4809
5131
|
id: "product.list",
|
|
4810
5132
|
type: "entityList",
|
|
@@ -4817,7 +5139,12 @@ describe("boot-validator", () => {
|
|
|
4817
5139
|
|
|
4818
5140
|
test("screen.id im kebab-case → kein Throw", () => {
|
|
4819
5141
|
const feature = defineFeature("shop", (r) => {
|
|
4820
|
-
r.entity(
|
|
5142
|
+
r.entity(
|
|
5143
|
+
"product",
|
|
5144
|
+
createEntity({
|
|
5145
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5146
|
+
}),
|
|
5147
|
+
);
|
|
4821
5148
|
r.screen({ id: "product-list", type: "entityList", entity: "product", columns: ["name"] });
|
|
4822
5149
|
});
|
|
4823
5150
|
expect(() => validateBoot([feature])).not.toThrow();
|
|
@@ -4849,7 +5176,12 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
4849
5176
|
|
|
4850
5177
|
test("navigate with params targeting a dashboard screen without a filter → Throw (params would be a no-op)", () => {
|
|
4851
5178
|
const feature = defineFeature("shop", (r) => {
|
|
4852
|
-
r.entity(
|
|
5179
|
+
r.entity(
|
|
5180
|
+
"product",
|
|
5181
|
+
createEntity({
|
|
5182
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5183
|
+
}),
|
|
5184
|
+
);
|
|
4853
5185
|
r.screen({
|
|
4854
5186
|
id: "product-list",
|
|
4855
5187
|
type: "entityList",
|
|
@@ -4889,7 +5221,12 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
4889
5221
|
|
|
4890
5222
|
test("navigate with params targeting a dashboard screen with a matching filter → no throw (useFilterParams reads it, fw#1708 follow-up)", () => {
|
|
4891
5223
|
const feature = defineFeature("shop", (r) => {
|
|
4892
|
-
r.entity(
|
|
5224
|
+
r.entity(
|
|
5225
|
+
"product",
|
|
5226
|
+
createEntity({
|
|
5227
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5228
|
+
}),
|
|
5229
|
+
);
|
|
4893
5230
|
r.screen({
|
|
4894
5231
|
id: "product-list",
|
|
4895
5232
|
type: "entityList",
|
|
@@ -4933,7 +5270,12 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
4933
5270
|
|
|
4934
5271
|
test("navigate with params targeting a dashboard screen whose filter id doesn't match any extracted key → Throw", () => {
|
|
4935
5272
|
const feature = defineFeature("shop", (r) => {
|
|
4936
|
-
r.entity(
|
|
5273
|
+
r.entity(
|
|
5274
|
+
"product",
|
|
5275
|
+
createEntity({
|
|
5276
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5277
|
+
}),
|
|
5278
|
+
);
|
|
4937
5279
|
r.screen({
|
|
4938
5280
|
id: "product-list",
|
|
4939
5281
|
type: "entityList",
|
|
@@ -4979,8 +5321,18 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
4979
5321
|
|
|
4980
5322
|
test("navigate with params targeting a cross-entity entityList screen → no throw (list screens read URL search params for filter-prefill, fw#1708)", () => {
|
|
4981
5323
|
const feature = defineFeature("housing", (r) => {
|
|
4982
|
-
r.entity(
|
|
4983
|
-
|
|
5324
|
+
r.entity(
|
|
5325
|
+
"unit",
|
|
5326
|
+
createEntity({
|
|
5327
|
+
fields: { id: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5328
|
+
}),
|
|
5329
|
+
);
|
|
5330
|
+
r.entity(
|
|
5331
|
+
"contract",
|
|
5332
|
+
createEntity({
|
|
5333
|
+
fields: { unitId: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5334
|
+
}),
|
|
5335
|
+
);
|
|
4984
5336
|
r.screen({
|
|
4985
5337
|
id: "unit-list",
|
|
4986
5338
|
type: "entityList",
|
|
@@ -5008,7 +5360,12 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
5008
5360
|
|
|
5009
5361
|
test("navigate with params targeting a custom screen → no throw (author owns the component, may read searchParams itself)", () => {
|
|
5010
5362
|
const feature = defineFeature("shop", (r) => {
|
|
5011
|
-
r.entity(
|
|
5363
|
+
r.entity(
|
|
5364
|
+
"product",
|
|
5365
|
+
createEntity({
|
|
5366
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5367
|
+
}),
|
|
5368
|
+
);
|
|
5012
5369
|
r.screen({
|
|
5013
5370
|
id: "product-list",
|
|
5014
5371
|
type: "entityList",
|
|
@@ -5038,7 +5395,12 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
5038
5395
|
// runNavigate() auto-fills row["id"], landing in EntityEditUpdateBody,
|
|
5039
5396
|
// which never reads searchParams. Params would silently no-op.
|
|
5040
5397
|
const feature = defineFeature("shop", (r) => {
|
|
5041
|
-
r.entity(
|
|
5398
|
+
r.entity(
|
|
5399
|
+
"product",
|
|
5400
|
+
createEntity({
|
|
5401
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5402
|
+
}),
|
|
5403
|
+
);
|
|
5042
5404
|
r.screen({
|
|
5043
5405
|
id: "product-list",
|
|
5044
5406
|
type: "entityList",
|
|
@@ -5068,8 +5430,18 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
5068
5430
|
|
|
5069
5431
|
test("navigate with params + explicit entityId targeting an entityEdit screen → Throw (forced update mode)", () => {
|
|
5070
5432
|
const feature = defineFeature("housing", (r) => {
|
|
5071
|
-
r.entity(
|
|
5072
|
-
|
|
5433
|
+
r.entity(
|
|
5434
|
+
"unit",
|
|
5435
|
+
createEntity({
|
|
5436
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5437
|
+
}),
|
|
5438
|
+
);
|
|
5439
|
+
r.entity(
|
|
5440
|
+
"contract",
|
|
5441
|
+
createEntity({
|
|
5442
|
+
fields: { unitId: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5443
|
+
}),
|
|
5444
|
+
);
|
|
5073
5445
|
r.screen({
|
|
5074
5446
|
id: "unit-list",
|
|
5075
5447
|
type: "entityList",
|
|
@@ -5102,7 +5474,12 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
5102
5474
|
// extended to projectionList rowActions (#1680 covered entityList only).
|
|
5103
5475
|
test("projectionList rowAction: navigate with params to an entityEdit target + explicit entityId → Throw", () => {
|
|
5104
5476
|
const feature = defineFeature("shop", (r) => {
|
|
5105
|
-
r.entity(
|
|
5477
|
+
r.entity(
|
|
5478
|
+
"product",
|
|
5479
|
+
createEntity({
|
|
5480
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5481
|
+
}),
|
|
5482
|
+
);
|
|
5106
5483
|
r.screen({
|
|
5107
5484
|
id: "product-projection",
|
|
5108
5485
|
type: "projectionList",
|
|
@@ -5133,7 +5510,12 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
5133
5510
|
|
|
5134
5511
|
test("projectionList rowAction: navigate with params to an entityEdit-create target (no entityId) → no throw", () => {
|
|
5135
5512
|
const feature = defineFeature("shop", (r) => {
|
|
5136
|
-
r.entity(
|
|
5513
|
+
r.entity(
|
|
5514
|
+
"product",
|
|
5515
|
+
createEntity({
|
|
5516
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5517
|
+
}),
|
|
5518
|
+
);
|
|
5137
5519
|
r.queryHandler("products", z.object({}), async () => ({ rows: [], nextCursor: null }), {
|
|
5138
5520
|
access: { openToAll: true },
|
|
5139
5521
|
});
|
|
@@ -5168,8 +5550,18 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
5168
5550
|
// renderer's same-entity row["id"] fallback does NOT fire, so this stays
|
|
5169
5551
|
// in create mode and EntityEditCreateBody reads the params.
|
|
5170
5552
|
const feature = defineFeature("housing", (r) => {
|
|
5171
|
-
r.entity(
|
|
5172
|
-
|
|
5553
|
+
r.entity(
|
|
5554
|
+
"unit",
|
|
5555
|
+
createEntity({
|
|
5556
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5557
|
+
}),
|
|
5558
|
+
);
|
|
5559
|
+
r.entity(
|
|
5560
|
+
"contract",
|
|
5561
|
+
createEntity({
|
|
5562
|
+
fields: { unitId: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5563
|
+
}),
|
|
5564
|
+
);
|
|
5173
5565
|
r.screen({
|
|
5174
5566
|
id: "unit-list",
|
|
5175
5567
|
type: "entityList",
|
|
@@ -5197,7 +5589,12 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
5197
5589
|
|
|
5198
5590
|
test("navigate with params targeting an actionForm screen → no throw", () => {
|
|
5199
5591
|
const feature = defineFeature("shop", (r) => {
|
|
5200
|
-
r.entity(
|
|
5592
|
+
r.entity(
|
|
5593
|
+
"product",
|
|
5594
|
+
createEntity({
|
|
5595
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5596
|
+
}),
|
|
5597
|
+
);
|
|
5201
5598
|
r.writeHandler(
|
|
5202
5599
|
"create",
|
|
5203
5600
|
z.object({ name: z.string() }),
|
|
@@ -5223,7 +5620,7 @@ describe("boot-validator — config key backing × scope", () => {
|
|
|
5223
5620
|
id: "product-form",
|
|
5224
5621
|
type: "actionForm",
|
|
5225
5622
|
handler: "shop:write:create",
|
|
5226
|
-
fields: { name: createTextField() },
|
|
5623
|
+
fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
|
|
5227
5624
|
layout: { sections: [{ columns: 1, fields: ["name"] }] },
|
|
5228
5625
|
});
|
|
5229
5626
|
});
|