- 地图脚本:localStorage 读写走 lsGet/lsSet 兜底(隐私模式下裸访问会打断整段脚本); preview() 在 /api/map-config 还没回来时不丢点(previewQueue 在 if (live) 之前排队); 异步回包一律发序号作废,取消后回来的包不再画 - photo-exif.js:EXIF 时间全 0 不再变成 1899-11-30 写进到访时间;读 count 前先按版本卡宽度 - 数据编辑页:三个筛选表单都把其余条件用隐藏域原样带上,提交不再把别的列表的筛选清掉 - 补全页:sessionStorage 的读写一律包 try(脏数据/隐私模式都会抛) - 窄屏:删掉被后面同特异性规则盖掉的死内边距;宽表堆叠类名成对、判据扩到所有 tb 表 - 无障碍:图片删除按钮补 aria-label,访客画廊图片补 alt - report.html 补上漏掉的 </tr>,fog-mask 的宽表带 tb-stack 本批不碰数据库与导出路径:往返包 823/323/8/30/791/557/2246 全等、 坐标偏差 0.000000000、时间偏差 0s、迷雾 8701 块一致。
68 lines
2.5 KiB
Go
68 lines
2.5 KiB
Go
package web
|
||
|
||
import (
|
||
"bytes"
|
||
"html/template"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
// TestPageTemplatesParse 把每个页面模板都解析一遍。
|
||
// 模板是启动时编译的(见 New),语法错会让整个服务起不来;
|
||
// 这个测试把它提前到 go test 阶段,不用真起一次服务才发现。
|
||
func TestPageTemplatesParse(t *testing.T) {
|
||
for key, def := range pageFiles {
|
||
if _, err := template.New(filepath.Base(def.files[0])).Funcs(templateFuncs()).
|
||
ParseFS(tmplFS, def.files...); err != nil {
|
||
t.Errorf("解析模板 %s 失败: %v", key, err)
|
||
}
|
||
}
|
||
}
|
||
|
||
// TestLayoutFooterToleratesMissingLastVisit 钉住页脚在「数据集一条到访都没有」时也渲染得完。
|
||
//
|
||
// last_visit_at 可以为 NULL(refreshDatasetAgg 用 LEFT JOIN 求 max,零到访就写 NULL),
|
||
// 而 d 的形参是 time.Time、实参是 *time.Time:非 nil 时模板会自动解一层指针,**nil 时报
|
||
// "dereference of nil pointer" 并中断渲染**。render() 只把错误记进日志,客户端拿到的是
|
||
// HTTP 200 加一个「页脚之后整段不存在」的页面——滚动恢复、地图脚本引入全丢,
|
||
// 服务端一点动静都没有。所以这里断言「有收尾的 </html>」,而不只是断言没报错。
|
||
func TestLayoutFooterToleratesMissingLastVisit(t *testing.T) {
|
||
base, err := template.New("layout.html").Funcs(templateFuncs()).ParseFS(tmplFS, "templates/layout.html")
|
||
if err != nil {
|
||
t.Fatalf("解析 layout.html: %v", err)
|
||
}
|
||
tpl, err := base.Parse(`{{define "content"}}正文{{end}}`)
|
||
if err != nil {
|
||
t.Fatalf("补 content 块: %v", err)
|
||
}
|
||
last := time.Date(2026, 9, 21, 12, 0, 0, 0, time.Local)
|
||
cases := []struct {
|
||
name string
|
||
ds *Dataset
|
||
want string
|
||
}{
|
||
{"没有数据集", nil, ""},
|
||
{"数据集里一条到访都没有", &Dataset{Name: "空数据集"}, ""},
|
||
{"正常", &Dataset{Name: "有数据", Last: &last}, "数据截至 2026-09-21"},
|
||
}
|
||
for _, c := range cases {
|
||
var buf bytes.Buffer
|
||
if err := tpl.ExecuteTemplate(&buf, "layout", Page{Nav: "home", Title: "测", Dataset: c.ds}); err != nil {
|
||
t.Fatalf("%s: 渲染失败: %v", c.name, err)
|
||
}
|
||
got := buf.String()
|
||
if !strings.Contains(got, "</html>") {
|
||
t.Errorf("%s: 页面被截断(没有收尾的 </html>)", c.name)
|
||
}
|
||
if c.want == "" {
|
||
if strings.Contains(got, "数据截至") {
|
||
t.Errorf("%s: 没有可信的截止时间时不该渲染「数据截至」", c.name)
|
||
}
|
||
} else if !strings.Contains(got, c.want) {
|
||
t.Errorf("%s: 页脚应含 %q", c.name, c.want)
|
||
}
|
||
}
|
||
}
|