const assert = require('assert'); const { classifyFailure, getFailureLabel, isOAuthWait7DaysOutcome, resolveFailureOutcome, } = require('../src/utils/error_classifier'); const { detectOAuthReauthProblem } = require('../src/services/ag_verify_service'); function codeFor(message, url = '') { return classifyFailure({ message, url }).code; } assert.strictEqual(codeFor('密码错误'), 'PASSWORD_WRONG'); assert.strictEqual(codeFor('Your password was changed 10 days ago'), 'PASSWORD_CHANGED_RECENTLY'); assert.strictEqual(codeFor('需要 2FA 验证但未提供密钥'), 'TOTP_KEY_INVALID'); assert.strictEqual(codeFor('Wrong code. Try again.'), 'TOTP_KEY_INCORRECT'); assert.strictEqual(codeFor('2fa密钥不正确'), 'TOTP_KEY_INCORRECT'); assert.strictEqual(codeFor('触发人机认证'), 'CAPTCHA'); assert.strictEqual(codeFor('Please try again later'), 'UNKNOWN', '普通 try again 不得误归2FA错误'); assert.strictEqual(codeFor('密码近期已更改'), 'PASSWORD_CHANGED_RECENTLY'); assert.strictEqual(codeFor('OAuth 暂无2FA认证选项'), 'OAUTH_WAIT_7_DAYS'); assert.strictEqual(codeFor('验证方式列表中没有 Google Authenticator 选项'), 'TOTP_OPTION_UNAVAILABLE'); assert.strictEqual(codeFor('需要辅助邮箱验证但未提供'), 'RECOVERY_EMAIL_REQUIRED'); assert.strictEqual(codeFor('需要备用码验证,且页面无法切换到 Google Authenticator'), 'BACKUP_CODE_REQUIRED'); assert.strictEqual(codeFor('Google拒绝本次登录', 'https://accounts.google.com/signin/rejected'), 'SIGNIN_REJECTED'); assert.strictEqual( classifyFailure({ url: 'https://accounts.google.com/signin/rejected', message: 'Google拒绝本次登录' }).shouldRotateProxy, true, 'signin/rejected 应触发自动更换代理后重试', ); // 账号列表统一使用处理结论,避免同一类问题出现多种可见文案。 assert.strictEqual(classifyFailure({ message: '密码错误' }).label, '密码错误'); assert.strictEqual(classifyFailure({ message: 'Your password was changed 10 days ago' }).label, '密码已被修改'); assert.strictEqual(classifyFailure({ message: 'Your password was changed 10 days ago' }).shouldKeepOpen, false); assert.strictEqual(classifyFailure({ message: 'Your password was changed 10 days ago' }).shouldRotateProxy, false); assert.strictEqual(classifyFailure({ message: 'Wrong code. Try again.' }).label, '2fa密钥不正确'); assert.strictEqual(classifyFailure({ message: 'Wrong code. Try again.' }).shouldKeepOpen, false); assert.strictEqual(classifyFailure({ message: 'Wrong code. Try again.' }).shouldRotateProxy, false); assert.strictEqual(classifyFailure({ message: "Confirm you're not a robot" }).label, '人机验证'); assert.strictEqual(getFailureLabel('CAPTCHA'), '人机验证'); assert.strictEqual(getFailureLabel('PHONE_TABLET_VERIFY'), '要等7天'); assert.strictEqual(getFailureLabel('CHATGPT_ACCOUNT_DEACTIVATED'), '账号已删除/停用'); assert.strictEqual( classifyFailure({ message: 'You do not have an account because it has been deleted or deactivated.' }).label, '账号已删除/停用', ); assert.strictEqual( classifyFailure({ message: '需手机/平板验证' }).code, 'PHONE_TABLET_VERIFY', ); assert.strictEqual( classifyFailure({ message: '需手机/平板验证' }).label, '要等7天', ); assert.strictEqual(isOAuthWait7DaysOutcome('PHONE_TABLET_VERIFY'), true); assert.strictEqual(classifyFailure({ message: '检测到风险登录,无法登录' }).label, '无法登录'); assert.strictEqual(classifyFailure({ message: 'net::ERR_CONNECTION_TIMED_OUT' }).label, '切换ip重试'); assert.strictEqual(classifyFailure({ message: '测速失败' }).label, '切换ip重试'); assert.strictEqual( classifyFailure({ message: 'OAuth身份验证页面无法切换到其它方式:/v3/signin/challenge/dp' }).label, '要等7天', 'OAuth 验证方式卡在 dp challenge 时应直接归入等待7天', ); assert.strictEqual( codeFor('OAuth身份验证页面无法切换到其它方式:/v3/signin/challenge/dp'), 'OAUTH_CHALLENGE_STUCK', ); assert.strictEqual(getFailureLabel('OAUTH_CHALLENGE_STUCK'), '要等7天'); assert.strictEqual(getFailureLabel('GCP_NO_PERMISSION'), '无权限'); assert.strictEqual(getFailureLabel('GOOGLE_UNDER_18'), '未满18岁'); assert.strictEqual(classifyFailure({ message: 'OAuth授权超时' }).label, '要等7天'); assert.strictEqual(isOAuthWait7DaysOutcome('OAUTH_NO_AUTHENTICATOR'), true); assert.strictEqual(isOAuthWait7DaysOutcome('OAUTH_CHALLENGE_STUCK'), true); assert.strictEqual(isOAuthWait7DaysOutcome('OAUTH_TIMEOUT'), true); assert.strictEqual(isOAuthWait7DaysOutcome('NETWORK_PROXY'), false); assert.strictEqual( isOAuthWait7DaysOutcome('TOKEN_EXCHANGE_FAILED', { message: 'network timeout' }), false, 'Token 网络失败不得误进等待7天分组', ); assert.strictEqual(classifyFailure({ message: 'OAuth token exchange network error' }).label, '切换ip重试'); assert.strictEqual( resolveFailureOutcome({ code: 'OAUTH_CHALLENGE_STUCK', message: 'OAuth身份验证页面无法切换到其它方式:/v3/signin/challenge/dp', }).displayMessage, '要等7天', ); function fakeOAuthPage({ url = 'https://accounts.google.com/signin/challenge/pwd', body = '', frameBox = null, frameBoxes = null } = {}) { const boxes = frameBoxes || (frameBox ? [frameBox] : []); return { url: () => url, locator: selector => { if (selector === 'body') { return { innerText: async () => body }; } return { count: async () => boxes.length, nth: index => ({ isVisible: async () => !!boxes[index], boundingBox: async () => boxes[index] || null, }), }; }, }; } (async () => { let result = await detectOAuthReauthProblem(fakeOAuthPage({ body: 'Wrong password. Try again.' }), { passwordSubmitted: false, }); assert.strictEqual(result, null, '提交前不得只凭页面文字判密码错误'); result = await detectOAuthReauthProblem(fakeOAuthPage({ body: 'Wrong password. Try again.' }), { passwordSubmitted: true, }); assert.deepStrictEqual(result, { reasonCode: 'PASSWORD_WRONG', msg: '密码错误' }); result = await detectOAuthReauthProblem(fakeOAuthPage({ body: 'Forgot password? Please try again.' }), { passwordSubmitted: true, }); assert.strictEqual(result, null, '普通忘记密码/重试文字不得误判'); result = await detectOAuthReauthProblem(fakeOAuthPage({ url: 'https://accounts.google.com/o/oauth2/auth', body: 'This site is protected by reCAPTCHA and the Google Privacy Policy.', frameBox: { width: 70, height: 60 }, })); assert.strictEqual(result, null, '正常 reCAPTCHA 条款和小徽标不得误报人机验证'); result = await detectOAuthReauthProblem(fakeOAuthPage({ url: 'https://accounts.google.com/o/oauth2/auth', frameBoxes: [{ width: 70, height: 60 }, { width: 320, height: 120 }], })); assert.deepStrictEqual( result, { reasonCode: 'CAPTCHA', msg: '触发人机验证' }, '小徽标之后的真挑战框不得被漏掉', ); result = await detectOAuthReauthProblem(fakeOAuthPage({ url: 'https://accounts.google.com/o/oauth2/auth', body: 'Verify you are not a robot', })); assert.deepStrictEqual(result, { reasonCode: 'CAPTCHA', msg: '触发人机验证' }); result = await detectOAuthReauthProblem(fakeOAuthPage({ url: 'https://accounts.google.com/signin/challenge/recaptcha', })); assert.deepStrictEqual(result, { reasonCode: 'CAPTCHA', msg: '触发人机验证' }); console.log('problem_reason_classification.test.js: PASS'); })().catch(error => { console.error(error); process.exitCode = 1; });