chore(qa): 验收台账与证据入库 + 构建/部署配置同步
- docs/acceptance/qa-tracker.md:跨周期缺陷单一真源台账(§7=第五轮)。 - 周期 1/2 + iPhone SE/axe 验收证据目录、ACCEPTANCE_REVIEW 快照入库。 - 同步 README/CONTEXT/CLAUDE/DESIGN/testing/deployment/lessons-learned 口径; next.config/Dockerfile/nginx/Jenkinsfile/docker-compose/sentry/prisma 对齐 standalone 产物装配与部署形态。
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
# 第七轮(死断言处理后的复验):
|
||||
# A. axe harness 扩到「tag 通道 + 规则级通道」——先 2 路由 sanity,再全站 34 路由 × 4 组合
|
||||
# B. Lighthouse 去掉 3 条死断言后重跑,证明 EXIT=0 且 0 warning
|
||||
set -u
|
||||
cd /Users/zhangxiang/Codes/Novalon/novalon-website || exit 1
|
||||
LOG=/tmp/final-chain7.log
|
||||
HARNESS=docs/acceptance/2026-09-21-axe/axe-contrast-evidence.mjs
|
||||
CRAWLER=docs/acceptance/2026-09-21-axe/crawl-sitemap.mjs
|
||||
PORTS() { lsof -nP -iTCP:3000 -iTCP:3100 -sTCP:LISTEN 2>/dev/null | grep -c LISTEN; }
|
||||
echo "=== chain7 started $(date -u +%FT%TZ) ===" > "$LOG"
|
||||
echo "PREFLIGHT_LISTENERS=$(PORTS) $(date -u +%FT%TZ)" >> "$LOG"
|
||||
|
||||
npx next start -p 3100 > /tmp/axe-server8.log 2>&1 &
|
||||
SRV=$!
|
||||
code=000
|
||||
for i in $(seq 1 40); do
|
||||
code=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:3100/ 2>/dev/null || true)
|
||||
[ "$code" = "200" ] && break
|
||||
sleep 3
|
||||
done
|
||||
echo "AXE_SERVER_UP=$code $(date -u +%FT%TZ)" >> "$LOG"
|
||||
|
||||
# 全站清单(口径与 chain6 相同:sitemap ∪ 预渲染产物 ∪ 站内链接 BFS)
|
||||
BASE=http://localhost:3100 SEED=/tmp/axe-sitemap2.xml \
|
||||
MANIFEST=dist/standalone/dist/server/app OUT=/tmp/axe-sitemap-all5.xml \
|
||||
node --input-type=module -e "$(cat $CRAWLER)" > /tmp/crawl6.log 2>&1
|
||||
echo "EXIT_CRAWL=$? $(date -u +%FT%TZ)" >> "$LOG"
|
||||
grep -a "^crawled" /tmp/crawl6.log >> "$LOG"
|
||||
|
||||
# sanity:只用 2 条路由跑新代码路径,避免 14 分钟后才发现探针本身有 bug
|
||||
python3 - <<'PY'
|
||||
import re
|
||||
src = open('/tmp/axe-sitemap-all5.xml', encoding='utf8').read()
|
||||
blocks = re.findall(r'<url>.*?</url>', src, re.S)
|
||||
open('/tmp/axe-sitemap-sanity.xml', 'w', encoding='utf8').write(
|
||||
'<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
|
||||
+ "\n".join(blocks[:2]) + "\n</urlset>\n")
|
||||
print('sanity urls:', len(blocks[:2]))
|
||||
PY
|
||||
echo "EXIT_SANITY_CROP=$?" >> "$LOG"
|
||||
SITEMAP=/tmp/axe-sitemap-sanity.xml BASE=http://localhost:3100 OUT=/tmp/axe-sanity-out \
|
||||
node --input-type=module -e "$(cat $HARNESS)" > /tmp/axe-sanity.log 2>&1
|
||||
echo "EXIT_SANITY=$? $(date -u +%FT%TZ)" >> "$LOG"
|
||||
sed -e 's/\x1b\[[0-9;]*m//g' /tmp/axe-sanity.log | grep -aE "^(chromium|firefox)/|^PASSED|^SUMMARY|FATAL|Error" | head -14 >> "$LOG"
|
||||
|
||||
# 保留 chain6 证据,再产出最终树的新证据
|
||||
cp docs/acceptance/2026-09-21-axe/axe-evidence.json \
|
||||
docs/acceptance/2026-09-21-axe/axe-evidence-chain6-tagonly.json 2>/dev/null
|
||||
SITEMAP=/tmp/axe-sitemap-all5.xml BASE=http://localhost:3100 \
|
||||
OUT=docs/acceptance/2026-09-21-axe \
|
||||
node --input-type=module -e "$(cat $HARNESS)" > /tmp/axe-sweep8.log 2>&1
|
||||
echo "EXIT_AXE_FULL=$? $(date -u +%FT%TZ)" >> "$LOG"
|
||||
node -e "const j=require('./docs/acceptance/2026-09-21-axe/axe-evidence.json');console.log('AXE routeCount='+j.routeCount+' rows='+j.rows.length+' passed='+j.passed+' extraRules='+JSON.stringify(j.extraRules)+' summary='+JSON.stringify(j.summary))" >> "$LOG" 2>&1
|
||||
|
||||
kill "$SRV" 2>/dev/null
|
||||
pkill -f 'next start -p 3100' 2>/dev/null
|
||||
sleep 3
|
||||
echo "POST_AXE_LISTENERS=$(PORTS)" >> "$LOG"
|
||||
|
||||
{
|
||||
echo
|
||||
echo "===== chain7 lighthouse(移除 3 条死断言后)$(date -u +%FT%TZ) ====="
|
||||
npm run lighthouse 2>&1
|
||||
} | sed -e 's/\x1b\[[0-9;]*m//g' >> docs/acceptance/2026-09-21-gates/lighthouse.txt 2>&1
|
||||
echo "EXIT_LIGHTHOUSE=${PIPESTATUS[0]} $(date -u +%FT%TZ)" >> "$LOG"
|
||||
# 只统计本轮(chain7 段)残留的死断言,历史段保留作对照
|
||||
awk '/chain7 lighthouse/{f=1} f' docs/acceptance/2026-09-21-gates/lighthouse.txt \
|
||||
| grep -ac "not a known audit" | sed 's/^/CHAIN7_DEAD_AUDIT_WARNINGS=/' >> "$LOG"
|
||||
sleep 3
|
||||
echo "POST_FINAL_LISTENERS=$(PORTS)" >> "$LOG"
|
||||
echo "=== chain7 done $(date -u +%FT%TZ) ===" >> "$LOG"
|
||||
@@ -0,0 +1,60 @@
|
||||
#!/bin/bash
|
||||
# 第八轮(补 chain6/7 未覆盖的两项证据):
|
||||
# A. npm run test:coverage —— A-7 阈值棘轮在最终树上是否仍成立
|
||||
# B. iPhone SE 口径复跑(含新增的 404 边界页),证据写入新目录,不覆盖 09-21 的旧证据
|
||||
set -u
|
||||
cd /Users/zhangxiang/Codes/Novalon/novalon-website || exit 1
|
||||
LOG=/tmp/final-chain8.log
|
||||
SE_OUT=docs/acceptance/2026-09-22-iphone-se
|
||||
PORTS() { lsof -nP -iTCP:3000 -iTCP:3100 -sTCP:LISTEN 2>/dev/null | grep -c LISTEN; }
|
||||
echo "=== chain8 started $(date -u +%FT%TZ) ===" > "$LOG"
|
||||
while ! grep -q "chain7 done" /tmp/final-chain7.log 2>/dev/null; do sleep 20; done
|
||||
echo "CHAIN7_TAIL: $(grep -aE 'EXIT_AXE_FULL|AXE routeCount|EXIT_LIGHTHOUSE|CHAIN7_DEAD|^crawled|EXIT_SANITY' /tmp/final-chain7.log | tr '\n' '|')" >> "$LOG"
|
||||
echo "PREFLIGHT_LISTENERS=$(PORTS) $(date -u +%FT%TZ)" >> "$LOG"
|
||||
|
||||
npm run test:coverage > /tmp/coverage-final8.log 2>&1
|
||||
echo "EXIT_COVERAGE=$? $(date -u +%FT%TZ)" >> "$LOG"
|
||||
{
|
||||
echo "# test:coverage 最终树复跑 $(date -u +%FT%TZ)"
|
||||
sed -e 's/\x1b\[[0-9;]*m//g' /tmp/coverage-final8.log | grep -aE "All files|Jest:|Tests:|Test Suites:|threshold|% (Stmts|Branch)" | head -20
|
||||
} > docs/acceptance/2026-09-21-gates/coverage-final-tree.txt 2>&1
|
||||
sleep 2
|
||||
echo "POST_COVERAGE_LISTENERS=$(PORTS)" >> "$LOG"
|
||||
|
||||
mkdir -p "$SE_OUT"
|
||||
npx next start -p 3000 > /tmp/se-server.log 2>&1 &
|
||||
SRV=$!
|
||||
code=000
|
||||
for i in $(seq 1 40); do
|
||||
code=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:3000/ 2>/dev/null || true)
|
||||
[ "$code" = "200" ] && break
|
||||
sleep 3
|
||||
done
|
||||
echo "SE_SERVER_UP=$code $(date -u +%FT%TZ)" >> "$LOG"
|
||||
|
||||
BASE=http://localhost:3000 OUT="$SE_OUT" \
|
||||
node --input-type=module -e "$(cat docs/acceptance/2026-09-21-iphone-se/iphone-se-audit.mjs)" \
|
||||
> "$SE_OUT/audit.log" 2>&1
|
||||
echo "EXIT_SE_AUDIT=$? $(date -u +%FT%TZ)" >> "$LOG"
|
||||
|
||||
kill "$SRV" 2>/dev/null
|
||||
pkill -f 'next start -p 3000' 2>/dev/null
|
||||
sleep 3
|
||||
node -e '
|
||||
const j = require("./'"$SE_OUT"'/measurements.json");
|
||||
const pending = j.rows.filter((r) => /pending/.test(r.tag));
|
||||
const overlap = pending.filter((r) => r.bannerOverlapsFooter);
|
||||
const nf = j.rows.filter((r) => /not-found/.test(r.tag));
|
||||
const bad = j.rows.filter((r) => r.docScrollW > r.clientW || r.theme === null);
|
||||
console.log("SE rows=" + j.rows.length
|
||||
+ " overflow=" + j.rows.filter((r) => r.docScrollW > r.clientW).length
|
||||
+ " themeNull=" + j.rows.filter((r) => r.theme === null).length
|
||||
+ " pendingRows=" + pending.length
|
||||
+ " pendingBannerOverlapFooter=" + overlap.length
|
||||
+ " notFoundRows=" + nf.length
|
||||
+ " notFoundGaps=" + JSON.stringify(nf.map((r) => r.footerBottomGap))
|
||||
+ " footerGaps=" + JSON.stringify([...new Set(j.rows.map((r) => r.footerBottomGap))]));
|
||||
console.log("SE PASSED =", j.rows.length === 20 && bad.length === 0);
|
||||
' >> "$LOG" 2>&1
|
||||
echo "POST_FINAL_LISTENERS=$(PORTS)" >> "$LOG"
|
||||
echo "=== chain8 done $(date -u +%FT%TZ) ===" >> "$LOG"
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# 第九轮(把 §7 覆盖缺口的 Lighthouse 半边补上后复跑):
|
||||
# lighthouserc 的 collect.url 由 7 条扩到 9 条(补 /products/erp-upgrade、/about/brand),
|
||||
# 同时重跑静态门禁,确认本轮改 config/docs/probe 未触碰 src 行为。
|
||||
set -u
|
||||
cd /Users/zhangxiang/Codes/Novalon/novalon-website || exit 1
|
||||
LOG=/tmp/final-chain9.log
|
||||
PORTS() { lsof -nP -iTCP:3000 -iTCP:3100 -sTCP:LISTEN 2>/dev/null | grep -c LISTEN; }
|
||||
echo "=== chain9 started $(date -u +%FT%TZ) ===" > "$LOG"
|
||||
while ! grep -q "chain8 done" /tmp/final-chain8.log 2>/dev/null; do sleep 20; done
|
||||
echo "CHAIN8_TAIL: $(grep -aE 'EXIT_COVERAGE|SE PASSED|SE rows|EXIT_SE_AUDIT' /tmp/final-chain8.log | tr '\n' '|')" >> "$LOG"
|
||||
echo "PREFLIGHT_LISTENERS=$(PORTS) $(date -u +%FT%TZ)" >> "$LOG"
|
||||
|
||||
for g in type-check lint test:unit check:contrast check:headings check:brand-token; do
|
||||
npm run "$g" > "/tmp/c9-$(echo "$g" | tr ':' '-').log" 2>&1
|
||||
echo "EXIT_$(echo "$g" | tr 'a-z-' 'A-Z')=$? $(date -u +%FT%TZ)" >> "$LOG"
|
||||
done
|
||||
sed -e 's/\x1b\[[0-9;]*m//g' /tmp/c9-lint.log | grep -a "problems" | tail -1 >> "$LOG"
|
||||
sleep 2
|
||||
echo "POST_STATIC_LISTENERS=$(PORTS)" >> "$LOG"
|
||||
|
||||
URLS=$(node -e 'const c=require("./config/test/lighthouserc.json");console.log(c.ci.collect.url.length)' 2>/dev/null)
|
||||
echo "LIGHTHOUSE_URLS=$URLS" >> "$LOG"
|
||||
{
|
||||
echo
|
||||
echo "===== chain9 lighthouse(9 URL × 3 次 = 27 运行,补 erp-upgrade / about-brand)$(date -u +%FT%TZ) ====="
|
||||
npm run lighthouse 2>&1
|
||||
} | sed -e 's/\x1b\[[0-9;]*m//g' >> docs/acceptance/2026-09-21-gates/lighthouse.txt 2>&1
|
||||
echo "EXIT_LIGHTHOUSE=${PIPESTATUS[0]} $(date -u +%FT%TZ)" >> "$LOG"
|
||||
awk '/chain9 lighthouse/{f=1} f' docs/acceptance/2026-09-21-gates/lighthouse.txt \
|
||||
| grep -ac "not a known audit" | sed 's/^/CHAIN9_DEAD_AUDIT_WARNINGS=/' >> "$LOG"
|
||||
awk '/chain9 lighthouse/{f=1} f' docs/acceptance/2026-09-21-gates/lighthouse.txt \
|
||||
| grep -aE "✗|✓ \[" | tail -12 >> "$LOG"
|
||||
sleep 3
|
||||
echo "POST_FINAL_LISTENERS=$(PORTS)" >> "$LOG"
|
||||
echo "=== chain9 done $(date -u +%FT%TZ) ===" >> "$LOG"
|
||||
@@ -0,0 +1,404 @@
|
||||
# check:contrast 与 check:headings —— 空闲机器复跑(无并发 E2E/Lighthouse)
|
||||
# 生成于 2026-09-21T21:51:32Z
|
||||
|
||||
## npm run check:contrast
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 check:contrast
|
||||
> tsx scripts/utils/check-color-contrast.ts
|
||||
|
||||
|
||||
🎨 LIGHT 主题(:root,246 个令牌)
|
||||
正文层级 × 页面底色
|
||||
✅ --color-text-primary on --color-bg-primary — 19.34:1
|
||||
✅ --color-text-primary on --color-bg-secondary — 18.48:1
|
||||
✅ --color-text-primary on --color-bg-tertiary — 17.65:1
|
||||
✅ --color-text-secondary on --color-bg-primary — 10.35:1
|
||||
✅ --color-text-secondary on --color-bg-secondary — 9.90:1
|
||||
✅ --color-text-tertiary on --color-bg-primary — 7.58:1
|
||||
✅ --color-text-muted on --color-bg-primary — 4.76:1
|
||||
品牌红文字通道(text-brand-ink 及 hover 档)
|
||||
✅ --color-brand-ink on --color-bg-primary — 5.84:1
|
||||
✅ --color-brand-ink on --color-bg-secondary — 5.58:1
|
||||
✅ --color-brand-ink on --color-brand-bg — 5.35:1
|
||||
✅ --color-brand-ink-hover on --color-bg-primary — 7.87:1
|
||||
✅ --color-brand-ink-hover on --color-brand-bg — 7.20:1
|
||||
✅ #FFFFFF on --color-brand — 5.84:1
|
||||
alpha 修饰正文(带 /80 等修饰类的正文)
|
||||
✅ --color-text-secondary on --color-bg-primary @80% — 5.74:1
|
||||
大号装饰文本(text-text-hint)× 各级卡片底色
|
||||
✅ --color-text-hint on --color-bg-primary — 3.41:1
|
||||
✅ --color-text-hint on --color-bg-secondary — 3.26:1
|
||||
✅ --color-text-hint on --color-bg-tertiary — 3.12:1
|
||||
✅ --color-text-hint on --color-bg-elevated — 3.41:1
|
||||
深色区块(不随主题翻转的独立 token)
|
||||
✅ --color-dark-text-primary on --color-dark-bg — 18.48:1
|
||||
✅ --color-dark-text-secondary on --color-dark-bg — 13.03:1
|
||||
✅ --color-dark-text-muted on --color-dark-bg — 7.54:1
|
||||
✅ --color-brand-section-text on --color-brand-section — 8.93:1
|
||||
|
||||
🎨 DARK 主题(html[data-theme='dark'],246 个令牌)
|
||||
正文层级 × 页面底色
|
||||
✅ --color-text-primary on --color-bg-primary — 18.48:1
|
||||
✅ --color-text-primary on --color-bg-secondary — 17.69:1
|
||||
✅ --color-text-primary on --color-bg-tertiary — 16.55:1
|
||||
✅ --color-text-secondary on --color-bg-primary — 13.03:1
|
||||
✅ --color-text-secondary on --color-bg-secondary — 12.47:1
|
||||
✅ --color-text-tertiary on --color-bg-primary — 7.54:1
|
||||
✅ --color-text-muted on --color-bg-primary — 7.54:1
|
||||
品牌红文字通道(text-brand-ink 及 hover 档)
|
||||
✅ --color-brand-ink on --color-bg-primary — 6.99:1
|
||||
✅ --color-brand-ink on --color-bg-secondary — 6.69:1
|
||||
✅ --color-brand-ink on --color-brand-bg — 6.27:1
|
||||
✅ --color-brand-ink-hover on --color-bg-primary — 10.19:1
|
||||
✅ --color-brand-ink-hover on --color-brand-bg — 9.13:1
|
||||
✅ #FFFFFF on --color-brand — 5.84:1
|
||||
alpha 修饰正文(带 /80 等修饰类的正文)
|
||||
✅ --color-text-secondary on --color-bg-primary @80% — 8.52:1
|
||||
大号装饰文本(text-text-hint)× 各级卡片底色
|
||||
✅ --color-text-hint on --color-bg-primary — 7.54:1
|
||||
✅ --color-text-hint on --color-bg-secondary — 7.22:1
|
||||
✅ --color-text-hint on --color-bg-tertiary — 6.75:1
|
||||
✅ --color-text-hint on --color-bg-elevated — 6.75:1
|
||||
深色区块(不随主题翻转的独立 token)
|
||||
✅ --color-dark-text-primary on --color-dark-bg — 18.48:1
|
||||
✅ --color-dark-text-secondary on --color-dark-bg — 13.03:1
|
||||
✅ --color-dark-text-muted on --color-dark-bg — 7.54:1
|
||||
✅ --color-brand-section-text on --color-brand-section — 8.93:1
|
||||
|
||||
📊 合计 44 组:✅ 44 / ❌ 0 不达标 / ⚠️ 0 令牌缺失
|
||||
|
||||
✅ 全部令牌配对满足 WCAG 2.1 AA
|
||||
|
||||
## npm run check:headings
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 check:headings
|
||||
> tsx scripts/utils/check-heading-hierarchy.ts
|
||||
|
||||
🚀 启动预览服务...
|
||||
(node:52518) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.
|
||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
||||
🔍 检查页面标题层级...
|
||||
|
||||
✅ 首页 (0 个问题)
|
||||
✅ 关于我们 (0 个问题)
|
||||
✅ 产品中心 (0 个问题)
|
||||
✅ 产品详情-ERP (0 个问题)
|
||||
✅ 解决方案 (0 个问题)
|
||||
✅ 解决方案详情-制造 (0 个问题)
|
||||
✅ 服务列表 (0 个问题)
|
||||
✅ 服务详情-软件开发 (0 个问题)
|
||||
✅ 新闻列表 (0 个问题)
|
||||
✅ 联系我们 (0 个问题)
|
||||
|
||||
📊 检查摘要
|
||||
扫描页面: 10
|
||||
通过页面: 10
|
||||
失败页面: 0
|
||||
问题总数: 0
|
||||
|
||||
📝 详细报告已保存: /Users/zhangxiang/Codes/Novalon/novalon-website/heading-hierarchy-report.json
|
||||
# check:contrast 与 check:headings —— 最终树空闲复跑
|
||||
# 生成于 2026-09-21T22:47:59Z
|
||||
|
||||
## npm run check:contrast
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 check:contrast
|
||||
> tsx scripts/utils/check-color-contrast.ts
|
||||
|
||||
|
||||
🎨 LIGHT 主题(:root,246 个令牌)
|
||||
正文层级 × 页面底色
|
||||
✅ --color-text-primary on --color-bg-primary — 19.34:1
|
||||
✅ --color-text-primary on --color-bg-secondary — 18.48:1
|
||||
✅ --color-text-primary on --color-bg-tertiary — 17.65:1
|
||||
✅ --color-text-secondary on --color-bg-primary — 10.35:1
|
||||
✅ --color-text-secondary on --color-bg-secondary — 9.90:1
|
||||
✅ --color-text-tertiary on --color-bg-primary — 7.58:1
|
||||
✅ --color-text-muted on --color-bg-primary — 4.76:1
|
||||
品牌红文字通道(text-brand-ink 及 hover 档)
|
||||
✅ --color-brand-ink on --color-bg-primary — 5.84:1
|
||||
✅ --color-brand-ink on --color-bg-secondary — 5.58:1
|
||||
✅ --color-brand-ink on --color-brand-bg — 5.35:1
|
||||
✅ --color-brand-ink-hover on --color-bg-primary — 7.87:1
|
||||
✅ --color-brand-ink-hover on --color-brand-bg — 7.20:1
|
||||
✅ #FFFFFF on --color-brand — 5.84:1
|
||||
alpha 修饰正文(带 /80 等修饰类的正文)
|
||||
✅ --color-text-secondary on --color-bg-primary @80% — 5.74:1
|
||||
大号装饰文本(text-text-hint)× 各级卡片底色
|
||||
✅ --color-text-hint on --color-bg-primary — 3.41:1
|
||||
✅ --color-text-hint on --color-bg-secondary — 3.26:1
|
||||
✅ --color-text-hint on --color-bg-tertiary — 3.12:1
|
||||
✅ --color-text-hint on --color-bg-elevated — 3.41:1
|
||||
深色区块(不随主题翻转的独立 token)
|
||||
✅ --color-dark-text-primary on --color-dark-bg — 18.48:1
|
||||
✅ --color-dark-text-secondary on --color-dark-bg — 13.03:1
|
||||
✅ --color-dark-text-muted on --color-dark-bg — 7.54:1
|
||||
✅ --color-brand-section-text on --color-brand-section — 8.93:1
|
||||
|
||||
🎨 DARK 主题(html[data-theme='dark'],246 个令牌)
|
||||
正文层级 × 页面底色
|
||||
✅ --color-text-primary on --color-bg-primary — 18.48:1
|
||||
✅ --color-text-primary on --color-bg-secondary — 17.69:1
|
||||
✅ --color-text-primary on --color-bg-tertiary — 16.55:1
|
||||
✅ --color-text-secondary on --color-bg-primary — 13.03:1
|
||||
✅ --color-text-secondary on --color-bg-secondary — 12.47:1
|
||||
✅ --color-text-tertiary on --color-bg-primary — 7.54:1
|
||||
✅ --color-text-muted on --color-bg-primary — 7.54:1
|
||||
品牌红文字通道(text-brand-ink 及 hover 档)
|
||||
✅ --color-brand-ink on --color-bg-primary — 6.99:1
|
||||
✅ --color-brand-ink on --color-bg-secondary — 6.69:1
|
||||
✅ --color-brand-ink on --color-brand-bg — 6.27:1
|
||||
✅ --color-brand-ink-hover on --color-bg-primary — 10.19:1
|
||||
✅ --color-brand-ink-hover on --color-brand-bg — 9.13:1
|
||||
✅ #FFFFFF on --color-brand — 5.84:1
|
||||
alpha 修饰正文(带 /80 等修饰类的正文)
|
||||
✅ --color-text-secondary on --color-bg-primary @80% — 8.52:1
|
||||
大号装饰文本(text-text-hint)× 各级卡片底色
|
||||
✅ --color-text-hint on --color-bg-primary — 7.54:1
|
||||
✅ --color-text-hint on --color-bg-secondary — 7.22:1
|
||||
✅ --color-text-hint on --color-bg-tertiary — 6.75:1
|
||||
✅ --color-text-hint on --color-bg-elevated — 6.75:1
|
||||
深色区块(不随主题翻转的独立 token)
|
||||
✅ --color-dark-text-primary on --color-dark-bg — 18.48:1
|
||||
✅ --color-dark-text-secondary on --color-dark-bg — 13.03:1
|
||||
✅ --color-dark-text-muted on --color-dark-bg — 7.54:1
|
||||
✅ --color-brand-section-text on --color-brand-section — 8.93:1
|
||||
|
||||
📊 合计 44 组:✅ 44 / ❌ 0 不达标 / ⚠️ 0 令牌缺失
|
||||
|
||||
✅ 全部令牌配对满足 WCAG 2.1 AA
|
||||
|
||||
## npm run check:headings
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 check:headings
|
||||
> tsx scripts/utils/check-heading-hierarchy.ts
|
||||
|
||||
🚀 启动预览服务...
|
||||
(node:61061) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.
|
||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
||||
🔍 检查页面标题层级...
|
||||
|
||||
✅ 首页 (0 个问题)
|
||||
✅ 关于我们 (0 个问题)
|
||||
✅ 产品中心 (0 个问题)
|
||||
✅ 产品详情-ERP (0 个问题)
|
||||
✅ 解决方案 (0 个问题)
|
||||
✅ 解决方案详情-制造 (0 个问题)
|
||||
✅ 服务列表 (0 个问题)
|
||||
✅ 服务详情-软件开发 (0 个问题)
|
||||
✅ 新闻列表 (0 个问题)
|
||||
✅ 联系我们 (0 个问题)
|
||||
|
||||
📊 检查摘要
|
||||
扫描页面: 10
|
||||
通过页面: 10
|
||||
失败页面: 0
|
||||
问题总数: 0
|
||||
|
||||
📝 详细报告已保存: /Users/zhangxiang/Codes/Novalon/novalon-website/heading-hierarchy-report.json
|
||||
|
||||
## npm run check:brand-token
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 check:brand-token
|
||||
> tsx scripts/utils/check-brand-text-token.ts
|
||||
|
||||
|
||||
🔴 Two-Channel Red Rule 检查 — 文字通道禁用 --color-brand
|
||||
|
||||
|
||||
📊 检查摘要
|
||||
扫描目录: src
|
||||
扫描文件: 414
|
||||
违规处数: 0
|
||||
|
||||
✅ 文字通道全部使用 --color-brand-ink,双通道契约未被违反!
|
||||
|
||||
# ===== 最终树空闲复跑(chain3,含门禁脚本进程回收修复后)2026-09-22T02:42:16Z =====
|
||||
|
||||
## npm run check:contrast (EXIT=0)
|
||||
✅ --color-brand-ink on --color-bg-primary — 6.99:1
|
||||
✅ --color-brand-ink on --color-bg-secondary — 6.69:1
|
||||
✅ --color-brand-ink on --color-brand-bg — 6.27:1
|
||||
✅ --color-brand-ink-hover on --color-bg-primary — 10.19:1
|
||||
✅ --color-brand-ink-hover on --color-brand-bg — 9.13:1
|
||||
✅ #FFFFFF on --color-brand — 5.84:1
|
||||
alpha 修饰正文(带 /80 等修饰类的正文)
|
||||
✅ --color-text-secondary on --color-bg-primary @80% — 8.52:1
|
||||
大号装饰文本(text-text-hint)× 各级卡片底色
|
||||
✅ --color-text-hint on --color-bg-primary — 7.54:1
|
||||
✅ --color-text-hint on --color-bg-secondary — 7.22:1
|
||||
✅ --color-text-hint on --color-bg-tertiary — 6.75:1
|
||||
✅ --color-text-hint on --color-bg-elevated — 6.75:1
|
||||
深色区块(不随主题翻转的独立 token)
|
||||
✅ --color-dark-text-primary on --color-dark-bg — 18.48:1
|
||||
✅ --color-dark-text-secondary on --color-dark-bg — 13.03:1
|
||||
✅ --color-dark-text-muted on --color-dark-bg — 7.54:1
|
||||
✅ --color-brand-section-text on --color-brand-section — 8.93:1
|
||||
|
||||
📊 合计 44 组:✅ 44 / ❌ 0 不达标 / ⚠️ 0 令牌缺失
|
||||
|
||||
✅ 全部令牌配对满足 WCAG 2.1 AA
|
||||
|
||||
## npm run check:headings (EXIT=0)
|
||||
(node:58761) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.
|
||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
||||
🔍 检查页面标题层级...
|
||||
|
||||
✅ 首页 (0 个问题)
|
||||
✅ 关于我们 (0 个问题)
|
||||
✅ 产品中心 (0 个问题)
|
||||
✅ 产品详情-ERP (0 个问题)
|
||||
✅ 解决方案 (0 个问题)
|
||||
✅ 解决方案详情-制造 (0 个问题)
|
||||
✅ 服务列表 (0 个问题)
|
||||
✅ 服务详情-软件开发 (0 个问题)
|
||||
✅ 新闻列表 (0 个问题)
|
||||
✅ 联系我们 (0 个问题)
|
||||
|
||||
📊 检查摘要
|
||||
扫描页面: 10
|
||||
通过页面: 10
|
||||
失败页面: 0
|
||||
问题总数: 0
|
||||
|
||||
📝 详细报告已保存: /Users/zhangxiang/Codes/Novalon/novalon-website/heading-hierarchy-report.json
|
||||
|
||||
## npm run check:brand-token (EXIT=0)
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 check:brand-token
|
||||
> tsx scripts/utils/check-brand-text-token.ts
|
||||
|
||||
|
||||
🔴 Two-Channel Red Rule 检查 — 文字通道禁用 --color-brand
|
||||
|
||||
|
||||
📊 检查摘要
|
||||
扫描目录: src
|
||||
扫描文件: 414
|
||||
违规处数: 0
|
||||
|
||||
✅ 文字通道全部使用 --color-brand-ink,双通道契约未被违反!
|
||||
|
||||
# ===== 最终树复跑(chain4:404 水印 /80 + global-error 兜底页修复后)2026-09-22T03:19:50Z =====
|
||||
|
||||
## npm run check:contrast (EXIT=0)
|
||||
✅ --color-brand-ink on --color-bg-primary — 6.99:1
|
||||
✅ --color-brand-ink on --color-bg-secondary — 6.69:1
|
||||
✅ --color-brand-ink on --color-brand-bg — 6.27:1
|
||||
✅ --color-brand-ink-hover on --color-bg-primary — 10.19:1
|
||||
✅ --color-brand-ink-hover on --color-brand-bg — 9.13:1
|
||||
✅ #FFFFFF on --color-brand — 5.84:1
|
||||
alpha 修饰正文(带 /80 等修饰类的正文)
|
||||
✅ --color-text-secondary on --color-bg-primary @80% — 8.52:1
|
||||
大号装饰文本(text-text-hint)× 各级卡片底色
|
||||
✅ --color-text-hint on --color-bg-primary — 7.54:1
|
||||
✅ --color-text-hint on --color-bg-secondary — 7.22:1
|
||||
✅ --color-text-hint on --color-bg-tertiary — 6.75:1
|
||||
✅ --color-text-hint on --color-bg-elevated — 6.75:1
|
||||
深色区块(不随主题翻转的独立 token)
|
||||
✅ --color-dark-text-primary on --color-dark-bg — 18.48:1
|
||||
✅ --color-dark-text-secondary on --color-dark-bg — 13.03:1
|
||||
✅ --color-dark-text-muted on --color-dark-bg — 7.54:1
|
||||
✅ --color-brand-section-text on --color-brand-section — 8.93:1
|
||||
|
||||
📊 合计 44 组:✅ 44 / ❌ 0 不达标 / ⚠️ 0 令牌缺失
|
||||
|
||||
✅ 全部令牌配对满足 WCAG 2.1 AA
|
||||
|
||||
## npm run check:brand-token (EXIT=0)
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 check:brand-token
|
||||
> tsx scripts/utils/check-brand-text-token.ts
|
||||
|
||||
|
||||
🔴 Two-Channel Red Rule 检查 — 文字通道禁用 --color-brand
|
||||
|
||||
|
||||
📊 检查摘要
|
||||
扫描目录: src
|
||||
扫描文件: 416
|
||||
违规处数: 0
|
||||
|
||||
✅ 文字通道全部使用 --color-brand-ink,双通道契约未被违反!
|
||||
|
||||
## npm run check:headings (EXIT=0)
|
||||
(node:41979) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities, as the arguments are not escaped, only concatenated.
|
||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
||||
🔍 检查页面标题层级...
|
||||
|
||||
✅ 首页 (0 个问题)
|
||||
✅ 关于我们 (0 个问题)
|
||||
✅ 产品中心 (0 个问题)
|
||||
✅ 产品详情-ERP (0 个问题)
|
||||
✅ 解决方案 (0 个问题)
|
||||
✅ 解决方案详情-制造 (0 个问题)
|
||||
✅ 服务列表 (0 个问题)
|
||||
✅ 服务详情-软件开发 (0 个问题)
|
||||
✅ 新闻列表 (0 个问题)
|
||||
✅ 联系我们 (0 个问题)
|
||||
|
||||
📊 检查摘要
|
||||
扫描页面: 10
|
||||
通过页面: 10
|
||||
失败页面: 0
|
||||
问题总数: 0
|
||||
|
||||
📝 详细报告已保存: /Users/zhangxiang/Codes/Novalon/novalon-website/heading-hierarchy-report.json
|
||||
|
||||
# ===== 最终树复跑(chain6:header 函数式 setState + 移动端性能计时修复后)2026-09-22T03:51:41Z =====
|
||||
|
||||
## npm run check:contrast (EXIT=0)
|
||||
✅ --color-brand-ink-hover on --color-brand-bg — 9.13:1
|
||||
✅ #FFFFFF on --color-brand — 5.84:1
|
||||
alpha 修饰正文(带 /80 等修饰类的正文)
|
||||
✅ --color-text-secondary on --color-bg-primary @80% — 8.52:1
|
||||
大号装饰文本(text-text-hint)× 各级卡片底色
|
||||
✅ --color-text-hint on --color-bg-primary — 7.54:1
|
||||
✅ --color-text-hint on --color-bg-secondary — 7.22:1
|
||||
✅ --color-text-hint on --color-bg-tertiary — 6.75:1
|
||||
✅ --color-text-hint on --color-bg-elevated — 6.75:1
|
||||
深色区块(不随主题翻转的独立 token)
|
||||
✅ --color-dark-text-primary on --color-dark-bg — 18.48:1
|
||||
✅ --color-dark-text-secondary on --color-dark-bg — 13.03:1
|
||||
✅ --color-dark-text-muted on --color-dark-bg — 7.54:1
|
||||
✅ --color-brand-section-text on --color-brand-section — 8.93:1
|
||||
|
||||
📊 合计 44 组:✅ 44 / ❌ 0 不达标 / ⚠️ 0 令牌缺失
|
||||
|
||||
✅ 全部令牌配对满足 WCAG 2.1 AA
|
||||
|
||||
## npm run check:brand-token (EXIT=0)
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 check:brand-token
|
||||
> tsx scripts/utils/check-brand-text-token.ts
|
||||
|
||||
|
||||
🔴 Two-Channel Red Rule 检查 — 文字通道禁用 --color-brand
|
||||
|
||||
|
||||
📊 检查摘要
|
||||
扫描目录: src
|
||||
扫描文件: 416
|
||||
违规处数: 0
|
||||
|
||||
✅ 文字通道全部使用 --color-brand-ink,双通道契约未被违反!
|
||||
|
||||
## npm run check:headings (EXIT=0)
|
||||
✅ 首页 (0 个问题)
|
||||
✅ 关于我们 (0 个问题)
|
||||
✅ 产品中心 (0 个问题)
|
||||
✅ 产品详情-ERP (0 个问题)
|
||||
✅ 解决方案 (0 个问题)
|
||||
✅ 解决方案详情-制造 (0 个问题)
|
||||
✅ 服务列表 (0 个问题)
|
||||
✅ 服务详情-软件开发 (0 个问题)
|
||||
✅ 新闻列表 (0 个问题)
|
||||
✅ 联系我们 (0 个问题)
|
||||
|
||||
📊 检查摘要
|
||||
扫描页面: 10
|
||||
通过页面: 10
|
||||
失败页面: 0
|
||||
问题总数: 0
|
||||
|
||||
📝 详细报告已保存: /Users/zhangxiang/Codes/Novalon/novalon-website/heading-hierarchy-report.json
|
||||
@@ -0,0 +1,10 @@
|
||||
# test:coverage 最终树复跑 2026-09-22T04:50:44Z
|
||||
✓ does not refresh when pull distance is below threshold (2 ms)
|
||||
✓ should call onSwipeLeft when progress exceeds threshold (2 ms)
|
||||
✓ should call onSwipeRight when progress exceeds threshold
|
||||
✓ should not trigger callbacks when progress is below threshold (1 ms)
|
||||
✓ should not call vibrate when progress is below threshold (2 ms)
|
||||
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
||||
All files | 77.92 | 84.6 | 77.64 | 77.92 |
|
||||
Test Suites: 137 passed, 137 total
|
||||
Tests: 1659 passed, 1659 total
|
||||
@@ -0,0 +1,68 @@
|
||||
// 从 chain6 的 allure-results 里取出「本轮真正跑过的用例」按状态分组,
|
||||
// 目的:给 ② 的 28 skipped 一份**具名**证据(哪些用例、在哪个 project、以什么理由跳过),
|
||||
// 而不是只引用汇总行里的计数。汇总计数只能证明「数量」,证明不了「没有把失败洗成跳过」。
|
||||
import { readdirSync, statSync, readFileSync, writeFileSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
|
||||
const DIR = resolve(process.cwd() ?? '.', 'e2e/allure-results');
|
||||
// chain6 功能阶段:03:52:08Z → 04:20:43Z;视觉阶段紧接其后。留出余量按 UTC 当日 03:50–04:25 过滤。
|
||||
const FROM = Date.parse('2026-09-22T03:50:00Z');
|
||||
const TO = Date.parse('2026-09-22T04:25:00Z');
|
||||
|
||||
const files = readdirSync(DIR).filter((f) => f.endsWith('-result.json'));
|
||||
const rows = [];
|
||||
for (const f of files) {
|
||||
const p = resolve(DIR, f);
|
||||
const m = statSync(p).mtimeMs;
|
||||
if (m < FROM || m > TO) continue;
|
||||
let j;
|
||||
try {
|
||||
j = JSON.parse(readFileSync(p, 'utf8'));
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
const labels = {};
|
||||
for (const l of j.labels || []) labels[l.name] = l.value;
|
||||
rows.push({
|
||||
file: f,
|
||||
mtime: new Date(m).toISOString(),
|
||||
status: j.status,
|
||||
reason: j.statusDetails?.message || j.statusDetails?.trace || '',
|
||||
project: labels.device || labels.suiteParent || '',
|
||||
suite: labels.suite || '',
|
||||
fullName: j.fullName || '',
|
||||
name: j.name || '',
|
||||
});
|
||||
}
|
||||
|
||||
const byStatus = {};
|
||||
for (const r of rows) byStatus[r.status] = (byStatus[r.status] || 0) + 1;
|
||||
const skipped = rows.filter((r) => r.status === 'skipped').sort((a, b) => (a.fullName + a.project).localeCompare(b.fullName + b.project));
|
||||
|
||||
const out = {
|
||||
generatedAt: new Date().toISOString(),
|
||||
source: 'e2e/allure-results(chain6 最终代码树 `npm run test` 功能+视觉两阶段的 allure 落盘)',
|
||||
window: { from: new Date(FROM).toISOString(), to: new Date(TO).toISOString() },
|
||||
totalResults: rows.length,
|
||||
byStatus,
|
||||
skippedCount: skipped.length,
|
||||
// 按 (suite, reason) 聚合,便于核对「每处 test.skip 条件命中了多少条」
|
||||
skipTally: Object.entries(
|
||||
skipped.reduce((acc, r) => {
|
||||
const k = `${r.suite} :: ${r.reason.slice(0, 80)}`;
|
||||
acc[k] = (acc[k] || 0) + 1;
|
||||
return acc;
|
||||
}, {}),
|
||||
).map(([k, n]) => ({ group: k, count: n })),
|
||||
skipped,
|
||||
};
|
||||
writeFileSync(
|
||||
resolve(process.cwd() ?? '.', 'docs/acceptance/2026-09-21-gates/skipped-tests-final-tree.json'),
|
||||
JSON.stringify(out, null, 2),
|
||||
);
|
||||
console.log(`window results=${rows.length} byStatus=${JSON.stringify(byStatus)}`);
|
||||
console.log(`skipped=${skipped.length}`);
|
||||
for (const t of out.skipTally) console.log(` x${t.count} ${t.group}`);
|
||||
const nonPass = rows.filter((r) => r.status !== 'passed' && r.status !== 'skipped');
|
||||
console.log(`otherNonPassed=${nonPass.length}`);
|
||||
for (const r of nonPass.slice(0, 10)) console.log(` ${r.status} ${r.project} ${r.fullName} :: ${r.reason.slice(0, 120)}`);
|
||||
@@ -0,0 +1,112 @@
|
||||
# 验收 §8 放行条件复跑结果(最终代码树)
|
||||
|
||||
生成时间:2026-09-22(UTC)。命令在**同一棵最终代码树**上串行执行,每步前后打印 :3000/:3100 端口占用数(0 才可用),
|
||||
证据链编号:chain1(静态 + Lighthouse + GA4 生产复跑)→ chain2(作废,孤儿服务复用毒化)→ chain3(进程回收修复后复跑)
|
||||
→ chain4/chain5/chain6(404 水印、`global-error` 兜底页、header 函数式 setState、移动端性能计时修复后,`EXIT_TEST=0` 归零轮)
|
||||
→ chain7(Lighthouse 死断言处理 + axe 规则级通道)→ chain8(覆盖率棘轮 + iPhone SE 口径复跑)→ chain9(静态门禁与 Lighthouse 的第二次连续全绿)。
|
||||
复跑脚本随证据存放于本目录:`chain7-dead-audit-and-rule-coverage.sh`、`chain8-coverage-and-iphone-se.sh`、`chain9-lighthouse-9urls.sh`。
|
||||
|
||||
## ② E2E 归零(`npm run test` = `test:functional && test:visual:all`)
|
||||
|
||||
| 轮次 | 结果 | 说明 |
|
||||
|---|---|---|
|
||||
| chain3 | 功能 `1048 passed / 4 failed / 28 skipped`(19.0m),端口预检 0 | 4 例均为**满负载竞态**(隔离复跑 `/tmp/repro-4.log` 33 例全过):p2 hover 下拉链接点击、p3 `isVisible→boundingBox` 两段式解析、uj-11 `scrollIntoViewIfNeeded` 撞 detach、p4 把 `waitForTimeout(1500)` 计入加载耗时 |
|
||||
| chain4 | 功能 `1049 passed / 3 failed / 28 skipped`(15.7m) | 上述 4 例全过;新暴露同类 3 例:移动端 LCP 2736ms(dev 现场编译计入计时)、`website-acceptance.spec.ts:121` 与 `mobile.spec.ts:101` 找不到 `[data-testid="mobile-navigation"]` |
|
||||
| chain6 | 功能 `1052 passed / 0 failed / 28 skipped`(17.4m)→ 视觉 `115 passed / 0 failed`(3.7m);`EXIT_TEST=0 2026-09-22T04:20:43Z` | **已归零**。chain4 的 3 例(移动端 LCP、两例 `mobile-navigation`)全部通过;视觉阶段真正执行(`/tmp/e2e-final9.log` 末段逐条列出 `visual-webkit-desktop` 的 115 例,含 L1 13 路由 + L2 组件态 + L3 排版色彩 + 浅色/深色主题各一)。全程未使用 `--update-snapshots`,基线未被改写。`POST_TEST_LISTENERS=0` |
|
||||
|
||||
chain4 的移动端两例经**根因定位后按产品缺陷修复**:`src/components/layout/header.tsx:184` 原为 `setIsOpen(!isOpen)`,
|
||||
读取渲染闭包里的 `isOpen`,与抽屉的 `AnimatePresence` 退出动画(0.2s + 0.25s)叠加时高负载下丢点击 ⇒ 用户连点汉堡按钮可能打不开抽屉。
|
||||
改为函数式 `setIsOpen((prev) => !prev)`。同文件同类的另外两处(`admin/login/page.tsx:80`、`admin/notifications/page.tsx:167`)
|
||||
未在失败用例链路上,记为残留项交范围裁定。视觉基线未被改写(全程未使用 `--update-snapshots`)。
|
||||
|
||||
## ④ 静态门禁(chain6 最终树)
|
||||
|
||||
| 门禁 | 命令 | 结果 |
|
||||
|---|---|---|
|
||||
| 类型 | `npm run type-check` | chain6 `EXIT_TYPECHECK=0`(2026-09-22T03:51:14Z,2s)。**2s 触发怀疑,已用正/负对照自证不是空跑**:临时写入 `src/__typecheck-probe.ts`(`const probe: number = "not a number"`)⇒ `tsc` 报 `error TS2322`(11.1s,冷缓存);删除后复跑干净(2.9s,`tsconfig.compilerOptions.incremental=true` 命中 `.tsbuildinfo`)。探针文件已删除,未进入代码树 |
|
||||
| 单元 | `npm run test:unit` | chain6 `EXIT_UNIT=0`:**137 suites / 1659 tests 全通过**(`Time: 6.936 s`,含新增 `src/app/global-error.test.tsx` 3 例) |
|
||||
| Lint | `npm run lint` | chain6 `EXIT_LINT=0`:**0 error / 106 warning**(chain4 同为 106)。⚠️ [AGENTS.md](../../../AGENTS.md) §5 记的「实测 105 条」已过期,需同步;warning 是否清零由范围裁定,见 CONTEXT.md 决策表。其中 1 条是 `Unused eslint-disable directive`(死抑制,非真问题但可清) |
|
||||
| 品牌文本通道 | `npm run check:brand-token` | chain6 `EXIT=0`,双通道契约未违反 |
|
||||
| 对比度(令牌配对) | `npm run check:contrast` | chain6 **合计 44 组:✅ 44 / ❌ 0 / ⚠️ 0** → `contrast-and-headings.txt`(chain3/4/6 各一段) |
|
||||
| 标题层级 | `npm run check:headings` | chain6 逐页 **0 问题**,`EXIT=0` |
|
||||
| 构建 | `npm run build` | chain6 `EXIT_BUILD=0`(8s 增量,路由表与 24 个 html 产物 mtime 新于 03:50 已核对,非空跑) |
|
||||
| Lighthouse | `npm run lighthouse` | chain6 `EXIT=0`(21 运行,但含 3 条死断言)→ **chain7 `EXIT_LIGHTHOUSE=0`(04:50:08Z)与 chain9 `EXIT_LIGHTHOUSE=0`(05:10:58Z)连续两次:9 URL × 3 次 = 27 运行、0 error、0 条 `not a known audit`**。URL 表已补 `/products/erp-upgrade`、`/about/brand`(§7 缺口的 Lighthouse 半边),两条新路由四类目均满分(perf 100 / a11y 1.0 / bp 1.0 / seo 1.0,LCP 786ms 与 794ms) |
|
||||
| axe 节点计数(⑤) | 见下节 | `passed=true` |
|
||||
|
||||
**chain9 二次确认(05:03–05:11Z)**:处理完死断言、改过 `config/test/lighthouserc.json` 与文档/探针之后,把 `type-check`、`lint`、`test:unit`、`check:contrast`、`check:headings`、`check:brand-token` 全量重跑,**6 项 `EXIT=0`**(lint 仍 0 error / 106 warning),前后 `LISTENERS=0`。chain9 同时是 Lighthouse 在 9 URL 配置下的第二次连续全绿。
|
||||
|
||||
### Lighthouse 的 3 条死断言(chain6 新发现,已在最终树处理)
|
||||
|
||||
`config/test/lighthouserc.json:95-97` 的 `autocomplete-valid` / `presentation-role-conflict` / `svg-img-alt` 三条 `warn` 断言,
|
||||
每轮都稳定打印 `"…" is not a known audit. expected: >=1 found: 0`(chain4+chain6 合计 42 条 = 3 条 × 7 URL × 2 轮)。
|
||||
两个独立信源确认它们是**恒不成立的死断言**,而非「页面恰好没问题」:
|
||||
|
||||
1. **运行时报告**:最新 JSON 报告(`lighthouse-reports/contact-2026_09_22_04_25_34.report.json`,`lighthouseVersion 12.6.1`)的 `audits` 键集合里没有这三个 id,而同批断言的 `color-contrast`/`heading-order`/`target-size`/`aria-conditional-attr`/`skip-link` 均在列。
|
||||
2. **审计注册表**:`@lhci/cli@0.15.1` 自带的是 `lighthouse@12.6.1`(不是顶层的 13.4.1 —— 这层版本裂差本身就是「为什么本地包里没有该审计」的答案),其 `core/audits/accessibility/` 共 64 个审计文件,无此三者。
|
||||
|
||||
覆盖率影响并非对等,因此不能简单删掉了事:用与门禁同款的 `runOnly: {type:'tag', values:['wcag2a','wcag2aa','wcag21a','wcag21aa']}`
|
||||
做正/负对照探针(`docs/acceptance/2026-09-21-axe/probe-axe-rule-coverage.mjs`,每条规则各造一个必然违规的最小节点):
|
||||
|
||||
| 规则 | axe 4.11.4 是否在门禁 tag 内 | 探针是否抓到违规 |
|
||||
|---|---|---|
|
||||
| `autocomplete-valid` | 在 | ✅ 1 node |
|
||||
| `svg-img-alt` | 在 | ✅ 1 node |
|
||||
| `presentation-role-conflict` | **不在**(属 `best-practice` tag) | 规则未参与运行 |
|
||||
|
||||
⇒ 前两条的真实兜底是 ⑤ 的 axe 通道(已 34 路由 × 4 组合 = 0 违规);第三条在 axe 通道里也测不到,必须以规则级 `runOnly` 显式补上,
|
||||
否则「删死断言」会变成「悄悄拆掉一道门」。
|
||||
|
||||
**chain7 复验(最终处理)**:`lighthouserc.json` 删掉这 3 条;`axe-contrast-evidence.mjs` 在 tag 通道之外增加第二次
|
||||
`axe.run(document, {runOnly: {type:'rules', values: EXTRA_RULES}})`,并按页记录 `extraRulesChecked` 与 `extraRuleNodes`,
|
||||
把 `extraRuleNodes === 0` 与 `extraRulePagesUnderCovered === 0`(即每页三条规则确实都跑了)一并写入 `thresholds` 与 `passed`。
|
||||
结果:`EXIT_AXE_FULL=0`,`Σ extraRulesChecked = 408 = 34 路由 × 4 组合 × 3 规则`(分母闭合,不是"没测到所以 0")、
|
||||
`extraRuleNodes = 0`;`EXIT_LIGHTHOUSE=0` 且 chain7 段 `not a known audit` 计数 **0**(chain4+chain6 历史段共 42 条,保留作对照)。
|
||||
|
||||
## ⑤ 全站双引擎双主题 axe 节点计数 = 0
|
||||
|
||||
**chain7 最终树(`docs/acceptance/2026-09-21-axe/axe-evidence.json`,`generatedAt 2026-09-22T04:43:02Z`,axe-core 4.11.4)**
|
||||
——同一棵 src 代码树,`EXIT_AXE_FULL=0`;chain6(tag 通道单跑)快照存为 `axe-evidence-chain6-tagonly.json`,chain5 前一刻快照存为 `axe-evidence-chain5-preheader-fix.json`。
|
||||
|
||||
| 组合 | pages | contrastNodes | violationNodes | themeMismatch | bgMismatch | extraRuleNodes | extraRulePagesUnderCovered |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| chromium / light | 34 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
| chromium / dark | 34 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
| firefox / light | 34 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
| firefox / dark | 34 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
|
||||
`routeCount=34 rows=136(= 34 × 4 组合,分母断言)passed=true`;`Σ extraRulesChecked = 408 = 34 × 4 × 3`,
|
||||
规则级通道覆盖 `autocomplete-valid` / `presentation-role-conflict` / `svg-img-alt`(后一条不在 wcag tag 集合内,只能靠它)。
|
||||
|
||||
**口径升级(这是 ⑤ 的关键,不是换实现)**:清单来源从「`/sitemap.xml` 的 29 条」扩为
|
||||
**sitemap ∪ 预渲染产物(`dist/standalone/dist/server/app/**/*.html`)∪ 站内链接 BFS**(`crawl-sitemap.mjs`,打印 `skippedInternalDocs=1`)。
|
||||
扩目录首轮(chain3)就**不是 0**:`/_not-found` 的 h1 用 `text-brand-ink` + `opacity-20` ⇒ 双引擎双主题各 1 个 `color-contrast` 节点;
|
||||
`/_global-error` 是 Next 内置 500 文档(`<html id="__next_error__">` 无 `lang`、深色丢本站令牌)。
|
||||
两处修复见 `docs/lessons-learned.md §5.24` 与 `CONTEXT.md` 决策行;框架内置文档按**内容**(非名字)排除并留痕,
|
||||
一旦框架把本站 `global-error.tsx` 预渲染到该路径,条件即不再命中、路由自动回到清单。
|
||||
|
||||
历史对照:`axe-evidence-sitemap29.json`(29 页版,`passed=true`,116 行)—— 当时的 0 是真 0,但分母不足以覆盖 404 与兜底页。
|
||||
|
||||
## ⑥ 与 A-7 的补充复跑(chain8,最终树)
|
||||
|
||||
| 项 | 结果 |
|
||||
|---|---|
|
||||
| 覆盖率棘轮(A-7) | `npm run test:coverage` → **`EXIT_COVERAGE=0`**(2026-09-22T04:50:44Z):137 套件 / 1659 例全通过,`All files` = **Stmts 77.92 / Branch 84.6 / Funcs 77.64 / Lines 77.92**,对照 `config/test/jest.config.js` 的 `coverageThreshold`(82 / 75 / 75 / 75)四项均达标。数值已回写 `AGENTS.md` §5(原记 84.71 / 77.55 / 77.89 / 77.89 是 2026-09-21 树,`global-error.tsx` 加入后微移)→ `coverage-final-tree.txt` |
|
||||
| iPhone SE 口径复跑(⑥ 的仿真部分) | `EXIT_SE_AUDIT=0`(2026-09-22T04:52:07Z),证据写入**新目录** `docs/acceptance/2026-09-22-iphone-se/`(40 图 + `measurements.json` + `audit.log`),不覆盖 09-21 那份 21:07Z 的旧证据。本轮把探针路由从 4 条扩到 5 条(新增 `/no-such-route-404-check`),得 **20 行 = 5 页 × 深/浅 × 同意条 pending/dismissed**:`overflow=0`(`docScrollW == clientW == 375` 全部成立)、`themeNull=0`、`dismissed` 态 `footerBottomGap=64` 一致(R-1 的双安全区空带已消除)。`pendingBannerOverlapFooter=8` 是 `fixed bottom-*` 浮层的既定行为,可关闭后消失,与旧证据同口径。**限制不变**:这是 Playwright 仿真,条件⑥ 要的「真机 iPhone SE + 系统深色」仍只能由交付决策人实机走查 |
|
||||
|
||||
**新探针当场挖到的一条观察(不是回归,待裁定)**:404 路由的 `footerBottomGap` 全为 `null` ⇒ 预渲染产物 `dist/standalone/dist/server/app/_not-found.html` 里**没有 `<footer>`**(同一探针下首页有 `<footer data-testid="footer" role="contentinfo">`)。根因不是 bug:`src/app/layout.tsx` 本身不渲染 Header/Footer,页面级外壳由各页自行组合,而 `src/app/not-found.tsx` 只返回 `NotFoundContent`(自带「返回首页 / 搜索」出口)。因此**404 与根错误页无站内导航、无备案页脚**——是否给边界页补齐页头页脚属设计判断,未擅自改动,列入决策清单。
|
||||
|
||||
## ① 四项 P0 的回归测试归属(非快照,指向可点开的具体用例)
|
||||
|
||||
- A-1/A-2 权限提升与改密鉴权:`src/app/api/admin/users/route.test.ts`(11 例,含「不得借先建号再自我提权绕过」「资料字段不得先落库再被角色校验拒绝」「不得停用/降级超管」)、`src/app/api/admin/roles/route.test.ts`(9 例)、`src/lib/permissions.test.ts`(10 例)。
|
||||
- A-3 存储型 XSS:`src/lib/sanitize.test.ts`(15 例)。
|
||||
- A-4 上传白名单 + 魔数:`src/lib/media/upload-policy.test.ts`(扩展名/MIME 申报不符、双扩展名、`.html`/`.svg`/可执行、路径穿越、空与超限)、`src/lib/media/media-service.test.ts:60,69`(**`upload-policy` 未被 mock**,断言「HTML 载荷在落盘前即被拒绝」,因此同时是路由下游的接线回归)、`src/app/api/admin/media/route.test.ts`(12 例:401/403/400/体积/多图)。
|
||||
|
||||
## 已知口径限制(不掩饰)
|
||||
|
||||
1. **chain2 那次 `805 passed / 263 failed` 作废**:`check:headings`/`check:contrast` 的脚本只 kill 包装进程 ⇒ `next-server` 孤儿占住 :3000,被 Playwright `reuseExistingServer` 静默复用,205 个失败是 `page.goto` 超时而非断言失败。已修(`detached` + 负 PID 杀进程组 + `process.exit` 前显式收服),chain3/4/6 的 `PRE/POST_*_LISTENERS` 均为 0 即为正/负对照。
|
||||
2. **满负载竞态与"隔离必过"的差别**:本地 `retries: 0`、CI `retries: 2`(`e2e/playwright.config.ts`),且 4 个 project × 多 worker 同机跑 3 个引擎。本轮不做"加 retries 掩盖",而是逐项消除竞态成因(预热、auto-retry 断言、限定 `main` 作用域、函数式 setState)。残留风险:同机并发仍可能出新的竞态例。
|
||||
3. ③「Jenkins 无 `|| echo` 后连续两次全绿」只能由交付决策人触发;本地已按 Jenkinsfile 原样跑通同一命令序列(`npm run build` + `npm run test:e2e:prod`)。
|
||||
4. ⑥ 已在最终树上以仿真复跑(chain8,`docs/acceptance/2026-09-22-iphone-se/`,含新增的 404 路由);`measurements.json` 的 `caveat` 仍写明「Playwright 仿真,非真机」,**真机走查只能由交付决策人完成**,本条件不得由本地证据替代。
|
||||
5. ② 的「提交信息留痕」需一次经授权的提交才能落地;**本轮全部改动(含 `src/app/global-error.tsx`、header setState、4 个 spec 修订、`CONTEXT.md`/`lessons-learned.md`)均未提交**。
|
||||
6. 28 skipped 的拆解见 §5.23 与下表;其中 16 条 GA4 `@critical` 已在**生产目标**下单独复跑并全部真断言(`ga4-production-run.txt`:`Running 4 tests using 4 workers` → `4 passed (7.2s)`,含 `next start` 与 `output: standalone` 的告警原文)。
|
||||
7. **覆盖缺口的处理进度**:`/products/erp-upgrade` 与 `/about/brand` 此前既不在 Lighthouse URL 表也不在视觉回归的 13 条路由表里(视觉表有 `/products/erp`,与 `erp-upgrade` 是**不同路由**)——这正是 §5.22 已记过的同型缺口。**Lighthouse 半边已闭合**(chain7 起为 9 URL × 3 = 27 运行,`EXIT=0`);**视觉半边仍未闭合**,把两条路由加进 `e2e/visual-regression.spec.ts` 需要 `--update-snapshots` 重写已审批基线,属破坏性动作,须单独授权。
|
||||
@@ -0,0 +1,24 @@
|
||||
=== GA4 生产目标复跑 2026-09-21T22:47:51Z ===
|
||||
(node:60835) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead.
|
||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
||||
[2m[WebServer] [22m[33m[1m⚠[22m[39m Warning: Next.js ignored package-lock.json in /Users/zhangxiang because it is outside the current Git repository (/Users/zhangxiang/Codes/Novalon/novalon-website).
|
||||
[2m[WebServer] [22m To use this directory, set `outputFileTracingRoot` in your Next.js config.
|
||||
[2m[WebServer] [22m
|
||||
[2m[WebServer] [22m[33m[1m⚠[22m[39m "next start" does not work with "output: standalone" configuration. Use "node .next/standalone/server.js" instead.
|
||||
|
||||
Running 4 tests using 4 workers
|
||||
|
||||
(node:60886) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead.
|
||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
||||
(node:60883) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead.
|
||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
||||
(node:60885) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead.
|
||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
||||
(node:60884) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead.
|
||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
||||
✓ 3 [chromium] › ga4-event-tracking.spec.ts:121:7 › GA4 事件追踪验证 › TC-GA4-001: 页面浏览追踪 - 首屏由应用发出唯一一次 config @analytics @regression @critical (2.2s)
|
||||
✓ 4 [chromium] › ga4-event-tracking.spec.ts:234:7 › GA4 事件追踪验证 › TC-GA4-004: 页面浏览追踪 - 客户端路由跳转触发带 page_path 的 config @analytics @regression @critical (2.5s)
|
||||
✓ 1 [chromium] › ga4-event-tracking.spec.ts:141:7 › GA4 事件追踪验证 › TC-GA4-002: 联系表单提交触发 form_submit 和 conversion 事件 @analytics @regression @critical (4.1s)
|
||||
✓ 2 [chromium] › ga4-event-tracking.spec.ts:199:7 › GA4 事件追踪验证 › TC-GA4-003: 同意横幅「接受所有」点击触发 button_click 事件 @analytics @regression @critical (5.1s)
|
||||
|
||||
4 passed (7.2s)
|
||||
@@ -0,0 +1,564 @@
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 lighthouse
|
||||
> lhci autorun --config=config/test/lighthouserc.json
|
||||
|
||||
✅ .lighthouseci/ directory writable
|
||||
✅ Configuration file found
|
||||
✅ Chrome installation found
|
||||
Healthcheck passed!
|
||||
|
||||
Started a web server with "npm run start"...
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/about
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/services
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/products
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/cases
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/news
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/contact
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Done running Lighthouse!
|
||||
|
||||
Checking assertions against 7 URL(s), 21 total run(s)
|
||||
|
||||
3 result(s) for http://localhost:3000/ :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/about :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/services :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/products :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/cases :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/news :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/contact :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
All results processed!
|
||||
|
||||
Dumping 21 reports to disk at /Users/zhangxiang/Codes/Novalon/novalon-website/lighthouse-reports...
|
||||
Done writing reports to disk.
|
||||
|
||||
Done running autorun.
|
||||
|
||||
===== chain6 lighthouse(最终树)2026-09-22T04:20:43Z =====
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 lighthouse
|
||||
> lhci autorun --config=config/test/lighthouserc.json
|
||||
|
||||
✅ .lighthouseci/ directory writable
|
||||
✅ Configuration file found
|
||||
✅ Chrome installation found
|
||||
Healthcheck passed!
|
||||
|
||||
Started a web server with "npm run start"...
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/about
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/services
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/products
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/cases
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/news
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/contact
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Done running Lighthouse!
|
||||
|
||||
Checking assertions against 7 URL(s), 21 total run(s)
|
||||
|
||||
3 result(s) for http://localhost:3000/ :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/about :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/services :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/products :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/cases :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/news :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
3 result(s) for http://localhost:3000/contact :
|
||||
|
||||
⚠️ autocomplete-valid warning for auditRan assertion
|
||||
"autocomplete-valid" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ presentation-role-conflict warning for auditRan assertion
|
||||
"presentation-role-conflict" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
|
||||
⚠️ svg-img-alt warning for auditRan assertion
|
||||
"svg-img-alt" is not a known audit.
|
||||
|
||||
expected: >=1
|
||||
found: 0
|
||||
all values: 0, 0, 0
|
||||
|
||||
All results processed!
|
||||
|
||||
Dumping 21 reports to disk at /Users/zhangxiang/Codes/Novalon/novalon-website/lighthouse-reports...
|
||||
Done writing reports to disk.
|
||||
|
||||
Done running autorun.
|
||||
|
||||
===== chain7 lighthouse(移除 3 条死断言后)2026-09-22T04:43:05Z =====
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 lighthouse
|
||||
> lhci autorun --config=config/test/lighthouserc.json
|
||||
|
||||
✅ .lighthouseci/ directory writable
|
||||
✅ Configuration file found
|
||||
✅ Chrome installation found
|
||||
Healthcheck passed!
|
||||
|
||||
Started a web server with "npm run start"...
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/about
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/services
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/products
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/cases
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/news
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/contact
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/products/erp-upgrade
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/about/brand
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Done running Lighthouse!
|
||||
|
||||
Checking assertions against 9 URL(s), 27 total run(s)
|
||||
|
||||
All results processed!
|
||||
|
||||
Dumping 27 reports to disk at /Users/zhangxiang/Codes/Novalon/novalon-website/lighthouse-reports...
|
||||
Done writing reports to disk.
|
||||
|
||||
Done running autorun.
|
||||
|
||||
===== chain9 lighthouse(9 URL × 3 次 = 27 运行,补 erp-upgrade / about-brand)2026-09-22T05:04:19Z =====
|
||||
|
||||
> ruixin-website-react@1.0.0-phase1 lighthouse
|
||||
> lhci autorun --config=config/test/lighthouserc.json
|
||||
|
||||
✅ .lighthouseci/ directory writable
|
||||
✅ Configuration file found
|
||||
✅ Chrome installation found
|
||||
Healthcheck passed!
|
||||
|
||||
Started a web server with "npm run start"...
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/about
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/services
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/products
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/cases
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/news
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/contact
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/products/erp-upgrade
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Running Lighthouse 3 time(s) on http://localhost:3000/about/brand
|
||||
Run #1...done.
|
||||
Run #2...done.
|
||||
Run #3...done.
|
||||
Done running Lighthouse!
|
||||
|
||||
Checking assertions against 9 URL(s), 27 total run(s)
|
||||
|
||||
All results processed!
|
||||
|
||||
Dumping 27 reports to disk at /Users/zhangxiang/Codes/Novalon/novalon-website/lighthouse-reports...
|
||||
Done writing reports to disk.
|
||||
|
||||
Done running autorun.
|
||||
@@ -0,0 +1,21 @@
|
||||
import { test } from '@playwright/test';
|
||||
|
||||
// 只打印、不判定:把「fixture browserName 值」与「真实引擎(userAgent)」两件事分开测,
|
||||
// 因为跳过条件读的是前者,而能力(Touchscreen API)取决于后者。
|
||||
test('probe browserName identity', async ({ browserName, page }, testInfo) => {
|
||||
const ua = await page.evaluate(() => navigator.userAgent);
|
||||
const touchPoints = await page.evaluate(() => 'ontouchstart' in window ? (navigator.maxTouchPoints ?? 0) : -1);
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
project: testInfo.project.name,
|
||||
fixtureBrowserName: browserName,
|
||||
useBrowserName: (testInfo.project.use as { browserName?: string }).browserName ?? null,
|
||||
skipConditionIsTrue: browserName !== 'chromium',
|
||||
ua: ua.slice(0, 90),
|
||||
engine: /AppleWebKit\/.*Version\//.test(ua) && !/Chrome\//.test(ua) ? 'webkit'
|
||||
: /Firefox\//.test(ua) ? 'firefox'
|
||||
: /Chrome\//.test(ua) ? 'chromium' : 'unknown',
|
||||
touchPoints,
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
|
||||
// 探针:`chromium-mobile` 项目里 browserName 到底是什么、真正跑的是哪个引擎。
|
||||
// 起因:最终树 28 条 skipped 有 7 条落在 chromium-mobile(cms-workflow ×3 + Touchscreen ×1 + GA4 ×4),
|
||||
// 而跳过条件写成 `browserName !== 'chromium'` ⇒ 该项目内条件为真。
|
||||
export default defineConfig({
|
||||
testDir: __dirname,
|
||||
fullyParallel: true,
|
||||
reporter: [['list']],
|
||||
projects: [
|
||||
{
|
||||
name: 'replica-chromium-mobile',
|
||||
use: {
|
||||
...devices['iPhone 14'],
|
||||
viewport: { width: 390, height: 844 },
|
||||
isMobile: true,
|
||||
hasTouch: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// 正对照:显式写 browserName,看是否与"仅 spread devices"得到不同的 fixture 值
|
||||
name: 'explicit-chromium-mobile',
|
||||
browserName: 'chromium',
|
||||
use: {
|
||||
...devices['iPhone 14'],
|
||||
viewport: { width: 390, height: 844 },
|
||||
isMobile: true,
|
||||
hasTouch: true,
|
||||
},
|
||||
},
|
||||
{ name: 'plain-desktop', use: { ...devices['Desktop Chrome'] } },
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,310 @@
|
||||
{
|
||||
"generatedAt": "2026-09-22T05:18:05.880Z",
|
||||
"source": "e2e/allure-results(chain6 最终代码树 `npm run test` 功能+视觉两阶段的 allure 落盘)",
|
||||
"window": {
|
||||
"from": "2026-09-22T03:50:00.000Z",
|
||||
"to": "2026-09-22T04:25:00.000Z"
|
||||
},
|
||||
"totalResults": 1195,
|
||||
"byStatus": {
|
||||
"passed": 1167,
|
||||
"skipped": 28
|
||||
},
|
||||
"skippedCount": 28,
|
||||
"skipTally": [
|
||||
{
|
||||
"group": "cms-workflow.spec.ts :: CMS workflow test runs only in chromium",
|
||||
"count": 9
|
||||
},
|
||||
{
|
||||
"group": "ga4-event-tracking.spec.ts :: 构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"count": 16
|
||||
},
|
||||
{
|
||||
"group": "p3-compatibility.spec.ts :: Touchscreen API only available in Chromium",
|
||||
"count": 3
|
||||
}
|
||||
],
|
||||
"skipped": [
|
||||
{
|
||||
"file": "2219cf08-fad3-4399-8ec7-90aaf2d53ae7-result.json",
|
||||
"mtime": "2026-09-22T04:07:45.576Z",
|
||||
"status": "skipped",
|
||||
"reason": "CMS workflow test runs only in chromium",
|
||||
"project": "",
|
||||
"suite": "cms-workflow.spec.ts",
|
||||
"fullName": "cms-workflow.spec.ts:265:7",
|
||||
"name": "admin 可完成 创建草稿 → 提交审核 → 发布 → 前台可见"
|
||||
},
|
||||
{
|
||||
"file": "7de4326b-8932-4c95-880a-1e80296196b4-result.json",
|
||||
"mtime": "2026-09-22T04:13:35.011Z",
|
||||
"status": "skipped",
|
||||
"reason": "CMS workflow test runs only in chromium",
|
||||
"project": "",
|
||||
"suite": "cms-workflow.spec.ts",
|
||||
"fullName": "cms-workflow.spec.ts:265:7",
|
||||
"name": "admin 可完成 创建草稿 → 提交审核 → 发布 → 前台可见"
|
||||
},
|
||||
{
|
||||
"file": "ab09e8f1-e6bf-4936-a6a8-330dbb04fc10-result.json",
|
||||
"mtime": "2026-09-22T04:03:26.179Z",
|
||||
"status": "skipped",
|
||||
"reason": "CMS workflow test runs only in chromium",
|
||||
"project": "",
|
||||
"suite": "cms-workflow.spec.ts",
|
||||
"fullName": "cms-workflow.spec.ts:265:7",
|
||||
"name": "admin 可完成 创建草稿 → 提交审核 → 发布 → 前台可见"
|
||||
},
|
||||
{
|
||||
"file": "55ec3c0e-1cce-4e62-b0a1-2812f419c924-result.json",
|
||||
"mtime": "2026-09-22T04:13:35.012Z",
|
||||
"status": "skipped",
|
||||
"reason": "CMS workflow test runs only in chromium",
|
||||
"project": "",
|
||||
"suite": "cms-workflow.spec.ts",
|
||||
"fullName": "cms-workflow.spec.ts:279:7",
|
||||
"name": "非法状态流转会被拦截"
|
||||
},
|
||||
{
|
||||
"file": "625d1024-b16b-4698-9365-bacbbbad6df8-result.json",
|
||||
"mtime": "2026-09-22T04:03:26.185Z",
|
||||
"status": "skipped",
|
||||
"reason": "CMS workflow test runs only in chromium",
|
||||
"project": "",
|
||||
"suite": "cms-workflow.spec.ts",
|
||||
"fullName": "cms-workflow.spec.ts:279:7",
|
||||
"name": "非法状态流转会被拦截"
|
||||
},
|
||||
{
|
||||
"file": "8ab7a06e-ec1f-4636-a4ec-f83311a5426e-result.json",
|
||||
"mtime": "2026-09-22T04:07:45.578Z",
|
||||
"status": "skipped",
|
||||
"reason": "CMS workflow test runs only in chromium",
|
||||
"project": "",
|
||||
"suite": "cms-workflow.spec.ts",
|
||||
"fullName": "cms-workflow.spec.ts:279:7",
|
||||
"name": "非法状态流转会被拦截"
|
||||
},
|
||||
{
|
||||
"file": "42921f30-5ef2-402c-a0cd-c75190f16bf1-result.json",
|
||||
"mtime": "2026-09-22T04:03:26.185Z",
|
||||
"status": "skipped",
|
||||
"reason": "CMS workflow test runs only in chromium",
|
||||
"project": "",
|
||||
"suite": "cms-workflow.spec.ts",
|
||||
"fullName": "cms-workflow.spec.ts:297:7",
|
||||
"name": "多角色权限分离:管理员配置权限 → 编辑创建/提交 → 审核员发布 → 前台可见"
|
||||
},
|
||||
{
|
||||
"file": "52d69dbe-2aeb-4a1c-a5b5-857f2f5cf0f1-result.json",
|
||||
"mtime": "2026-09-22T04:07:45.579Z",
|
||||
"status": "skipped",
|
||||
"reason": "CMS workflow test runs only in chromium",
|
||||
"project": "",
|
||||
"suite": "cms-workflow.spec.ts",
|
||||
"fullName": "cms-workflow.spec.ts:297:7",
|
||||
"name": "多角色权限分离:管理员配置权限 → 编辑创建/提交 → 审核员发布 → 前台可见"
|
||||
},
|
||||
{
|
||||
"file": "f4d7c0ab-7d86-41bf-9e0c-9dba8af4fcf6-result.json",
|
||||
"mtime": "2026-09-22T04:13:35.013Z",
|
||||
"status": "skipped",
|
||||
"reason": "CMS workflow test runs only in chromium",
|
||||
"project": "",
|
||||
"suite": "cms-workflow.spec.ts",
|
||||
"fullName": "cms-workflow.spec.ts:297:7",
|
||||
"name": "多角色权限分离:管理员配置权限 → 编辑创建/提交 → 审核员发布 → 前台可见"
|
||||
},
|
||||
{
|
||||
"file": "08dcaad7-65e9-4f8f-ba09-8ccf9998eea6-result.json",
|
||||
"mtime": "2026-09-22T04:08:01.577Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:121:7",
|
||||
"name": "TC-GA4-001: 页面浏览追踪 - 首屏由应用发出唯一一次 config"
|
||||
},
|
||||
{
|
||||
"file": "19adc24e-76cd-4c67-86e3-6dc3349ad6c0-result.json",
|
||||
"mtime": "2026-09-22T04:13:53.422Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:121:7",
|
||||
"name": "TC-GA4-001: 页面浏览追踪 - 首屏由应用发出唯一一次 config"
|
||||
},
|
||||
{
|
||||
"file": "3e38da66-8835-4bd0-bcd5-4f25b9632243-result.json",
|
||||
"mtime": "2026-09-22T04:03:45.432Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:121:7",
|
||||
"name": "TC-GA4-001: 页面浏览追踪 - 首屏由应用发出唯一一次 config"
|
||||
},
|
||||
{
|
||||
"file": "8e30c9be-b79a-463c-959d-3d89ecc8f79b-result.json",
|
||||
"mtime": "2026-09-22T04:00:03.361Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:121:7",
|
||||
"name": "TC-GA4-001: 页面浏览追踪 - 首屏由应用发出唯一一次 config"
|
||||
},
|
||||
{
|
||||
"file": "0e4356a2-c4fe-4992-8152-7a42b02323a5-result.json",
|
||||
"mtime": "2026-09-22T04:08:06.884Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:141:7",
|
||||
"name": "TC-GA4-002: 联系表单提交触发 form_submit 和 conversion 事件"
|
||||
},
|
||||
{
|
||||
"file": "19d37331-c2d4-4467-89fe-a3f1979e7a28-result.json",
|
||||
"mtime": "2026-09-22T04:00:03.245Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:141:7",
|
||||
"name": "TC-GA4-002: 联系表单提交触发 form_submit 和 conversion 事件"
|
||||
},
|
||||
{
|
||||
"file": "29da23ac-66f4-4bed-b9a7-5680ee020b52-result.json",
|
||||
"mtime": "2026-09-22T04:13:53.581Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:141:7",
|
||||
"name": "TC-GA4-002: 联系表单提交触发 form_submit 和 conversion 事件"
|
||||
},
|
||||
{
|
||||
"file": "d74226e3-b1ee-45e8-8ece-dd756bd2428d-result.json",
|
||||
"mtime": "2026-09-22T04:03:44.905Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:141:7",
|
||||
"name": "TC-GA4-002: 联系表单提交触发 form_submit 和 conversion 事件"
|
||||
},
|
||||
{
|
||||
"file": "37e77148-e420-4c3f-ba73-e7348fbab00c-result.json",
|
||||
"mtime": "2026-09-22T04:08:06.810Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:199:7",
|
||||
"name": "TC-GA4-003: 同意横幅「接受所有」点击触发 button_click 事件"
|
||||
},
|
||||
{
|
||||
"file": "868f0726-a517-48d4-953f-8a226ee4b5aa-result.json",
|
||||
"mtime": "2026-09-22T04:13:52.839Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:199:7",
|
||||
"name": "TC-GA4-003: 同意横幅「接受所有」点击触发 button_click 事件"
|
||||
},
|
||||
{
|
||||
"file": "8be78b7c-be72-4d56-a8a7-e2898c54f1cb-result.json",
|
||||
"mtime": "2026-09-22T04:00:04.472Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:199:7",
|
||||
"name": "TC-GA4-003: 同意横幅「接受所有」点击触发 button_click 事件"
|
||||
},
|
||||
{
|
||||
"file": "c47b32cd-0f86-46b8-98c1-641664fa84c4-result.json",
|
||||
"mtime": "2026-09-22T04:03:44.635Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:199:7",
|
||||
"name": "TC-GA4-003: 同意横幅「接受所有」点击触发 button_click 事件"
|
||||
},
|
||||
{
|
||||
"file": "0c13405f-07ca-465f-babe-7694785d1386-result.json",
|
||||
"mtime": "2026-09-22T04:00:06.235Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:234:7",
|
||||
"name": "TC-GA4-004: 页面浏览追踪 - 客户端路由跳转触发带 page_path 的 config"
|
||||
},
|
||||
{
|
||||
"file": "2a78aee1-234c-4b59-9d03-96e5fb749a93-result.json",
|
||||
"mtime": "2026-09-22T04:03:48.732Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:234:7",
|
||||
"name": "TC-GA4-004: 页面浏览追踪 - 客户端路由跳转触发带 page_path 的 config"
|
||||
},
|
||||
{
|
||||
"file": "5ce72f00-9339-4ed9-9243-376f97720ea1-result.json",
|
||||
"mtime": "2026-09-22T04:13:55.190Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:234:7",
|
||||
"name": "TC-GA4-004: 页面浏览追踪 - 客户端路由跳转触发带 page_path 的 config"
|
||||
},
|
||||
{
|
||||
"file": "be9ce18f-0ab5-4016-9697-047f0208eb00-result.json",
|
||||
"mtime": "2026-09-22T04:08:08.969Z",
|
||||
"status": "skipped",
|
||||
"reason": "构建未注入 GA 脚本(NEXT_PUBLIC_GA_MEASUREMENT_ID 为空)",
|
||||
"project": "",
|
||||
"suite": "ga4-event-tracking.spec.ts",
|
||||
"fullName": "ga4-event-tracking.spec.ts:234:7",
|
||||
"name": "TC-GA4-004: 页面浏览追踪 - 客户端路由跳转触发带 page_path 的 config"
|
||||
},
|
||||
{
|
||||
"file": "2c6ec67e-4473-4796-a81b-d51ec9bef653-result.json",
|
||||
"mtime": "2026-09-22T04:05:29.786Z",
|
||||
"status": "skipped",
|
||||
"reason": "Touchscreen API only available in Chromium",
|
||||
"project": "",
|
||||
"suite": "p3-compatibility.spec.ts",
|
||||
"fullName": "p3-compatibility.spec.ts:226:7",
|
||||
"name": "触摸滑动流畅(无卡顿)"
|
||||
},
|
||||
{
|
||||
"file": "50fe3c7c-8d10-49b1-800d-cf504f89511f-result.json",
|
||||
"mtime": "2026-09-22T04:15:12.200Z",
|
||||
"status": "skipped",
|
||||
"reason": "Touchscreen API only available in Chromium",
|
||||
"project": "",
|
||||
"suite": "p3-compatibility.spec.ts",
|
||||
"fullName": "p3-compatibility.spec.ts:226:7",
|
||||
"name": "触摸滑动流畅(无卡顿)"
|
||||
},
|
||||
{
|
||||
"file": "da7b926e-4c87-4ca5-9b21-4b4d9eb0ff4a-result.json",
|
||||
"mtime": "2026-09-22T04:10:56.093Z",
|
||||
"status": "skipped",
|
||||
"reason": "Touchscreen API only available in Chromium",
|
||||
"project": "",
|
||||
"suite": "p3-compatibility.spec.ts",
|
||||
"fullName": "p3-compatibility.spec.ts:226:7",
|
||||
"name": "触摸滑动流畅(无卡顿)"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user