plugins/navManager:导航 CRUD + 导航分类 CRUD(独立 blueprint) plugins/friendManager:友情链接 CRUD plugins/aboutManager:关于本站 CRUD plugins/siteStats:访问统计主页 + JSON 接口 + /site/* GET 埋点 + nav 卡片点击埋点 applications/view/public/nav.py:导航聚合页 / 分类详情 / JSON 接口,支持 visit_count 注入 applications/view/public/about.py:关于本站公开页 applications/view/public/friend.py:友情链接公开页 templates/public/base.html:响应式首页(搜索框 / 分类抽屉 / 5 主题切换 / footer 隐私小字) templates/public/index.html / category.html:卡片右下角访问次数 templates/public/about.html / friend.html:关于 + 友链前台页 docs/plugins-development.md:插件开发完整指南(生命周期 + 4 个示例 + FAQ + framework 迁移) scripts/:探针与端到端验证脚本(probe_*/verify_*/test_*)
75 lines
3.7 KiB
Python
75 lines
3.7 KiB
Python
"""A+E 主题自适应验证(每个场景前清 localStorage)"""
|
||
from playwright.sync_api import sync_playwright
|
||
|
||
with sync_playwright() as pw:
|
||
browser = pw.chromium.launch(headless=True, args=['--no-sandbox', '--disable-gpu'])
|
||
ctx = browser.new_context(viewport={'width':1440,'height':900})
|
||
page = ctx.new_page()
|
||
|
||
msgs = []
|
||
page.on('pageerror', lambda e: msgs.append(f'[ERR] {e}'))
|
||
|
||
# 场景 1:saved=auto + system=light → 应 default
|
||
page.goto('http://127.0.0.1:5000/', wait_until='networkidle')
|
||
page.evaluate('localStorage.setItem("bw-theme", "auto")')
|
||
page.reload(wait_until='networkidle')
|
||
page.wait_for_timeout(500)
|
||
theme = page.evaluate('document.documentElement.getAttribute("data-theme")')
|
||
label = page.locator('#theme-toggle-label').inner_text()
|
||
sys_dark = page.evaluate('window.matchMedia("(prefers-color-scheme: dark)").matches')
|
||
print(f'[1] saved=auto, system_dark={sys_dark} -> data-theme={theme!r}, label={label!r} (expect default, "跟随系统")')
|
||
|
||
# 场景 2:saved=dark + system=light → 应 dark
|
||
page.evaluate('localStorage.setItem("bw-theme", "dark")')
|
||
page.reload(wait_until='networkidle')
|
||
page.wait_for_timeout(500)
|
||
theme = page.evaluate('document.documentElement.getAttribute("data-theme")')
|
||
label = page.locator('#theme-toggle-label').inner_text()
|
||
print(f'[2] saved=dark, system_dark={sys_dark} -> data-theme={theme!r}, label={label!r} (expect dark, "暗色")')
|
||
|
||
# 场景 3:saved=default → 应 default
|
||
page.evaluate('localStorage.setItem("bw-theme", "default")')
|
||
page.reload(wait_until='networkidle')
|
||
page.wait_for_timeout(500)
|
||
theme = page.evaluate('document.documentElement.getAttribute("data-theme")')
|
||
label = page.locator('#theme-toggle-label').inner_text()
|
||
print(f'[3] saved=default -> data-theme={theme!r}, label={label!r} (expect default, "蓝绿")')
|
||
|
||
# 场景 4:无 localStorage + system=light → 应 default(不持久化为 auto)
|
||
page.evaluate('localStorage.removeItem("bw-theme")')
|
||
page.reload(wait_until='networkidle')
|
||
page.wait_for_timeout(500)
|
||
theme = page.evaluate('document.documentElement.getAttribute("data-theme")')
|
||
label = page.locator('#theme-toggle-label').inner_text()
|
||
saved_after = page.evaluate('localStorage.getItem("bw-theme")')
|
||
print(f'[4] no saved, system_dark={sys_dark} -> data-theme={theme!r}, label={label!r}, after-save={saved_after!r}')
|
||
print(f' (system=light 时应 default,不写 auto;只有 system=dark 才写 auto)')
|
||
|
||
# 场景 5:从 sunset 点 auto → 应 default + label="跟随系统" + saved=auto
|
||
page.evaluate('localStorage.setItem("bw-theme", "sunset")')
|
||
page.reload(wait_until='networkidle')
|
||
page.wait_for_timeout(500)
|
||
page.click('#theme-toggle')
|
||
page.wait_for_timeout(300)
|
||
page.click('.theme-menu li[data-theme="auto"]')
|
||
page.wait_for_timeout(500)
|
||
theme = page.evaluate('document.documentElement.getAttribute("data-theme")')
|
||
label = page.locator('#theme-toggle-label').inner_text()
|
||
saved = page.evaluate('localStorage.getItem("bw-theme")')
|
||
print(f'[5] click auto -> data-theme={theme!r}, label={label!r}, saved={saved!r} (expect default, "跟随系统", auto)')
|
||
|
||
# 场景 6:早期脚本无闪烁(head 检查 data-theme 在脚本运行前已设)
|
||
page.evaluate('localStorage.setItem("bw-theme", "dark")')
|
||
early_attr = page.evaluate('''
|
||
() => {
|
||
return new Promise(resolve => {
|
||
const iframe = document.createElement('iframe');
|
||
// 没法直接测 early-script 在主页面执行前的状态,改用:再次模拟 reload 看 meta
|
||
resolve(null);
|
||
});
|
||
}
|
||
''')
|
||
|
||
print()
|
||
print('JS errors:', msgs[-5:])
|
||
browser.close() |