Files
summercms/modules/cabana/field_trigger_smoke_test.go
Jakub Zych 7091d09699 feat(19.6.1-02): field trigger and admin build
- fields.yaml trigger (action disable|hide, field, condition checked|unchecked) compiled to FormField.Trigger
- boot errors for malformed triggers, controlling fields that are not a switch or checkbox, and triggers in repeater rows, settings and relation forms
- Administrators permissions overrides are disabled while Superuser is on (D-06)
- SPA: trigger.ts (triggerState, applyTriggers), FORM_TRIGGER_NOTES, the trigger note in FormField, FormView tabs/banner/payload after triggers, PreviewView hide only
- regenerated admin OpenAPI and schema.d.ts; rebuilt modules/boardwalk/dist; docs and README
2026-10-22 11:43:58 +02:00

108 lines
5.0 KiB
Go

package cabana
import (
"context"
"strings"
"testing"
"testing/fstest"
)
type triggerController struct{}
func (triggerController) ID() string { return "acme.trig.items" }
func (triggerController) ModelName() string { return "Item" }
func (triggerController) ConfigDir() string { return "controllers/items" }
func compileTriggerForm(fields string) (*FormSchema, error) {
fsys := fstest.MapFS{
"controllers/items/config_form.yaml": &fstest.MapFile{Data: []byte("form: ~/plugins/acme/trig/models/item/fields.yaml\nmodelClass: Item\n")},
"models/item/fields.yaml": &fstest.MapFile{Data: []byte(fields)},
}
return CompileForm("acme.trig", triggerController{}, fsys)
}
func TestFieldTriggerSmoke(t *testing.T) {
base := "fields:\n is_admin:\n type: switch\n title:\n type: text\n"
valid := base + " notes:\n type: textarea\n trigger:\n action: disable\n field: is_admin\n condition: checked\n"
t.Run("a valid trigger compiles and reaches the schema", func(t *testing.T) {
schema, err := compileTriggerForm(valid)
if err != nil {
t.Fatal(err)
}
view, err := schema.Localize(context.Background(), nil, nil)
if err != nil {
t.Fatal(err)
}
var got *FieldTrigger
for _, field := range view.Fields {
if field.Name == "notes" {
got = field.Trigger
}
}
if got == nil || *got != (FieldTrigger{Action: "disable", Field: "is_admin", Condition: "checked"}) {
t.Fatalf("notes trigger = %+v", got)
}
if got == schema.Fields[2].Trigger {
t.Fatal("the localized view shares the cached trigger")
}
})
trig := func(body string) string { return base + " notes:\n type: textarea\n trigger:\n" + body }
for _, tc := range []struct{ name, fields, want string }{
{"unknown action", trig(" action: show\n field: is_admin\n condition: checked\n"), "action show is not supported"},
{"unknown condition", trig(" action: hide\n field: is_admin\n condition: value[1]\n"), "condition value[1] is not supported"},
{"extra sub-key", trig(" action: hide\n field: is_admin\n condition: checked\n value: 1\n"), "unknown key value"},
{"missing field", trig(" action: hide\n condition: checked\n"), "field is required"},
{"not a mapping", base + " notes:\n type: textarea\n trigger: is_admin\n", "trigger must be a mapping"},
{"self reference", base + " notes:\n type: checkbox\n trigger:\n action: hide\n field: notes\n condition: checked\n", "names the field itself"},
{"unknown controlling field", trig(" action: hide\n field: active\n condition: checked\n"), "trigger field active is not a field of this form"},
{"text controlling field", trig(" action: hide\n field: title\n condition: unchecked\n"), "trigger field title must be a switch or checkbox"},
{"in a repeater row", base + " rows:\n type: repeater\n form:\n fields:\n flag:\n type: checkbox\n notes:\n type: text\n trigger:\n action: hide\n field: flag\n condition: checked\n", "trigger is not supported in a repeater row"},
} {
t.Run(tc.name, func(t *testing.T) {
_, err := compileTriggerForm(tc.fields)
if err == nil {
t.Fatalf("compiled; want an error containing %q", tc.want)
}
msg := err.Error()
if !strings.Contains(msg, tc.want) || !strings.Contains(msg, "trigger") || !strings.Contains(msg, "notes") {
t.Fatalf("err = %v, want it to name notes, trigger and %q", err, tc.want)
}
if !strings.Contains(msg, "acme.trig.items") {
t.Fatalf("err = %v, want the controller named", err)
}
})
}
t.Run("settings and relation forms refuse trigger", func(t *testing.T) {
field := FormField{Name: "notes", Type: "text", Trigger: &FieldTrigger{Action: "hide", Field: "flag", Condition: "checked"}}
if err := settingsFormOnly(field); err == nil || !strings.Contains(err.Error(), "trigger") {
t.Fatalf("settingsFormOnly = %v", err)
}
if err := controllerFormOnly(field); err == nil || !strings.Contains(err.Error(), "trigger") {
t.Fatalf("controllerFormOnly = %v", err)
}
})
t.Run("the Administrators form disables overrides while Superuser is on", func(t *testing.T) {
reg, err := compileWithScreens(t, nil)
if err != nil {
t.Fatal(err)
}
cc, ok := reg.Get(AdministratorsControllerID)
if !ok || cc.Form == nil {
t.Fatal("no administrators form")
}
for _, field := range cc.Form.Fields {
if field.Name == usersPermissionsField {
if field.Trigger == nil || *field.Trigger != (FieldTrigger{Action: "disable", Field: usersSuperuserField, Condition: "checked"}) {
t.Fatalf("permissions trigger = %+v", field.Trigger)
}
return
}
}
t.Fatal("administrators form has no permissions field")
})
}