Go · 3983 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package web
4
5 import (
6 "bytes"
7 "html/template"
8 "io/fs"
9 "strings"
10 "testing"
11 "testing/fstest"
12
13 "github.com/tenseleyFlow/shithub/internal/web/render"
14 )
15
16 func TestNavRendersContextualRepoAndOrgHeaders(t *testing.T) {
17 t.Parallel()
18 navFS := fstest.MapFS{
19 "_layout.html": {Data: []byte(`{{ define "layout" }}{{ template "nav" . }}{{ template "page" . }}{{ end }}`)},
20 "page.html": {Data: []byte(`{{ define "page" }}page{{ end }}`)},
21 }
22 for _, name := range []string{"_nav.html", "_nav_offcanvas.html", "_repo_subnav.html", "_org_subnav.html"} {
23 body, err := fs.ReadFile(TemplatesFS(), name)
24 if err != nil {
25 t.Fatalf("read %s: %v", name, err)
26 }
27 navFS[name] = &fstest.MapFile{Data: body}
28 }
29 r, err := render.New(navFS, render.Options{
30 Octicons: func(name string) (template.HTML, bool) {
31 return template.HTML(`<svg data-icon="` + name + `"></svg>`), true //nolint:gosec // test-only constant markup
32 },
33 })
34 if err != nil {
35 t.Fatalf("render.New: %v", err)
36 }
37
38 cases := []struct {
39 name string
40 data map[string]any
41 want []string
42 wantNot []string
43 }{
44 {
45 name: "repo",
46 data: map[string]any{
47 "Viewer": map[string]any{"ID": int64(1), "Username": "mfwolffe"},
48 "CSRFToken": "token",
49 "Owner": "tenseleyFlow",
50 "Repo": map[string]any{"Name": "shithub", "Visibility": "public"},
51 "RepoCounts": map[string]any{"HasIssues": true, "Issues": 1, "Pulls": 2, "Forks": 0},
52 "ActiveSubnav": "code",
53 },
54 want: []string{
55 `class="shithub-nav has-context"`,
56 `data-offcanvas-open`,
57 `role="dialog" aria-modal="true" aria-label="Global navigation"`,
58 `aria-label="Repository"`,
59 `href="/tenseleyFlow/shithub" class="is-strong">shithub</a>`,
60 `href="/tenseleyFlow/shithub" class="shithub-offcanvas-repo-item"`,
61 `href="/tenseleyFlow/shithub/issues"`,
62 `Pull requests`,
63 },
64 wantNot: []string{`class="shithub-nav-links"`, `href="/about"`, `aria-label="Organization"`, `Copilot`, `MCP registry`, `href="/mcp"`},
65 },
66 {
67 name: "org",
68 data: map[string]any{
69 "Viewer": map[string]any{"ID": int64(1), "Username": "mfwolffe"},
70 "CSRFToken": "token",
71 "Org": map[string]any{"Slug": "tenseleyFlow"},
72 "RepoCount": 37,
73 "MemberCount": 2,
74 "IsOwner": true,
75 "ActiveOrgNav": "teams",
76 },
77 want: []string{
78 `class="shithub-nav has-context"`,
79 `data-offcanvas-open`,
80 `role="dialog" aria-modal="true" aria-label="Global navigation"`,
81 `aria-label="Organization"`,
82 `href="/tenseleyFlow" class="is-strong">tenseleyFlow</a>`,
83 `href="/orgs/tenseleyFlow/repositories" class="shithub-offcanvas-repo-item"`,
84 `href="/tenseleyFlow/teams"`,
85 `href="/tenseleyFlow/people"`,
86 },
87 wantNot: []string{`class="shithub-nav-links"`, `href="/about"`, `Copilot`, `MCP registry`, `href="/mcp"`},
88 },
89 {
90 name: "global",
91 data: map[string]any{
92 "Viewer": map[string]any{"ID": int64(1), "Username": "mfwolffe"},
93 "CSRFToken": "token",
94 },
95 want: []string{
96 `class="shithub-nav"`,
97 `data-offcanvas-open`,
98 `role="dialog" aria-modal="true" aria-label="Global navigation"`,
99 `All pull requests`,
100 `href="/explore"`,
101 `href="/about"`,
102 },
103 wantNot: []string{`shithub-nav-local`, `aria-label="Repository"`, `aria-label="Organization"`, `Copilot`, `MCP registry`, `href="/mcp"`},
104 },
105 }
106 for _, tc := range cases {
107 t.Run(tc.name, func(t *testing.T) {
108 t.Parallel()
109 var buf bytes.Buffer
110 if err := r.Render(&buf, "page", tc.data); err != nil {
111 t.Fatalf("Render: %v", err)
112 }
113 html := buf.String()
114 for _, want := range tc.want {
115 if !strings.Contains(html, want) {
116 t.Errorf("rendered nav missing %q in:\n%s", want, html)
117 }
118 }
119 for _, unwanted := range tc.wantNot {
120 if strings.Contains(html, unwanted) {
121 t.Errorf("rendered nav unexpectedly contained %q in:\n%s", unwanted, html)
122 }
123 }
124 })
125 }
126 }
127