mirror of
https://github.com/alireza0/x-ui.git
synced 2026-10-20 18:51:33 +00:00
136 lines
3.9 KiB
Go
136 lines
3.9 KiB
Go
package web
|
|
|
|
import (
|
|
"encoding/json"
|
|
"html/template"
|
|
"io/fs"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Every page is assembled from the embedded templates at startup, and a parse
|
|
// error there is swallowed so the panel only fails once a request comes in.
|
|
// Parsing them here turns a broken template into a failing build instead.
|
|
func TestEmbeddedHtmlTemplatesParse(t *testing.T) {
|
|
funcMap := template.FuncMap{
|
|
"i18n": func(key string, args ...interface{}) (template.HTML, error) { return "", nil },
|
|
}
|
|
|
|
parsed := 0
|
|
err := fs.WalkDir(htmlFS, "html", func(path string, entry fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if entry.IsDir() {
|
|
return nil
|
|
}
|
|
if !strings.HasSuffix(path, ".html") {
|
|
return nil
|
|
}
|
|
if _, err := template.New("").Funcs(funcMap).ParseFS(htmlFS, path); err != nil {
|
|
t.Errorf("%s: %v", path, err)
|
|
return nil
|
|
}
|
|
parsed++
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("walk templates: %v", err)
|
|
}
|
|
if parsed == 0 {
|
|
t.Fatal("no templates were parsed; the embedded FS looks empty")
|
|
}
|
|
}
|
|
|
|
// getHtmlTemplate skips directories that hold no templates, so it must still
|
|
// end up with the whole set defined.
|
|
func TestGetHtmlTemplateDefinesEveryPage(t *testing.T) {
|
|
server := NewServer()
|
|
funcMap := template.FuncMap{
|
|
"i18n": func(key string, args ...interface{}) (template.HTML, error) { return "", nil },
|
|
}
|
|
|
|
parsed, err := server.getHtmlTemplate(funcMap)
|
|
if err != nil {
|
|
t.Fatalf("getHtmlTemplate: %v", err)
|
|
}
|
|
|
|
for _, name := range []string{"inbounds.html", "api_docs.html", "clientsBulkModal", "clientsModal", "qrcodeModal"} {
|
|
if parsed.Lookup(name) == nil {
|
|
t.Errorf("template %q was not defined", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The OpenAPI document is embedded at build time and read once at startup, so a
|
|
// wrong path would only show up as a panic on a real server.
|
|
func TestOpenAPIDocumentIsEmbedded(t *testing.T) {
|
|
embedded, err := openAPIFS.ReadFile("api/openapi.json")
|
|
if err != nil {
|
|
t.Fatalf("the API description is not in the binary: %v", err)
|
|
}
|
|
if len(embedded) == 0 {
|
|
t.Fatal("the embedded API description is empty")
|
|
}
|
|
|
|
var document map[string]interface{}
|
|
if err := json.Unmarshal(embedded, &document); err != nil {
|
|
t.Fatalf("the embedded API description is not valid JSON: %v", err)
|
|
}
|
|
if _, ok := document["paths"]; !ok {
|
|
t.Fatal("the embedded API description has no paths")
|
|
}
|
|
|
|
onDisk, err := os.ReadFile("api/openapi.json")
|
|
if err != nil {
|
|
t.Fatalf("read the file on disk: %v", err)
|
|
}
|
|
if string(onDisk) != string(embedded) {
|
|
t.Fatal("the embedded description differs from the file on disk")
|
|
}
|
|
}
|
|
|
|
// The dark theme styles ant-design components and h2, but nothing else, so a
|
|
// bare <h1>, <h3>, <h4>… keeps the light theme's near-black colour and turns
|
|
// invisible on the dark background. Card titles and list-item metas are the
|
|
// panel's styled alternatives.
|
|
func TestPagesAvoidUnstyledHeadings(t *testing.T) {
|
|
darkThemeStyles, err := fs.ReadFile(assetsFS, "assets/css/custom.css")
|
|
if err != nil {
|
|
t.Fatalf("read the theme stylesheet: %v", err)
|
|
}
|
|
|
|
unstyled := []string{}
|
|
for _, tag := range []string{"h1", "h3", "h4", "h5", "h6"} {
|
|
if !strings.Contains(string(darkThemeStyles), ".dark "+tag) {
|
|
unstyled = append(unstyled, tag)
|
|
}
|
|
}
|
|
if len(unstyled) == 0 {
|
|
t.Skip("the dark theme now styles every heading level")
|
|
}
|
|
|
|
err = fs.WalkDir(htmlFS, "html", func(path string, entry fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if entry.IsDir() || !strings.HasSuffix(path, ".html") {
|
|
return nil
|
|
}
|
|
raw, err := fs.ReadFile(htmlFS, path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, tag := range unstyled {
|
|
if strings.Contains(string(raw), "<"+tag+">") || strings.Contains(string(raw), "<"+tag+" ") {
|
|
t.Errorf("%s uses a bare <%s>, which the dark theme leaves near-black; "+
|
|
"use a card title slot or a-list-item-meta instead", path, tag)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("walk templates: %v", err)
|
|
}
|
|
}
|