293 lines
9.6 KiB
Go
293 lines
9.6 KiB
Go
package web
|
||
|
||
import (
|
||
"bytes"
|
||
"net/http"
|
||
"net/http/httptest"
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
func TestRoutes(t *testing.T) {
|
||
srv, err := NewServer()
|
||
if err != nil {
|
||
t.Fatalf("NewServer: %v", err)
|
||
}
|
||
|
||
t.Run("index", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
if !strings.Contains(rr.Body.String(), "UI Design Code") {
|
||
t.Fatalf("unexpected body: %s", rr.Body.String())
|
||
}
|
||
})
|
||
|
||
t.Run("healthz", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/healthz", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
})
|
||
|
||
t.Run("static", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/static/css/app.css", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
})
|
||
|
||
t.Run("table pattern page", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/table", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "Canonical List Page") {
|
||
t.Fatalf("missing table demo content in body")
|
||
}
|
||
if !strings.Contains(body, "Showing 1–10 of 36") {
|
||
t.Fatalf("missing summary: %s", body)
|
||
}
|
||
})
|
||
|
||
t.Run("controls pattern page", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/controls?segment=warning", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "Selection Table") {
|
||
t.Fatalf("missing controls page content")
|
||
}
|
||
})
|
||
|
||
t.Run("controls selection toggle persists in query links", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/controls?segment=all&selection_action=toggle&id=2", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "1 selected") {
|
||
t.Fatalf("expected selected counter, got body")
|
||
}
|
||
if !strings.Contains(body, "sel=2") {
|
||
t.Fatalf("expected selected id in follow-up links")
|
||
}
|
||
})
|
||
|
||
t.Run("controls select visible", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/controls?segment=warning&selection_action=select_visible", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "4 selected") {
|
||
t.Fatalf("expected all visible selected")
|
||
}
|
||
})
|
||
|
||
t.Run("modal pattern page", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/modals?open=edit&stage=confirm&sel=1", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "Confirmation Summary") || !strings.Contains(body, "Single-modal workflow progression") {
|
||
t.Fatalf("missing modal page markers")
|
||
}
|
||
})
|
||
|
||
t.Run("io pattern page", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/io?import_mode=confirm&export_ready=1", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "Import / Export Pattern") || !strings.Contains(body, "Download CSV") {
|
||
t.Fatalf("missing io page markers")
|
||
}
|
||
})
|
||
|
||
t.Run("forms pattern page", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/forms?mode=register&step=review", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "Forms") || !strings.Contains(body, "Validation Pattern") || !strings.Contains(body, "Review Summary") {
|
||
t.Fatalf("missing forms page markers")
|
||
}
|
||
if !strings.Contains(body, "Server serial is required") {
|
||
t.Fatalf("expected validation message")
|
||
}
|
||
})
|
||
|
||
t.Run("style playground pattern page", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/style-playground?style=slate", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "Style Playground") || !strings.Contains(body, "Theme Presets") {
|
||
t.Fatalf("missing style playground markers")
|
||
}
|
||
if !strings.Contains(body, "theme-slate") {
|
||
t.Fatalf("expected theme class in body")
|
||
}
|
||
})
|
||
|
||
t.Run("style playground extra presets", func(t *testing.T) {
|
||
for _, tc := range []struct {
|
||
name string
|
||
style string
|
||
expectMark string
|
||
}{
|
||
{name: "y2k silver", style: "y2k-silver", expectMark: "theme-y2k-silver"},
|
||
{name: "vaporwave alias", style: "vaporwave", expectMark: "theme-vaporwave"},
|
||
{name: "vaporwave soft", style: "vaporwave-soft", expectMark: "theme-vaporwave"},
|
||
{name: "vaporwave night", style: "vaporwave-night", expectMark: "theme-vaporwave-night"},
|
||
{name: "aqua", style: "aqua", expectMark: "theme-aqua"},
|
||
{name: "win9x", style: "win9x", expectMark: "theme-win9x"},
|
||
} {
|
||
t.Run(tc.name, func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/style-playground?style="+tc.style, nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, tc.expectMark) {
|
||
t.Fatalf("expected theme marker %q", tc.expectMark)
|
||
}
|
||
if !strings.Contains(body, "Y2K Silver") || !strings.Contains(body, "Vapor Soft") || !strings.Contains(body, "Vapor Night") || !strings.Contains(body, "Aqua") || !strings.Contains(body, "Win9x") {
|
||
t.Fatalf("expected preset tabs in switcher")
|
||
}
|
||
})
|
||
}
|
||
})
|
||
|
||
t.Run("operator tools pattern page", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/operator-tools?scope=components&queue=failed", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "Operator Tools Pattern") || !strings.Contains(body, "Operations Queue") {
|
||
t.Fatalf("missing operator tools page markers")
|
||
}
|
||
})
|
||
|
||
t.Run("timeline pattern page", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/timeline?open=c1", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "Timeline Cards Pattern") || !strings.Contains(body, "Open details") {
|
||
t.Fatalf("missing timeline page markers")
|
||
}
|
||
if !strings.Contains(body, "Event Detail") {
|
||
t.Fatalf("expected drilldown panel when card is open")
|
||
}
|
||
})
|
||
|
||
t.Run("io export csv endpoint", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/io/export.csv?scope=selected", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
if got := rr.Header().Get("Content-Type"); !strings.Contains(got, "text/csv") {
|
||
t.Fatalf("content-type=%q", got)
|
||
}
|
||
if got := rr.Header().Get("Content-Disposition"); !strings.Contains(got, "items.csv") {
|
||
t.Fatalf("content-disposition=%q", got)
|
||
}
|
||
body := rr.Body.Bytes()
|
||
if len(body) < 3 || !bytes.Equal(body[:3], []byte{0xEF, 0xBB, 0xBF}) {
|
||
t.Fatalf("missing UTF-8 BOM")
|
||
}
|
||
if !strings.Contains(string(body), "Code;Name;Category;Status;Qty") {
|
||
t.Fatalf("unexpected csv header")
|
||
}
|
||
})
|
||
|
||
t.Run("table pattern filters before pagination", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/table?q=Rack&page=99", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "Showing 1–3 of 3") {
|
||
t.Fatalf("expected filtered summary, got: %s", body)
|
||
}
|
||
if !strings.Contains(body, "Rack Controller Alpha") {
|
||
t.Fatalf("expected filtered rows")
|
||
}
|
||
if strings.Contains(body, "Component Spec 36") {
|
||
t.Fatalf("unexpected unrelated row present")
|
||
}
|
||
})
|
||
|
||
t.Run("table pattern keeps filter params in pager links", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/table?status=ready", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "status=ready") {
|
||
t.Fatalf("expected status filter in pagination links")
|
||
}
|
||
})
|
||
|
||
t.Run("table pattern empty result", func(t *testing.T) {
|
||
rr := httptest.NewRecorder()
|
||
req := httptest.NewRequest(http.MethodGet, "/patterns/table?q=does-not-exist", nil)
|
||
srv.Handler().ServeHTTP(rr, req)
|
||
if rr.Code != http.StatusOK {
|
||
t.Fatalf("status=%d", rr.Code)
|
||
}
|
||
body := rr.Body.String()
|
||
if !strings.Contains(body, "No rows match current filters.") {
|
||
t.Fatalf("expected empty-state message")
|
||
}
|
||
if !strings.Contains(body, "Showing 0 of 0") {
|
||
t.Fatalf("expected zero summary")
|
||
}
|
||
})
|
||
}
|