From 80a0efbcfebd51d09cb837a3a131fcd375499158 Mon Sep 17 00:00:00 2001 From: LoveChengke Date: Sat, 12 Sep 2026 21:06:58 +0800 Subject: [PATCH] =?UTF-8?q?fix(smoke):=20=E5=86=92=E7=83=9F=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E6=82=84=E6=82=84=E6=94=B9=E6=8E=89=E6=BC=94=E7=A4=BA?= =?UTF-8?q?=E7=8F=AD=E7=BA=A7=E5=AF=86=E7=A0=81=EF=BC=88=E5=85=88=E8=AF=95?= =?UTF-8?q?=E5=B7=B2=E7=9F=A5=E5=AF=86=E7=A0=81=EF=BC=8C=E5=BF=85=E8=A6=81?= =?UTF-8?q?=E6=97=B6=E6=89=8D=E9=87=8D=E7=BD=AE=E5=B9=B6=E6=81=A2=E5=A4=8D?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 现状问题:pnpm verify:desktop 会用管理员接口把被测班级密码改成 smoke123456 且不恢复, 导致演示实例的「班级码 G101 / 123456」在跑完冒烟后登录失败(本次验证时实际踩到)。 - 现在先按 [冒烟密码, 种子默认 123456] 依次探测:命中就直接用,**完全不改数据**; 只有当两者都不通时才临时重置,并在脚本收尾(含失败分支)恢复为 123456 并打印日志。 - README 冒烟章节补充说明;演示实例的 G101 密码已恢复为 123456。 验证:verify:desktop 62/62(日志显示「班级账号就绪:G101」即未改动数据)、离线复跑 56/56; 打包便携版 62/62(packaged=true)且跑完后 G101/123456 仍可登录。 --- README.md | 2 + packages/desktop-client/scripts/smoke.mjs | 57 +++++++++++++++++++---- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 14b85c7..e3feb21 100644 --- a/README.md +++ b/README.md @@ -569,6 +569,8 @@ pnpm dist:win # nsis 安装包 + portable 单文件(需联网下载 NSIS `ISLAND_SHOTS_DIR`(默认 `.cache/island-shots/`,仓库内留档目录 `docs/screenshots/island/`), 并对尺寸、宽高比、绘制内容(不透明像素/颜色种类)、紧急态红色像素与外溢红光做断言。 冒烟进程使用独立 userData(`ELECTRON_SMOKE_PROFILE`),因此**用户开着客户端也能跑验证**。 +冒烟准备班级凭据时**不改任何数据**:先试冒烟密码与种子默认 `123456`,命中就直接用; +都不通才会临时重置该班密码,并在脚本收尾时恢复为 `123456`(日志会打印"已恢复班级密码…冒烟不留副作用")。 ## 叫人(老师点名让学生过来) diff --git a/packages/desktop-client/scripts/smoke.mjs b/packages/desktop-client/scripts/smoke.mjs index b7cb7a7..9662955 100644 --- a/packages/desktop-client/scripts/smoke.mjs +++ b/packages/desktop-client/scripts/smoke.mjs @@ -59,14 +59,24 @@ if (online === undefined) { /** * 准备一个已知可用的班级账号(学生端已改为班级码 + 班级密码登录): - * 用管理员账号登录 → 取第一个班级 → 重置成冒烟专用密码(必要时补一个班级码)。 - * 这样无论被测实例是全新安装还是升级安装,冒烟都能拿到可用凭据。 + * 用管理员账号登录 → 取第一个班级 → 先试"已知密码"(冒烟密码 / 种子默认 123456), + * 命中就直接用、**不改动任何数据**;都不行才把该班重置成冒烟专用密码, + * 并在脚本收尾时恢复为种子默认密码(避免把演示实例的 123456 悄悄改掉)。 */ async function provisionClassAccount() { const base = process.env.ELECTRON_SMOKE_API ?? 'http://127.0.0.1:4000/api'; const username = process.env.ELECTRON_SMOKE_ADMIN ?? 'admin'; const adminPassword = process.env.ELECTRON_SMOKE_ADMIN_PASSWORD ?? 'admin123'; const password = process.env.ELECTRON_SMOKE_CLASS_PASSWORD ?? 'smoke123456'; + const CANDIDATES = [...new Set([password, process.env.ELECTRON_SMOKE_SEED_PASSWORD ?? '123456'])]; + const tryLogin = async (code, candidate) => { + const response = await fetch(`${base}/auth/class-login`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ code, password: candidate }), + }); + return response.ok; + }; try { const loginResponse = await fetch(`${base}/auth/login`, { method: 'POST', @@ -84,16 +94,13 @@ async function provisionClassAccount() { if (!target) return null; // 冒烟**永不修改班级码**(班级码是给学生用的,不应被测试工具改写): - // 只有"现有班级码 + 目标密码登录失败"时才重置密码,班级码原样保留。 + // 只有"现有班级码 + 已知密码全部登录失败"时才重置密码,班级码原样保留。 const code = target.code; if (!code) return null; - const probe = await fetch(`${base}/auth/class-login`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ code, password }), - }); - if (probe.ok) return { code, password, className: target.name }; + for (const candidate of CANDIDATES) { + if (await tryLogin(code, candidate)) return { code, password: candidate, className: target.name }; + } const patchResponse = await fetch(`${base}/classes/${target.id}/class-account`, { method: 'PATCH', @@ -103,12 +110,43 @@ async function provisionClassAccount() { if (!patchResponse.ok) return null; const patched = (await patchResponse.json())?.data; + // 记下"需要恢复",脚本收尾时改回种子默认密码(已知密码都不通时无法得知原密码) + patchedAccount = { id: target.id, code: patched?.code ?? code, base, authHeaders }; + console.log( + `[smoke] 已知密码均不可用,已把班级 ${target.name} 的密码临时重置为 ${password}` + + `(结束时恢复为 ${CANDIDATES[1]})`, + ); return { code: patched?.code ?? code, password, className: target.name }; } catch { return null; } } +/** 冒烟临时重置过的班级账号(结束时恢复) */ +let patchedAccount = null; + +/** 恢复被冒烟临时改过的班级密码(失败只告警,不影响冒烟结论) */ +async function restoreClassAccount() { + if (!patchedAccount) return; + try { + const response = await fetch(`${patchedAccount.base}/classes/${patchedAccount.id}/class-account`, { + method: 'PATCH', + headers: patchedAccount.authHeaders, + body: JSON.stringify({ + code: patchedAccount.code, + password: process.env.ELECTRON_SMOKE_SEED_PASSWORD ?? '123456', + }), + }); + console.log( + response.ok + ? '[smoke] 已恢复班级密码为种子默认 123456(冒烟不留副作用)' + : `[smoke] [WARN] 班级密码恢复失败:status=${response.status},请到后台重新设置`, + ); + } catch (error) { + console.log(`[smoke] [WARN] 班级密码恢复失败:${error?.message ?? error}`); + } +} + let classCredentials = null; if (online === '1') { classCredentials = await provisionClassAccount(); @@ -140,6 +178,7 @@ function launchSmoke(extraEnv) { const code = await launchSmoke(); console.log(`\n[smoke] Electron 退出,code=${code}`); +await restoreClassAccount(); if (code !== 0) process.exit(code); /**