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