appointments_test.go
⎇
Raw
1package web
2
3import (
4 "io"
5 "net/http"
6 "net/url"
7 "regexp"
8 "strings"
9 "testing"
10 "time"
11
12 "forge.gpl-nas.de/physiobase/internal/config"
13)
14
15func TestAppointmentsAndCalendar(t *testing.T) {
16 ts, c := newServerCfg(t, func(cfg *config.Config) {
17 cfg.PublicURL = "https://physio.example.org"
18 cfg.Address = "Musterstraße 1, 50667 Köln"
19 })
20 login(t, c, ts.URL)
21 post(c, ts.URL+"/patienten", url.Values{"name": {"Kai Kalender"}})
22 post(c, ts.URL+"/behandler", url.Values{"name": {"Anna Schmidt"}})
23
24 // Serie: 3× wöchentlich, ab morgen
25 day := time.Now().AddDate(0, 0, 1).Format("2006-01-02")
26 r, _ := post(c, ts.URL+"/termine", url.Values{
27 "patient": {"1"}, "date": {day}, "time": {"09:30"}, "duration": {"25"},
28 "therapist": {"1"}, "title": {"Krankengymnastik"}, "note": {"Handtuch, mitbringen; bitte"}, "repeat": {"3"}, "every": {"7"}, "back": {"patient"},
29 })
30 if r.Header.Get("Location") != "/patient/1#termine" {
31 t.Fatalf("Termin anlegen: %d %s", r.StatusCode, r.Header.Get("Location"))
32 }
33 _, html := body(t, c, ts.URL+"/patient/1")
34 if strings.Count(html, "Krankengymnastik · Anna Schmidt") != 3 {
35 t.Fatalf("Serie nicht vollständig auf der Patientenseite")
36 }
37 m := regexp.MustCompile(`https://physio\.example\.org/kalender/([0-9a-f]{48})\.ics`).FindStringSubmatch(html)
38 if m == nil || !strings.Contains(html, "webcal://physio.example.org/kalender/") {
39 t.Fatal("Kalender-Link fehlt")
40 }
41 feed := "/kalender/" + m[1] + ".ics"
42
43 // Feed ohne Login abrufbar, korrektes Format, keine Gesundheitsdaten/Namen
44 anon := &http.Client{}
45 resp, err := anon.Get(ts.URL + feed)
46 if err != nil {
47 t.Fatal(err)
48 }
49 b, _ := io.ReadAll(resp.Body)
50 resp.Body.Close()
51 ics := string(b)
52 if resp.StatusCode != http.StatusOK || !strings.HasPrefix(resp.Header.Get("Content-Type"), "text/calendar") {
53 t.Fatalf("Feed: %d %s", resp.StatusCode, resp.Header.Get("Content-Type"))
54 }
55 for _, want := range []string{
56 "BEGIN:VCALENDAR", "SUMMARY:Krankengymnastik – Test", "Behandlung bei: Anna Schmidt",
57 `Hinweis: Handtuch\, mitbringen\; bitte`, `LOCATION:Musterstraße 1\, 50667 Köln`, "STATUS:CONFIRMED",
58 } {
59 if !strings.Contains(strings.ReplaceAll(ics, "\r\n ", ""), want) {
60 t.Errorf("Feed ohne %q", want)
61 }
62 }
63 if strings.Count(ics, "BEGIN:VEVENT") != 3 || strings.Contains(ics, "Kai Kalender") {
64 t.Error("Feed: falsche Anzahl Termine oder Patientenname enthalten")
65 }
66
67 // Absagen → STATUS:CANCELLED, SEQUENCE steigt
68 post(c, ts.URL+"/termin/1/absagen", nil)
69 resp, _ = anon.Get(ts.URL + feed)
70 b, _ = io.ReadAll(resp.Body)
71 resp.Body.Close()
72 if !strings.Contains(string(b), "STATUS:CANCELLED") || !strings.Contains(string(b), "SEQUENCE:1") {
73 t.Error("Absage nicht im Feed")
74 }
75
76 // Falscher Token → 404; Link erneuern macht alten Link ungültig
77 if resp, _ := anon.Get(ts.URL + "/kalender/" + strings.Repeat("0", 48) + ".ics"); resp.StatusCode != http.StatusNotFound {
78 t.Errorf("falscher Token: %d", resp.StatusCode)
79 }
80 post(c, ts.URL+"/patient/1/kalender-link", nil)
81 if resp, _ := anon.Get(ts.URL + feed); resp.StatusCode != http.StatusNotFound {
82 t.Errorf("alter Link nach Erneuern noch gültig: %d", resp.StatusCode)
83 }
84
85 // QR-Code, Druckliste, Übersicht
86 if code, svg := body(t, c, ts.URL+"/patient/1/kalender-qr.svg"); code != http.StatusOK || !strings.HasPrefix(svg, "<svg") {
87 t.Errorf("QR: %d", code)
88 }
89 if _, pr := body(t, c, ts.URL+"/patient/1/termine/druck"); !strings.Contains(pr, "Ihre Termine") || strings.Count(pr, "Anna Schmidt") < 3 {
90 t.Error("Druckliste unvollständig")
91 }
92 if _, ov := body(t, c, ts.URL+"/termine"); !strings.Contains(ov, "Kai Kalender") || !strings.Contains(ov, "abgesagt") {
93 t.Error("Übersicht unvollständig")
94 }
95
96 // Behandlungszusammenfassung nennt den nächsten Termin
97 post(c, ts.URL+"/patient/1/verlauf", url.Values{"date": {time.Now().Format("2006-01-02")}, "goal": {"Mobilisation"}})
98 r, _ = post(c, ts.URL+"/verlauf/1/zusammenfassung", nil)
99 if _, sum := body(t, c, ts.URL+r.Header.Get("Location")); !strings.Contains(sum, "um 09:30 Uhr bei Anna Schmidt") {
100 t.Error("nächster Termin fehlt in der Zusammenfassung")
101 }
102}
103