修复:统一主题切换并升级依赖与验证流程
This commit is contained in:
1 parent
22163a8b51
commit
bcb47f102c
6 files changed
+146
-21
No files matched your search
@@ -0,0 +1,35 @@
|
|||||||
|
# 仅做前端验证,不包含发布、服务器登录或生产凭证。
|
||||||
|
name: 前端验证
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
verify:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 15
|
||||||
|
steps:
|
||||||
|
- name: 获取源码
|
||||||
|
uses: https://github.com/actions/checkout@v4
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: 准备 Node.js
|
||||||
|
uses: https://github.com/actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "22"
|
||||||
|
cache: npm
|
||||||
|
- name: 安装锁定依赖
|
||||||
|
run: npm ci
|
||||||
|
- name: 安装测试浏览器
|
||||||
|
run: npx playwright install --with-deps chromium
|
||||||
|
- name: 检查源码并构建
|
||||||
|
run: |
|
||||||
|
npm run check
|
||||||
|
npm run build
|
||||||
|
- name: 验收真实生产构建
|
||||||
|
run: |
|
||||||
|
task_chrome_path="$(node --input-type=module -e 'import { chromium } from "playwright"; process.stdout.write(chromium.executablePath())')"
|
||||||
|
CHROME_PATH="$task_chrome_path" npm test
|
||||||
|
# deepmerge 尚无上游修复版本;低危传播项保留在审计输出,不通过降级框架隐藏。
|
||||||
|
- name: 阻止中危及以上依赖风险
|
||||||
|
run: npm audit --audit-level=moderate
|
||||||
@@ -123,10 +123,19 @@ npm test
|
|||||||
CHROME_PATH=/absolute/path/to/chrome npm test
|
CHROME_PATH=/absolute/path/to/chrome npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
现有 21 个离线场景覆盖登录协议、短信倒计时、路由保护、会话失效、双标签页退出、SSH 密钥管理、
|
离线场景覆盖登录协议、短信倒计时、路由保护、会话失效、双标签页退出、SSH 密钥管理、
|
||||||
请求超时、支付期限及旧登录入口等流程。测试产物保存在被忽略的 `tests/fixtures/runs/`。
|
请求超时、支付期限及旧登录入口,并逐步补充安全组、工单、镜像购买和商品字段回归。
|
||||||
|
测试产物保存在被忽略的 `tests/fixtures/runs/`。
|
||||||
详细使用方式见 [测试说明](tests/README.md)。
|
详细使用方式见 [测试说明](tests/README.md)。
|
||||||
|
|
||||||
|
仓库包含 `.gitea/workflows/frontend.yml`:安装锁定依赖后运行源码检查、生产构建、浏览器测试和
|
||||||
|
`npm audit --audit-level=moderate`,不执行部署。Git 服务需启用 Actions 并配置兼容的 Linux runner;
|
||||||
|
仅提交工作流不代表远端任务已经运行通过。
|
||||||
|
|
||||||
|
传递依赖 `glob` 与 `minimatch` 通过精确 overrides 使用修复版本。
|
||||||
|
截至 2026-11-06,`deepmerge` 的 GHSA-gcqx-w48m-w2h4 尚无已发布修复版本,低危传播告警仍保留,
|
||||||
|
未用强制降级 Nuxt 或关闭审计来隐藏。禁止把通过中危及以上门禁解读为依赖零风险。
|
||||||
|
|
||||||
真实支付、第三方登录 / CAPTCHA、安全挑战、短信邮件投递、供应商接口和 VNC 网关仍需在测试环境联调。
|
真实支付、第三方登录 / CAPTCHA、安全挑战、短信邮件投递、供应商接口和 VNC 网关仍需在测试环境联调。
|
||||||
|
|
||||||
## 维护与交付说明
|
## 维护与交付说明
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ onMounted(() => siteConfig.load().catch(() => {}));
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- Keep the published CSS scope until its shared auth styles are migrated together. -->
|
<!-- 共享认证样式迁移前保留发布版作用域;主题入口遵循全站浅色/深色/跟随系统三态。 -->
|
||||||
<div class="blank-layout" data-v-69ca9392>
|
<div class="blank-layout" data-v-69ca9392>
|
||||||
<header class="auth-topbar" data-v-69ca9392>
|
<header class="auth-topbar" data-v-69ca9392>
|
||||||
<NuxtLink to="/" class="auth-logo" data-v-69ca9392>
|
<NuxtLink to="/" class="auth-logo" data-v-69ca9392>
|
||||||
@@ -29,14 +29,12 @@ onMounted(() => siteConfig.load().catch(() => {}));
|
|||||||
<button
|
<button
|
||||||
class="auth-theme"
|
class="auth-theme"
|
||||||
type="button"
|
type="button"
|
||||||
:aria-label="theme.isDark.value ? '切换浅色模式' : '切换深色模式'"
|
:aria-label="`切换主题,当前${theme.label.value}`"
|
||||||
|
:title="`主题:${theme.label.value}(点击切换)`"
|
||||||
data-v-69ca9392
|
data-v-69ca9392
|
||||||
@click="theme.cycle"
|
@click="theme.cycle"
|
||||||
>
|
>
|
||||||
<i
|
<i :class="theme.icon.value" data-v-69ca9392 />
|
||||||
:class="theme.isDark.value ? 'pi pi-moon' : 'pi pi-sun'"
|
|
||||||
data-v-69ca9392
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
v-if="route.path !== '/login'"
|
v-if="route.path !== '/login'"
|
||||||
|
|||||||
Generated
+20
-13
@@ -1076,6 +1076,12 @@
|
|||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@isaacs/nonrecursive-glob-match": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@isaacs/nonrecursive-glob-match/-/nonrecursive-glob-match-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-SI7kyKHq4XXDRozw+r9GlRZkia1ZkFrpLW98r2IC2Bpr8YkFGE3fvjzmxCG0x78A++69HmDNrDvSMYBZmHGpKA==",
|
||||||
|
"license": "BlueOak-1.0.0"
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.13",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||||
@@ -4744,14 +4750,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/glob": {
|
"node_modules/glob": {
|
||||||
"version": "13.0.6",
|
"version": "14.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-14.0.3.tgz",
|
||||||
"integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
|
"integrity": "sha512-A1vjIwC3qpdCso45Iw127gnp7sPhqgY8lUQhDrArIs+GbmfaaVPFuoyy7WyLT9EPZCRZ7j7aLdwUhQmHWesEow==",
|
||||||
"license": "BlueOak-1.0.0",
|
"license": "BlueOak-1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimatch": "^10.2.2",
|
"minimatch": "^11.0.2",
|
||||||
"minipass": "^7.1.3",
|
"minipass": "^7.1.3",
|
||||||
"path-scurry": "^2.0.2"
|
"path-scurry": "^3.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "18 || 20 || >=22"
|
"node": "18 || 20 || >=22"
|
||||||
@@ -5838,15 +5844,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "10.2.6",
|
"version": "11.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-11.0.4.tgz",
|
||||||
"integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
|
"integrity": "sha512-/UJ1dEoVQTjPNDh6SGlUo+ueLMmoHTas4q+8yaAR/5t6nLAIiBDJtoYUh20IYleix7ehiQkgczb84PE3uzHkxg==",
|
||||||
"license": "BlueOak-1.0.0",
|
"license": "BlueOak-1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^5.0.8"
|
"@isaacs/nonrecursive-glob-match": "^1.0.3",
|
||||||
|
"brace-expansion": "^5.0.12"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "18 || 20 || >=22"
|
"node": "20 || >=22"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
@@ -6598,9 +6605,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/path-scurry": {
|
"node_modules/path-scurry": {
|
||||||
"version": "2.0.2",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-3.0.0.tgz",
|
||||||
"integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
|
"integrity": "sha512-1pTbQqH1wIwMi/eleQ5leFTTCkzFsPcgXNjwOA8YGGW/W4/kHT3dssE7Z6NH+zuqNLOzOB0uaD61yl7cAcVhgg==",
|
||||||
"license": "BlueOak-1.0.0",
|
"license": "BlueOak-1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lru-cache": "^11.0.0",
|
"lru-cache": "^11.0.0",
|
||||||
|
|||||||
@@ -38,6 +38,10 @@
|
|||||||
"playwright": "^1.64.1",
|
"playwright": "^1.64.1",
|
||||||
"prettier": "^3.8.0"
|
"prettier": "^3.8.0"
|
||||||
},
|
},
|
||||||
|
"overrides": {
|
||||||
|
"glob": "14.0.3",
|
||||||
|
"minimatch": "11.0.4"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.12.0"
|
"node": ">=22.12.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* 认证页复用全站三态主题协议;按钮必须如实说明当前模式,不能承诺下一次一定变深/浅色。
|
||||||
|
*/
|
||||||
|
import assert from "node:assert/strict";
|
||||||
|
import { test } from "node:test";
|
||||||
|
import { appOrigin, scenario } from "./helpers/console-browser.mjs";
|
||||||
|
|
||||||
|
test(
|
||||||
|
"auth theme control describes and persists the shared three-mode cycle",
|
||||||
|
{ timeout: 20000 },
|
||||||
|
(t) =>
|
||||||
|
scenario(t, {}, async (page) => {
|
||||||
|
await page.emulateMedia({ colorScheme: "light" });
|
||||||
|
await page.goto(`${appOrigin}/login`);
|
||||||
|
const themeButton = page.getByRole("button", {
|
||||||
|
name: "切换主题,当前跟随系统",
|
||||||
|
exact: true,
|
||||||
|
});
|
||||||
|
await themeButton.waitFor();
|
||||||
|
assert.equal(
|
||||||
|
await page
|
||||||
|
.locator("html")
|
||||||
|
.evaluate((html) => html.classList.contains("app-dark")),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
await themeButton.click();
|
||||||
|
await page
|
||||||
|
.getByRole("button", { name: "切换主题,当前浅色", exact: true })
|
||||||
|
.waitFor();
|
||||||
|
assert.equal(
|
||||||
|
await page.evaluate(() => localStorage.getItem("theme")),
|
||||||
|
"light",
|
||||||
|
);
|
||||||
|
await page
|
||||||
|
.getByRole("button", { name: "切换主题,当前浅色", exact: true })
|
||||||
|
.click();
|
||||||
|
await page
|
||||||
|
.getByRole("button", { name: "切换主题,当前深色", exact: true })
|
||||||
|
.waitFor();
|
||||||
|
assert.equal(
|
||||||
|
await page
|
||||||
|
.locator("html")
|
||||||
|
.evaluate((html) => html.classList.contains("app-dark")),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
await page.reload();
|
||||||
|
await page
|
||||||
|
.getByRole("button", { name: "切换主题,当前深色", exact: true })
|
||||||
|
.waitFor();
|
||||||
|
await page
|
||||||
|
.getByRole("button", { name: "切换主题,当前深色", exact: true })
|
||||||
|
.click();
|
||||||
|
await page
|
||||||
|
.getByRole("button", { name: "切换主题,当前跟随系统", exact: true })
|
||||||
|
.waitFor();
|
||||||
|
assert.equal(
|
||||||
|
await page
|
||||||
|
.locator("html")
|
||||||
|
.evaluate((html) => html.classList.contains("app-dark")),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
await page.emulateMedia({ colorScheme: "dark" });
|
||||||
|
await page.waitForFunction(() =>
|
||||||
|
document.documentElement.classList.contains("app-dark"),
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
currentModeDescribed: true,
|
||||||
|
explicitModePersisted: true,
|
||||||
|
automaticModeTracksSystem: true,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
Reference in new issue
Block a user