@@ -0,0 +1,99 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gardomatic.kleiax.de/lib/client"
|
||||
)
|
||||
|
||||
func TestJournalTemplateRendersMetadataMarkdownAndMedia(t *testing.T) {
|
||||
app := newTestApplication(t)
|
||||
garden := client.Garden{ID: 3, Name: "Hinterhof", Role: "owner"}
|
||||
entry := client.JournalEntry{ID: 7, GardenID: 3, AuthorName: "Ada", Title: "Ernte", Body: "**Drei** Tomaten.\n\n<script>alert(1)</script>", CreatedAt: time.Date(2026, 9, 5, 14, 30, 0, 0, time.Local), Tags: []string{"tomaten"}, Attachments: []client.JournalAttachment{{ID: 9, EntryID: 7, FileName: "foto.jpg", MediaType: "image/jpeg", Size: 2048}}}
|
||||
response := httptest.NewRecorder()
|
||||
app.render(response, http.StatusOK, "journal.tmpl", &templateData{commonTemplateData: commonTemplateData{Garden: &garden}, journalTemplateData: journalTemplateData{JournalEntries: []client.JournalEntry{entry}}})
|
||||
body := response.Body.String()
|
||||
for _, want := range []string{"<strong>Drei</strong>", "05.09.2026 · 14:30 Uhr", "Ada", "tomaten", "/g/3/journal/attachments/7/9", "Tagebuch", "data-card-href='/g/3/journal/edit/7'"} {
|
||||
if !strings.Contains(body, want) {
|
||||
t.Errorf("journal output missing %q: %s", want, body)
|
||||
}
|
||||
}
|
||||
if strings.Contains(body, "<script>alert(1)</script>") {
|
||||
t.Fatalf("raw HTML was not escaped: %s", body)
|
||||
}
|
||||
if strings.Contains(body, ">Bearbeiten</a>") {
|
||||
t.Fatalf("journal tile still exposes a separate edit link: %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJournalFormOffersBothEditorModesAndCaptureInputs(t *testing.T) {
|
||||
app := newTestApplication(t)
|
||||
garden := client.Garden{ID: 3, Name: "Hinterhof", Role: "owner"}
|
||||
response := httptest.NewRecorder()
|
||||
app.render(response, http.StatusOK, "journal_form.tmpl", &templateData{commonTemplateData: commonTemplateData{Garden: &garden, Form: journalForm{Body: "# Notiz", Errors: map[string]string{}}, UseJournalEditor: true}})
|
||||
body := response.Body.String()
|
||||
for _, want := range []string{"toastui-editor-3.2.2.min.js", "data-journal-editor", "data-journal-body", "data-image-camera", "data-video-record", "data-video-pause", "data-video-apply", "Mediendateien auswählen", "Audio aufnehmen", "data-audio-dialog", "data-audio-preview", "data-audio-pause", "data-audio-apply", "data-recording-indicator", "name='embedded_images'", "data-tag-editor", "data-tag-suggestions"} {
|
||||
if !strings.Contains(body, want) {
|
||||
t.Errorf("journal form missing %q: %s", want, body)
|
||||
}
|
||||
}
|
||||
if strings.Contains(body, "data-image-preview") || strings.Contains(body, "data-image-file") {
|
||||
t.Fatalf("photo capture should expose one button, not a persistent preview/file picker: %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPinboardReusesEntryAndPhotoComponents(t *testing.T) {
|
||||
app := newTestApplication(t)
|
||||
garden := client.Garden{ID: 3, Name: "Hinterhof", Role: "owner"}
|
||||
entry := client.JournalEntry{ID: 8, GardenID: 3, EntryType: client.JournalEntryTypePinboard, AuthorName: "Ada", Title: "Sitzecke", Body: "Bank unter den Apfelbaum", CreatedAt: time.Date(2026, 9, 6, 10, 0, 0, 0, time.Local), Attachments: []client.JournalAttachment{{ID: 11, EntryID: 8, FileName: "idee.jpg", MediaType: "image/jpeg", Size: 1024}}}
|
||||
|
||||
listResponse := httptest.NewRecorder()
|
||||
app.render(listResponse, http.StatusOK, "journal.tmpl", &templateData{commonTemplateData: commonTemplateData{Garden: &garden, ContentKind: client.JournalEntryTypePinboard}, journalTemplateData: journalTemplateData{JournalEntries: []client.JournalEntry{entry}}})
|
||||
listBody := listResponse.Body.String()
|
||||
for _, want := range []string{"Pinnwand", "pinboard-list", "data-card-href='/g/3/pinboard/edit/8'", "/g/3/pinboard/attachments/8/11", "Bank unter den Apfelbaum"} {
|
||||
if !strings.Contains(listBody, want) {
|
||||
t.Errorf("pinboard output missing %q: %s", want, listBody)
|
||||
}
|
||||
}
|
||||
|
||||
formResponse := httptest.NewRecorder()
|
||||
app.render(formResponse, http.StatusOK, "journal_form.tmpl", &templateData{commonTemplateData: commonTemplateData{Garden: &garden, ContentKind: client.JournalEntryTypePinboard, Form: journalForm{DateTime: "2026-09-06T10:00", Errors: map[string]string{}}, UseJournalEditor: true}, mediaTemplateData: mediaTemplateData{Images: []client.Image{{ID: 4, FileName: "vorhanden.jpg"}}}})
|
||||
formBody := formResponse.Body.String()
|
||||
for _, want := range []string{"Neue Notiz", "Fotos auswählen", "Foto mit Gerät aufnehmen", "Aus Bilderdatenbank", "href='/g/3/pinboard'"} {
|
||||
if !strings.Contains(formBody, want) {
|
||||
t.Errorf("pinboard form missing %q: %s", want, formBody)
|
||||
}
|
||||
}
|
||||
if strings.Contains(formBody, "name='title' value='' maxlength='500' required") {
|
||||
t.Fatalf("pinboard title is still required: %s", formBody)
|
||||
}
|
||||
if strings.Contains(formBody, "data-video-record") || strings.Contains(formBody, "data-audio-record") {
|
||||
t.Fatalf("simple pinboard form exposes journal recording controls: %s", formBody)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPinboardSearchCardLinksBackToPinboard(t *testing.T) {
|
||||
card := gardenEntrySearchCard(3, client.JournalEntry{ID: 8, EntryType: client.JournalEntryTypePinboard, Title: "Sitzecke"})
|
||||
if card.Type != "Pinnwand" || card.URL != "/g/3/pinboard#entry-8" {
|
||||
t.Fatalf("pinboard search card: %+v", card)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDashboardShowsJournalEntryCount(t *testing.T) {
|
||||
app := newTestApplication(t)
|
||||
garden := client.Garden{ID: 3, Name: "Hinterhof", Role: "owner"}
|
||||
entries := []client.JournalEntry{{ID: 1}, {ID: 2}, {ID: 3}}
|
||||
response := httptest.NewRecorder()
|
||||
app.render(response, http.StatusOK, "dashboard.tmpl", &templateData{commonTemplateData: commonTemplateData{Garden: &garden}, journalTemplateData: journalTemplateData{JournalEntries: entries, PinboardEntries: []client.JournalEntry{{ID: 4}}}})
|
||||
body := response.Body.String()
|
||||
if !strings.Contains(body, "href='/g/3/journal'") || !strings.Contains(body, "<span class='summary-number'>3</span><h3>Tagebuch</h3>") {
|
||||
t.Fatalf("dashboard output missing journal count: %s", body)
|
||||
}
|
||||
if !strings.Contains(body, "href='/g/3/pinboard'") || !strings.Contains(body, "<span class='summary-number'>1</span><h3>Pinnwand</h3>") {
|
||||
t.Fatalf("dashboard output missing pinboard count: %s", body)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user