| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- /**
- * 灰度切换冒烟:确认 **Vue 产物经网关可达**、且这份产物确实是"10 页签"的那一份。
- *
- * 说明(如实):本机没有浏览器自动化,jsdom 也不能执行 Vite 打出的 ESM 包,
- * 所以这里做的是**产物级**验证:
- * ① `/web/index.html` 200 且引用构建产物;
- * ② 该产物里含全部 10 个页签标签(取自语言包)与 10 个视图组件名;
- * ③ SPA 依赖的接口面(`/api/fleet` 等)经网关可达。
- * 浏览器内的真实交互回归不在此覆盖 —— 由 SSR 对拍(10 页签全绿)承担"呈现一致"的证明。
- *
- * 用法:node tools/spa_smoke.mjs http://127.0.0.1:28084
- */
- const GATEWAY = (process.argv[2] || 'http://127.0.0.1:28084').replace(/\/$/, '')
- // 页签标签**以现网语言包为准**(`window.__L` 的 `tab.<id>`)—— 不硬编码,避免拿猜测值当判据
- const TAB_IDS = ['overview', 'energy', 'component', 'fault', 'vibration', 'generation', 'decision', 'assistant', 'report', 'system', 'documents', 'recalc']
- const pageHtml = await (await fetch(`${GATEWAY}/detail/v2`)).text()
- const langJson = pageHtml.slice(pageHtml.indexOf('window.__L'), pageHtml.indexOf('window.__L') + 400000)
- const TABS10 = TAB_IDS.map((id) => {
- const m = langJson.match(new RegExp(`"tab\\.${id}":\\s*"([^"]+)"`))
- return m ? m[1] : id
- })
- const COMPONENTS = ['Overview', 'Energy', 'Component', 'Fault', 'Vibration', 'Generation', 'Decision', 'Assistant', 'Report', 'System']
- let bad = 0
- const ok = (cond, msg, extra = '') => {
- console.log(`${cond ? '[OK]' : '[X] '} ${msg}${extra ? ' —— ' + extra : ''}`)
- if (!cond) bad++
- }
- // ① index.html
- const idx = await fetch(`${GATEWAY}/web/index.html`)
- ok(idx.ok, `/web/index.html 可达`, `HTTP ${idx.status}`)
- const html = await idx.text()
- const srcs = [...html.matchAll(/<script[^>]+src="([^"]+)"/g)].map((m) => m[1])
- const links = [...html.matchAll(/<link[^>]+href="([^"]+)"/g)].map((m) => m[1])
- ok(srcs.length > 0, 'index.html 引用了脚本', srcs.join(', ').slice(0, 120))
- // ② 产物内容:10 个页签 + 10 个视图
- let bundleText = ''
- for (const s of srcs) {
- const u = s.startsWith('http') ? s : `${GATEWAY}/web/${s.replace(/^\.?\//, '')}`
- const r = await fetch(u)
- ok(r.ok, `脚本可达 ${s.slice(0, 48)}`, `HTTP ${r.status}`)
- if (r.ok) bundleText += await r.text()
- }
- for (const l of links) {
- const u = l.startsWith('http') ? l : `${GATEWAY}/web/${l.replace(/^\.?\//, '')}`
- const r = await fetch(u)
- ok(r.ok, `样式可达 ${l.slice(0, 40)}`, `HTTP ${r.status}`)
- }
- const missingTabs = TABS10.filter((x) => !bundleText.includes(x))
- ok(missingTabs.length === 0, '产物含全部 10 个页签标签(取自语言包)', missingTabs.length ? '缺: ' + missingTabs.join('/') : `${TABS10.length}/10 · ${TABS10.join('/')}`)
- const missingCmp = COMPONENTS.filter((x) => !bundleText.includes(x))
- ok(missingCmp.length === 0, '产物含全部 10 个视图组件', missingCmp.length ? '缺: ' + missingCmp.join('/') : `${COMPONENTS.length}/10`)
- // ③ SPA 依赖的接口面
- for (const p of ['/api/fleet', '/algorithm/healthz']) {
- const r = await fetch(`${GATEWAY}${p}`)
- ok(r.ok, `接口可达 ${p}`, `HTTP ${r.status}`)
- }
- console.log(`\n结论: ${bad === 0 ? 'Vue 产物经网关可作并列入口(灰度第一步就绪)' : bad + ' 项未通过'}`)
- process.exit(bad === 0 ? 0 : 1)
|