Files
nidus/internal/web/resources_test.go
T
arnefandCopilot ebbc7a2a2b Add calendar color support (DAVx5 calendar-color)
Calendars can now have a color (hex, e.g. #3b82f6) that DAVx5 and other
CalDAV clients pick up via the Apple/dav4jvm calendar-color property.

- db: add calendars.color column with migration for existing DBs;
  CreateCalendarWithColor, SetCalendarColor, GetCalendarColor;
  ListCalendars now returns []Calendar{Name, Color} instead of []string
- caldav: since go-webdav's caldav.Backend interface has no extension
  point for vendor properties, wrap the handler with a response-rewriting
  middleware that injects <calendar-color xmlns="http://apple.com/ns/ical/">
  into PROPFIND responses for calendars that have a color set
- web: color picker on the "New calendar" form and an inline color swatch/
  picker on each calendar card (calendars only, not address books)
- nidusctl: `calendar create --color` flag and a new `calendar color`
  subcommand; `calendar list` now also prints the color if set

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-20 06:43:56 +02:00

104 lines
3.1 KiB
Go

package web
import (
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
)
func TestCreateAndDeleteCalendarViaWebUI(t *testing.T) {
s := newTestServer(t)
handler := s.Handler(emptyStaticFS{})
cookie := loginAs(t, handler, "alice", "password")
// Create a new calendar.
form := url.Values{"name": {"vacation"}}
req := httptest.NewRequest(http.MethodPost, "/resources/calendar", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.AddCookie(cookie)
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("create: expected 200, got %d: %s", rr.Code, rr.Body.String())
}
if !strings.Contains(rr.Body.String(), "vacation") {
t.Fatalf("expected resource list to include new calendar, got: %s", rr.Body.String())
}
names, err := s.dbase.ListCalendars("alice")
if err != nil {
t.Fatalf("ListCalendars: %v", err)
}
found := false
for _, c := range names {
if c.Name == "vacation" {
found = true
}
}
if !found {
t.Fatalf("expected vacation calendar to be registered, got %v", names)
}
// Duplicate creation should fail with 409.
req = httptest.NewRequest(http.MethodPost, "/resources/calendar", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.AddCookie(cookie)
rr = httptest.NewRecorder()
handler.ServeHTTP(rr, req)
if rr.Code != http.StatusConflict {
t.Fatalf("expected 409 on duplicate create, got %d", rr.Code)
}
// Delete it — htmx v2 sends DELETE params as a URL query string.
req = httptest.NewRequest(http.MethodDelete, "/resources/calendar?name=vacation", nil)
req.AddCookie(cookie)
rr = httptest.NewRecorder()
handler.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("delete: expected 200, got %d: %s", rr.Code, rr.Body.String())
}
if strings.Contains(rr.Body.String(), "vacation") {
t.Fatalf("expected resource list to no longer include deleted calendar, got: %s", rr.Body.String())
}
names, err = s.dbase.ListCalendars("alice")
if err != nil {
t.Fatalf("ListCalendars: %v", err)
}
for _, c := range names {
if c.Name == "vacation" {
t.Fatalf("expected vacation calendar to be gone, got %v", names)
}
}
}
func TestCreateAddressBookInvalidName(t *testing.T) {
s := newTestServer(t)
handler := s.Handler(emptyStaticFS{})
cookie := loginAs(t, handler, "alice", "password")
form := url.Values{"name": {"has a space"}}
req := httptest.NewRequest(http.MethodPost, "/resources/addressbook", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.AddCookie(cookie)
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
if rr.Code != http.StatusBadRequest {
t.Fatalf("expected 400 for invalid name, got %d", rr.Code)
}
}
func TestDeleteCalendarRequiresLogin(t *testing.T) {
s := newTestServer(t)
handler := s.Handler(emptyStaticFS{})
req := httptest.NewRequest(http.MethodDelete, "/resources/calendar?name=work", nil)
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
if rr.Code != http.StatusSeeOther {
t.Fatalf("expected redirect to login, got %d", rr.Code)
}
}