package main import ( "html/template" "os" "strings" "testing" ) func TestInnerCodeTemplate_独立导航与安全表单(t *testing.T) { if _, err := template.ParseFS(templateFS, "templates/*/*.html"); err != nil { t.Fatalf("模板必须可解析: %v", err) } header, err := os.ReadFile("templates/partials/header.html") if err != nil { t.Fatal(err) } headerText := string(header) clientIndex := strings.Index(headerText, `href="/clients"`) innerCodeIndex := strings.Index(headerText, `href="/inner-codes"`) if clientIndex < 0 || innerCodeIndex < 0 || innerCodeIndex < clientIndex { t.Fatal("档口入库码导航必须紧跟在客户端列表之后") } raw, err := os.ReadFile("templates/inner_code/list.html") if err != nil { t.Fatal(err) } page := string(raw) for _, want := range []string{ `action="/inner-codes/import"`, `action="/inner-codes/match"`, `action="/inner-codes/apply"`, `action="/inner-codes/recheck"`, `action="/inner-codes/delete"`, `name="csrf_token"`, `data-check-all`, `data-inner-code-apply-open`, `data-need-checked="inner-code-match"`, `data-inner-code-id="{{.ID}}"`, `data-need-checked="inner-code-delete"`, `data-confirm-delete-action="inner-code-delete"`, `inner-code-delete {{if .CanMatch}}inner-code-match{{end}}{{if .CanApply}} inner-code-apply`, `删除不会撤销顺运宝已写入的快递单号`, `匹配已选`, `aria-label="档口入库码记录列表"`, } { if !strings.Contains(page, want) { t.Errorf("正式页面缺少 %s", want) } } if strings.Contains(page, `{{if not .CanMatch}}disabled{{end}}`) { t.Fatal("所有状态都应允许勾选删除,不能再按 CanMatch 禁用复选框") } } func TestInnerCodeTemplate_模块状态白名单已登记(t *testing.T) { raw, err := os.ReadFile("static/js/app.js") if err != nil { t.Fatal(err) } if !strings.Contains(string(raw), `"/inner-codes": ["date", "status", "q", "page", "page_size"]`) { t.Fatal("档口入库码页面切换模块后应保持稳定筛选和页码") } for _, want := range []string{ `appendSelectedIDs(matchForm, "inner-code-match")`, `appendSelectedIDs(applyForm, "inner-code-apply")`, `appendSelectedIDs(deleteForm, "inner-code-delete")`, `checkedCount(action)`, `field.name = "ids"`, } { if !strings.Contains(string(raw), want) { t.Errorf("档口入库码选中 ID 提交缺少 %s", want) } } } func TestInnerCodeTemplate_筛选顺序与紧凑宽度(t *testing.T) { raw, err := os.ReadFile("templates/inner_code/list.html") if err != nil { t.Fatal(err) } page := string(raw) parts := []string{ `id="inner-code-status"`, `id="inner-code-date" type="date" name="date"`, `id="inner-code-keyword"`, `class="button-link" href="/inner-codes?date={{.BusinessDate}}&page_size={{.CurrentPageSize}}">清除`, ``, } lastIndex := -1 for _, part := range parts { index := strings.Index(page, part) if index < 0 { t.Fatalf("筛选工具栏缺少 %s", part) } if index <= lastIndex { t.Fatalf("筛选工具栏顺序不正确,%s 没有位于上一控件之后", part) } lastIndex = index } filterStart := strings.Index(page, `
`) if filterEnd < 0 { t.Fatal("没有找到完整的档口入库码筛选表单") } filter := page[filterStart : filterStart+filterEnd] if strings.Contains(filter, `type="hidden" name="date"`) { t.Fatal("筛选表单应直接提交可见业务日期,不能继续保留重复隐藏字段") } css, err := os.ReadFile("static/css/app.css") if err != nil { t.Fatal(err) } styles := string(css) for _, want := range []string{ `.inner-code-toolbar input[type="text"].inner-code-search`, `flex: 0 0 150px`, `width: 150px`, `min-width: 150px`, `.inner-code-toolbar .inner-code-filter-form { flex-wrap: wrap; }`, `.inner-code-toolbar .inner-code-filter-form { flex-basis: 100%; }`, } { if !strings.Contains(styles, want) { t.Errorf("筛选工具栏样式缺少 %s", want) } } }