chore: preserve step-aware logging after upstream sync

- 吸收 master 的核心改动:按可见步骤归类日志显示,覆盖 OAuth、手机号验证、平台验证和内容脚本日志链路。

- 本地补充修复:保留平台验证成功后的手机号接码确认收尾,避免 #193/#194 恢复的手机号复用链路被合并覆盖。

- 影响范围:background routing、phone verification、platform verify、content scripts、sidepanel 与相关测试/文档。
This commit is contained in:
QLHazyCoder
2026-05-04 04:41:49 +08:00
25 changed files with 690 additions and 290 deletions
+16 -6
View File
@@ -773,8 +773,8 @@ ${bundle}
return { refreshOAuthUrlBeforeStep6 };
`)();
globalThis.addLog = async (message) => {
calls.push({ type: 'log', message });
globalThis.addLog = async (message, level, options) => {
calls.push({ type: 'log', message, level, options });
};
globalThis.contributionOAuthManager = {
async startContributionFlow(options) {
@@ -801,7 +801,12 @@ return { refreshOAuthUrlBeforeStep6 };
assert.equal(oauthUrl, 'https://auth.example.com/oauth?state=oauth-state-001');
assert.deepStrictEqual(calls, [
{ type: 'log', message: '步骤 7contributionMode=true,走公开贡献接口,正在申请 OAuth 登录地址...' },
{
type: 'log',
message: 'contributionMode=true,走公开贡献接口,正在申请 OAuth 登录地址...',
level: 'info',
options: { step: 7, stepKey: 'oauth-login' },
},
{
type: 'contribution',
options: {
@@ -839,8 +844,8 @@ ${bundle}
return { refreshOAuthUrlBeforeStep6 };
`)();
globalThis.addLog = async (message) => {
calls.push({ type: 'log', message });
globalThis.addLog = async (message, level, options) => {
calls.push({ type: 'log', message, level, options });
};
globalThis.contributionOAuthManager = {
async startContributionFlow() {
@@ -868,7 +873,12 @@ return { refreshOAuthUrlBeforeStep6 };
assert.equal(oauthUrl, 'https://panel.example.com/oauth');
assert.deepStrictEqual(calls, [
{ type: 'log', message: '步骤 7contributionMode=false,走普通 CPA / SUB2API / Codex2API 链路(当前面板:SUB2API),正在刷新 OAuth 登录地址...' },
{
type: 'log',
message: 'contributionMode=false,走普通 CPA / SUB2API / Codex2API 链路(当前面板:SUB2API),正在刷新 OAuth 登录地址...',
level: 'info',
options: { step: 7, stepKey: 'oauth-login' },
},
{ type: 'panel' },
{
type: 'step',
@@ -21,8 +21,8 @@ function createRouter(overrides = {}) {
};
const router = api.createMessageRouter({
addLog: async (message, level) => {
events.logs.push({ message, level });
addLog: async (message, level, options = {}) => {
events.logs.push({ message, level, step: options.step, stepKey: options.stepKey });
},
appendAccountRunRecord: async () => null,
batchUpdateLuckmailPurchases: async () => {},
@@ -352,7 +352,7 @@ test('message router marks step 3 failed when post-submit finalize fails', async
error: '步骤 3 提交后仍停留在密码页。',
},
]);
assert.equal(events.logs.some(({ message }) => /步骤 3 失败步骤 3 提交后仍停留在密码页/.test(message)), true);
assert.equal(events.logs.some(({ message, step }) => /失败步骤 3 提交后仍停留在密码页/.test(message) && step === 3), true);
assert.deepStrictEqual(response, { ok: true, error: '步骤 3 提交后仍停留在密码页。' });
});
@@ -30,8 +30,8 @@ test('platform verify module supports codex2api protocol callback exchange', asy
const completed = [];
const logs = [];
const executor = api.createStep10Executor({
addLog: async (message, level = 'info') => {
logs.push({ message, level });
addLog: async (message, level = 'info', options = {}) => {
logs.push({ message, level, step: options.step, stepKey: options.stepKey });
},
chrome: {},
closeConflictingTabsForSource: async () => {},
@@ -63,8 +63,8 @@ test('platform verify module supports codex2api protocol callback exchange', asy
});
assert.deepStrictEqual(logs, [
{ message: '步骤 10正在向 Codex2API 提交回调并创建账号...', level: 'info' },
{ message: '步骤 10OAuth 账号 flow@example.com 添加成功', level: 'ok' },
{ message: '正在向 Codex2API 提交回调并创建账号...', level: 'info', step: 10, stepKey: 'platform-verify' },
{ message: 'OAuth 账号 flow@example.com 添加成功', level: 'ok', step: 10, stepKey: 'platform-verify' },
]);
assert.deepStrictEqual(completed, [
{
@@ -8,8 +8,8 @@ function createDeps(overrides = {}) {
const uiCalls = [];
const deps = {
addLog: async (message, level = 'info') => {
logs.push({ message, level });
addLog: async (message, level = 'info', options = {}) => {
logs.push({ message, level, step: options.step, stepKey: options.stepKey });
},
chrome: {
tabs: {
@@ -91,8 +91,8 @@ test('platform verify module submits CPA callback via management API first', asy
},
]);
assert.deepStrictEqual(logs, [
{ message: '步骤 10正在通过 CPA 管理接口提交回调地址...', level: 'info' },
{ message: '步骤 10CPA API 回调提交成功', level: 'ok' },
{ message: '正在通过 CPA 管理接口提交回调地址...', level: 'info', step: 10, stepKey: 'platform-verify' },
{ message: 'CPA API 回调提交成功', level: 'ok', step: 10, stepKey: 'platform-verify' },
]);
} finally {
globalThis.fetch = originalFetch;
@@ -160,8 +160,10 @@ test('platform verify module fails fast when CPA API submit fails', async () =>
assert.equal(uiCalls.length, 0);
assert.equal(completed.length, 0);
assert.equal(logs[0].message, '步骤 10正在通过 CPA 管理接口提交回调地址...');
assert.match(logs[1].message, /步骤 10CPA 接口提交失败:failed to persist oauth callback/);
assert.equal(logs[0].message, '正在通过 CPA 管理接口提交回调地址...');
assert.equal(logs[0].step, 10);
assert.match(logs[1].message, /CPA 接口提交失败:failed to persist oauth callback/);
assert.equal(logs[1].step, 10);
assert.equal(logs[1].level, 'error');
} finally {
globalThis.fetch = originalFetch;
+9 -8
View File
@@ -4133,8 +4133,8 @@ test('phone verification helper logs no-supply diagnostics with consecutive stre
};
const helpers = api.createPhoneVerificationHelpers({
addLog: async (message, level = 'info') => {
logs.push({ message, level });
addLog: async (message, level = 'info', options = {}) => {
logs.push({ message, level, options });
},
ensureStep8SignupPageReady: async () => {},
fetchImpl: async (url) => {
@@ -4180,18 +4180,19 @@ test('phone verification helper logs no-supply diagnostics with consecutive stre
await runOnce();
const diagnosticsLogs = logs
.filter((entry) => String(entry.message || '').includes('Step 9 diagnostics: 无号连续失败'))
.map((entry) => String(entry.message || ''));
.filter((entry) => String(entry.message || '').includes('diagnostics: 无号连续失败'));
assert.equal(diagnosticsLogs.length >= 2, true);
assert.equal(diagnosticsLogs.some((message) => message.includes('无号连续失败 1 次')), true);
assert.equal(diagnosticsLogs.some((message) => message.includes('无号连续失败 2 次')), true);
assert.equal(diagnosticsLogs.every((entry) => entry.options?.step === 9), true);
assert.equal(diagnosticsLogs.every((entry) => entry.options?.stepKey === 'phone-verification'), true);
assert.equal(diagnosticsLogs.some((entry) => entry.message.includes('无号连续失败 1 次')), true);
assert.equal(diagnosticsLogs.some((entry) => entry.message.includes('无号连续失败 2 次')), true);
assert.equal(
diagnosticsLogs.some((message) => message.includes('maxPrice=0.06')),
diagnosticsLogs.some((entry) => entry.message.includes('maxPrice=0.06')),
true
);
assert.equal(
diagnosticsLogs.some((message) => message.includes('国家数 HeroSMS=1, 5sim=0, NexSMS=0')),
diagnosticsLogs.some((entry) => entry.message.includes('国家数 HeroSMS=1, 5sim=0, NexSMS=0')),
true
);
assert.equal(currentState.phoneNoSupplyFailureStreak, 2);
+3 -3
View File
@@ -84,8 +84,8 @@ test('step6LoginFromPasswordPage switches to one-time-code login when password i
globalThis.normalizeStep6Snapshot = (value) => value;
globalThis.inspectLoginAuthState = () => snapshot;
globalThis.log = (message, level = 'info') => {
logs.push({ message, level });
globalThis.log = (message, level = 'info', options = {}) => {
logs.push({ message, level, step: options.step, stepKey: options.stepKey });
};
globalThis.step6SwitchToOneTimeCodeLogin = async (payload, value) => {
assert.deepStrictEqual(payload, { email: 'user@example.com', password: '' });
@@ -110,7 +110,7 @@ test('step6LoginFromPasswordPage switches to one-time-code login when password i
assert.deepStrictEqual(result, { step6Outcome: 'success', via: 'switch_to_one_time_code_login' });
assert.deepStrictEqual(logs, [
{ message: '步骤 7当前未提供密码,改走一次性验证码登录。', level: 'warn' },
{ message: '当前未提供密码,改走一次性验证码登录。', level: 'warn', step: 7, stepKey: 'oauth-login' },
]);
} finally {
cleanupGlobals();
+3 -1
View File
@@ -185,7 +185,9 @@ test('step 8 reruns step 7 when auth page enters login timeout retry state', asy
assert.equal(calls.logs.some(({ message }) => /重新开始|重新发起/.test(message)), true);
assert.deepStrictEqual(calls.rerunOptions, [
{
logMessage: '步骤 8认证页进入重试/超时报错状态,正在回到步骤 7 重新发起登录流程...',
logMessage: '认证页进入重试/超时报错状态,正在回到步骤 7 重新发起登录流程...',
logStep: 8,
logStepKey: 'fetch-login-code',
},
]);
});