- 集成 tauri-plugin-opener:Cargo/lib.rs/capabilities/npm 四处接线,新增 src/openExternal.ts(桌面走 opener,浏览器回退 window.open,相对路径绝对化) - 关于页 4 个链接、活动栏官网菜单、代理错误横幅 2 处健康检查链接全部改走 openExternal,桌面端可正常跳转 - 设置→外观 主题顺序调整为 深色/浅色/跟随系统 - release 二进制重编并验证(浏览器实测关于页链接可开文档页) - 附带工作区中未提交的扁平化重构现状(另一会话进行中) - homepage 落地页与文档终检通过(8787 / 与 /docs 双 200)
123 lines
3.3 KiB
Go
123 lines
3.3 KiB
Go
package docs
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func newTestRouter(t *testing.T) *gin.Engine {
|
|
t.Helper()
|
|
gin.SetMode(gin.TestMode)
|
|
r := gin.New()
|
|
New().Register(r)
|
|
return r
|
|
}
|
|
|
|
func TestDocsIndexRedirect(t *testing.T) {
|
|
r := newTestRouter(t)
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/docs", nil))
|
|
if w.Code != http.StatusFound {
|
|
t.Fatalf("expect 302, got %d", w.Code)
|
|
}
|
|
if !strings.HasPrefix(w.Header().Get("Location"), "/docs/") {
|
|
t.Fatalf("bad redirect: %s", w.Header().Get("Location"))
|
|
}
|
|
}
|
|
|
|
func TestDocsAllPagesRender(t *testing.T) {
|
|
h := New()
|
|
r := newTestRouter(t)
|
|
for _, slug := range h.order {
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/docs/"+slug, nil)
|
|
r.ServeHTTP(w, req)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("page %s: expect 200, got %d", slug, w.Code)
|
|
}
|
|
body := w.Body.String()
|
|
if !strings.Contains(body, "<title>") || !strings.Contains(body, `class="md"`) {
|
|
t.Fatalf("page %s: html structure incomplete", slug)
|
|
}
|
|
// 正文有渲染出的标题与段落
|
|
if !strings.Contains(body, "<h1") {
|
|
t.Fatalf("page %s: missing h1", slug)
|
|
}
|
|
// 侧栏包含全部分组
|
|
for _, g := range h.manifest.Groups {
|
|
if !strings.Contains(body, g.Name) {
|
|
t.Fatalf("page %s: sidebar missing group %s", slug, g.Name)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDocsPageContainsTOCAndNav(t *testing.T) {
|
|
r := newTestRouter(t)
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/docs/http", nil))
|
|
body := w.Body.String()
|
|
if !strings.Contains(body, "sec-1") {
|
|
t.Fatal("expect heading anchors")
|
|
}
|
|
if !strings.Contains(body, "上一页") {
|
|
t.Fatal("expect prev link")
|
|
}
|
|
}
|
|
|
|
func TestDocsSearchData(t *testing.T) {
|
|
r := newTestRouter(t)
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/docs/search-data.json", nil))
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("expect 200, got %d", w.Code)
|
|
}
|
|
var entries []SearchEntry
|
|
if err := json.Unmarshal(w.Body.Bytes(), &entries); err != nil {
|
|
t.Fatalf("invalid json: %v", err)
|
|
}
|
|
if len(entries) < 10 {
|
|
t.Fatalf("expect >= 10 search entries, got %d", len(entries))
|
|
}
|
|
// MQTT 页应可被检索(标题或正文命中)
|
|
found := false
|
|
for _, e := range entries {
|
|
if e.Slug == "mqtt" && (e.Title == "MQTT" || strings.Contains(e.Text, "MQTT")) {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatal("mqtt entry missing searchable text")
|
|
}
|
|
}
|
|
|
|
func TestDocsAssetsAnd404(t *testing.T) {
|
|
r := newTestRouter(t)
|
|
|
|
w := httptest.NewRecorder()
|
|
r.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/docs/assets/docs.css", nil))
|
|
if w.Code != http.StatusOK || !strings.Contains(w.Header().Get("Content-Type"), "text/css") {
|
|
t.Fatalf("css asset: %d %s", w.Code, w.Header().Get("Content-Type"))
|
|
}
|
|
|
|
w = httptest.NewRecorder()
|
|
r.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/docs/assets/docs.js", nil))
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("js asset: %d", w.Code)
|
|
}
|
|
|
|
w = httptest.NewRecorder()
|
|
r.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/docs/not-exist-page", nil))
|
|
if w.Code != http.StatusNotFound {
|
|
t.Fatalf("404 page: %d", w.Code)
|
|
}
|
|
if !strings.Contains(w.Body.String(), "返回文档首页") {
|
|
t.Fatal("404 page missing home link")
|
|
}
|
|
}
|