- 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 产物装配与部署形态。
73 lines
3.6 KiB
Bash
73 lines
3.6 KiB
Bash
#!/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"
|