package gonexapp_test import ( "html" "net/http" "net/http/httptest" "net/url" "strings" "testing" "gitea.neitzel.de/konrad/go-nc-exapp" ) func sampleNavigation() gonexapp.AppNavigation { items := []gonexapp.Item{ { ID: "domains", Label: "Domains", Children: []gonexapp.Item{{ID: "example.com", Label: "example.com"}}, }, {ID: "keys", Label: "Keys"}, } return gonexapp.AppNavigation{ Items: func(*http.Request) []gonexapp.Item { return items }, Page: func(_ *http.Request, id string) (string, bool) { switch id { case "domains": return "
domains-page
", true case "keys": return "keys-page
", true case "example.com": return "zone-page
", true default: return "", false } }, Header: func(*http.Request) string { return `folder-line
` }, DefaultID: "domains", MissingMessage: "that item is not in this Visit", } } func navBody(t *testing.T, rawURL string) string { t.Helper() rec := httptest.NewRecorder() sampleNavigation().Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, rawURL, nil)) if rec.Code != http.StatusOK { t.Fatalf("GET %s: got %d", rawURL, rec.Code) } return rec.Body.String() } func navAddress(t *testing.T, body string) url.Values { t.Helper() const key = `data-address="` _, after, ok := strings.Cut(body, key) if !ok { t.Fatalf("no data-address in %s", body) } rest := after end := strings.Index(rest, `"`) if end < 0 { t.Fatalf("unclosed data-address") } raw, err := url.QueryUnescape(html.UnescapeString(rest[:end])) if err != nil { t.Fatal(err) } q, err := url.ParseQuery(strings.TrimPrefix(raw, "?")) if err != nil { t.Fatal(err) } return q } func TestAppNavigationShowsSelectedPage(t *testing.T) { body := navBody(t, "/?item=keys") if !strings.Contains(body, "keys-page
") { t.Fatalf("got %s", body) } if !strings.Contains(body, `data-selected="keys"`) { t.Fatalf("got %s", body) } if navAddress(t, body).Get("item") != "keys" { t.Fatalf("address: %s", navAddress(t, body).Encode()) } } func TestAppNavigationDefaultsWhenItemMissingFromAddress(t *testing.T) { body := navBody(t, "/") if !strings.Contains(body, "domains-page
") { t.Fatalf("got %s", body) } if navAddress(t, body).Get("item") != "domains" { t.Fatalf("address item = %q", navAddress(t, body).Get("item")) } if strings.Contains(body, "that item is not in this Visit") { t.Fatalf("default open should not show the missing-item message: %s", body) } } func TestAppNavigationMissingItemSelectsDefault(t *testing.T) { body := navBody(t, "/?folder=share&item=gone") if !strings.Contains(body, "domains-page
") { t.Fatalf("got %s", body) } if !strings.Contains(body, "that item is not in this Visit") { t.Fatalf("got %s", body) } q := navAddress(t, body) if q.Get("item") != "domains" || q.Get("folder") != "share" { t.Fatalf("address = %s", q.Encode()) } } func TestAppNavigationPageRefusalSelectsDefault(t *testing.T) { nav := sampleNavigation() inner := nav.Page nav.Page = func(r *http.Request, id string) (string, bool) { if id == "keys" { return "", false } return inner(r, id) } rec := httptest.NewRecorder() nav.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/?folder=share&item=keys", nil)) if rec.Code != http.StatusOK { t.Fatalf("got %d", rec.Code) } body := rec.Body.String() if !strings.Contains(body, "domains-page
") || !strings.Contains(body, "that item is not in this Visit") { t.Fatalf("got %s", body) } q := navAddress(t, body) if q.Get("item") != "domains" || q.Get("folder") != "share" { t.Fatalf("address = %s", q.Encode()) } } func TestAppNavigationChildExpandsParents(t *testing.T) { body := navBody(t, "/?item=example.com") if !strings.Contains(body, "zone-page
") { t.Fatalf("got %s", body) } if !strings.Contains(body, `data-id="domains" data-expanded="true"`) { t.Fatalf("got %s", body) } } func TestAppNavigationHeaderPrecedesTree(t *testing.T) { body := navBody(t, "/?item=domains") header := strings.Index(body, "folder-line") tree := strings.Index(body, ">Domains<") if header < 0 || tree < 0 || header > tree { t.Fatalf("header %d tree %d in %s", header, tree, body) } }