Render markdown and images in web UI

This commit is contained in:
2026-06-08 15:03:41 -05:00
parent fca1dd89f2
commit 66a8242980
6 changed files with 189 additions and 26 deletions
+59 -1
View File
@@ -1,6 +1,7 @@
package app
import (
"encoding/base64"
"net/http"
"net/http/httptest"
"os"
@@ -70,6 +71,41 @@ func TestWebReposAndLogin(t *testing.T) {
}
}
func addWebRenderFilesToRepo(t *testing.T, bare string) {
t.Helper()
work := filepath.Join(t.TempDir(), "render-work")
if err := runGit("", "clone", bare, work); err != nil {
t.Fatal(err)
}
if err := runGit(work, "checkout", "main"); err != nil {
t.Fatal(err)
}
for _, args := range [][]string{{"config", "user.name", "Test User"}, {"config", "user.email", "test@example.com"}} {
if err := runGit(work, args...); err != nil {
t.Fatal(err)
}
}
if err := os.WriteFile(filepath.Join(work, "docs.md"), []byte("# Rendered Title\n\nThis is **markdown**.\n"), 0644); err != nil {
t.Fatal(err)
}
png, err := base64.StdEncoding.DecodeString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+/p9sAAAAASUVORK5CYII=")
if err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(work, "logo.png"), png, 0644); err != nil {
t.Fatal(err)
}
if err := runGit(work, "add", "docs.md", "logo.png"); err != nil {
t.Fatal(err)
}
if err := runGit(work, "commit", "-m", "add render files"); err != nil {
t.Fatal(err)
}
if err := runGit(work, "push", "origin", "HEAD:main"); err != nil {
t.Fatal(err)
}
}
func TestWebRepoPagesCreateEditAndForkRules(t *testing.T) {
requireGitForApp(t)
s, mock, cleanup := newMockServer(t)
@@ -81,6 +117,7 @@ func TestWebRepoPagesCreateEditAndForkRules(t *testing.T) {
t.Fatal(err)
}
seedRepoWithFeatureBranch(t, bare)
addWebRenderFilesToRepo(t, bare)
expectLoadRepo(mock, "alice", "demo", repo)
rr := httptest.NewRecorder()
@@ -93,10 +130,31 @@ func TestWebRepoPagesCreateEditAndForkRules(t *testing.T) {
expectLoadRepo(mock, "alice", "demo", repo)
rr = httptest.NewRecorder()
s.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/alice/demo/blob?ref=main&path=README.md", nil))
if rr.Code != http.StatusOK || !strings.Contains(rr.Body.String(), "hello") {
if rr.Code != http.StatusOK || !strings.Contains(rr.Body.String(), "hello") || !strings.Contains(rr.Body.String(), `/alice/demo/tree?ref=main&path=`) {
t.Fatalf("blob page status=%d body=%s", rr.Code, rr.Body.String())
}
expectLoadRepo(mock, "alice", "demo", repo)
rr = httptest.NewRecorder()
s.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/alice/demo/blob?ref=main&path=docs.md", nil))
if rr.Code != http.StatusOK || !strings.Contains(rr.Body.String(), "<h1>Rendered Title</h1>") || strings.Contains(rr.Body.String(), "# Rendered Title") {
t.Fatalf("markdown page status=%d body=%s", rr.Code, rr.Body.String())
}
expectLoadRepo(mock, "alice", "demo", repo)
rr = httptest.NewRecorder()
s.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/alice/demo/blob?ref=main&path=logo.png", nil))
if rr.Code != http.StatusOK || !strings.Contains(rr.Body.String(), `<img src="/alice/demo/raw?`) || !strings.Contains(rr.Body.String(), "logo.png") {
t.Fatalf("image page status=%d body=%s", rr.Code, rr.Body.String())
}
expectLoadRepo(mock, "alice", "demo", repo)
rr = httptest.NewRecorder()
s.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/alice/demo/raw?ref=main&path=logo.png", nil))
if rr.Code != http.StatusOK || !strings.HasPrefix(rr.Header().Get("Content-Type"), "image/png") || len(rr.Body.Bytes()) == 0 {
t.Fatalf("raw image status=%d content-type=%q len=%d", rr.Code, rr.Header().Get("Content-Type"), rr.Body.Len())
}
expectBearerUser(mock, "tok", user)
mock.ExpectExec("INSERT INTO repositories").WithArgs(user.ID, "newrepo", "public", "new desc").WillReturnResult(sqlmock.NewResult(20, 1))
rr = httptest.NewRecorder()