/** * 深色模式 logo 对比:生产 vs 本地 * 强制 prefers-color-scheme: dark,截 header logo */ import { chromium } from 'playwright'; import fs from 'node:fs'; import path from 'node:path'; const OUT = path.join(process.cwd(), 'dogfood-ui-audit', 'logo-compare'); fs.mkdirSync(OUT, { recursive: true }); const TARGETS = [ { tag: 'prod-dark', url: 'https://www.novalon.cn/' }, { tag: 'local-dark', url: 'http://127.0.0.1:3000/' }, ]; const browser = await chromium.launch(); for (const t of TARGETS) { const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 2, colorScheme: 'dark', // 强制深色模式 }); const page = await ctx.newPage(); try { await page.goto(t.url, { waitUntil: 'networkidle', timeout: 60000 }); await page.waitForTimeout(1500); // 1) 截 header const header = page.locator('header').first(); await header.screenshot({ path: path.join(OUT, `${t.tag}-header.png`) }).catch(async () => { await page.screenshot({ path: path.join(OUT, `${t.tag}-header.png`), clip: { x: 0, y: 0, width: 1440, height: 80 } }); }); // 2) 探测 logo 元素的可视状态(在深色背景下) const info = await page.evaluate(() => { const imgs = [...document.querySelectorAll('img')].filter(i => /logo\.svg$/.test(i.getAttribute('src') || '')); return imgs.map(i => { const r = i.getBoundingClientRect(); const cs = getComputedStyle(i); const parentCs = getComputedStyle(i.closest('header') || document.body); return { src: i.getAttribute('src'), renderedW: Math.round(r.width), renderedH: Math.round(r.height), filter: cs.filter, opacity: cs.opacity, visibility: cs.visibility, parentBg: parentCs.backgroundColor, htmlBg: getComputedStyle(document.documentElement).backgroundColor, }; }); }); console.log(`[${t.tag}]`); for (const l of info) console.log(' ' + JSON.stringify(l)); } catch (e) { console.log(`[${t.tag}] FAILED ${e.message.slice(0, 120)}`); } await ctx.close(); } await browser.close(); console.log('\n✓ 输出目录:' + OUT);