mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-10-28 15:51:15 +00:00
Services declare up to 8 intake fields (text/yesno, required) stored as JSONB; shared/intake.go is the single normalization point — slug keys, label/dup/unknown-key rules, yes/no canonicalization. Booking create validates answers against the service declaration (missing required -> 400), unknown keys are dropped before persist. Answers surface on UpcomingBooking and CustomerBookingView; the services page gains a compact editor and the public form renders declared questions under contact details. Verified live end-to-end. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
84 lines
2.5 KiB
Go
84 lines
2.5 KiB
Go
package shared
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"bookra/apps/backend/internal/domain"
|
|
)
|
|
|
|
func TestNormalizeIntakeFields(t *testing.T) {
|
|
raw, err := NormalizeIntakeFields([]domain.IntakeField{
|
|
{Label: "First visit?", Type: "yesno", Required: true},
|
|
{Key: "injuries", Label: "Injuries or health notes", Type: "text"},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("normalize: %v", err)
|
|
}
|
|
fields := ParseIntakeFields(raw)
|
|
if len(fields) != 2 {
|
|
t.Fatalf("expected 2 fields, got %d", len(fields))
|
|
}
|
|
if fields[0].Key != "first_visit" || !fields[0].Required {
|
|
t.Fatalf("unexpected field normalization: %+v", fields[0])
|
|
}
|
|
|
|
if _, err := NormalizeIntakeFields([]domain.IntakeField{
|
|
{Label: "A", Type: "yesno"}, {Label: "A", Type: "text"},
|
|
}); err == nil {
|
|
t.Fatal("expected duplicate key error")
|
|
}
|
|
if _, err := NormalizeIntakeFields([]domain.IntakeField{
|
|
{Label: "A", Type: "radio"},
|
|
}); err == nil {
|
|
t.Fatal("expected bad type error")
|
|
}
|
|
nine := make([]domain.IntakeField, 9)
|
|
for i := range nine {
|
|
nine[i] = domain.IntakeField{Key: strings.Repeat("k", i+1), Label: "L", Type: "text"}
|
|
}
|
|
if _, err := NormalizeIntakeFields(nine); err == nil {
|
|
t.Fatal("expected max-8 error")
|
|
}
|
|
}
|
|
|
|
func TestNormalizeIntakeAnswers(t *testing.T) {
|
|
fields := []domain.IntakeField{
|
|
{Key: "first_visit", Label: "First visit?", Type: "yesno", Required: true},
|
|
{Key: "injuries", Label: "Injuries?", Type: "text"},
|
|
}
|
|
|
|
raw, err := NormalizeIntakeAnswers(fields, map[string]string{
|
|
"first_visit": "yes",
|
|
"injuries": " sore knee ",
|
|
"undeclared": "dropped",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("normalize answers: %v", err)
|
|
}
|
|
answers := ParseIntakeAnswers(raw)
|
|
if answers["first_visit"] != "yes" || answers["injuries"] != "sore knee" {
|
|
t.Fatalf("unexpected answers: %+v", answers)
|
|
}
|
|
if _, ok := answers["undeclared"]; ok {
|
|
t.Fatal("undeclared key should be dropped")
|
|
}
|
|
|
|
if _, err := NormalizeIntakeAnswers(fields, map[string]string{}); err == nil {
|
|
t.Fatal("expected required-field error")
|
|
}
|
|
if _, err := NormalizeIntakeAnswers(fields, map[string]string{"first_visit": "maybe"}); err == nil {
|
|
t.Fatal("expected yesno coercion error")
|
|
}
|
|
if _, err := NormalizeIntakeAnswers(fields, map[string]string{
|
|
"first_visit": "no", "injuries": strings.Repeat("x", 501),
|
|
}); err == nil {
|
|
t.Fatal("expected text cap error")
|
|
}
|
|
|
|
raw, err = NormalizeIntakeAnswers(nil, map[string]string{"anything": "ignored"})
|
|
if err != nil || raw != "{}" {
|
|
t.Fatalf("expected {} for no declared fields, got %q err=%v", raw, err)
|
|
}
|
|
}
|