117 lines
4.2 KiB
JavaScript
117 lines
4.2 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('assert');
|
|
const { checkNeedPassword, handleIdentityVerification } = require('../src/services/common_auth');
|
|
|
|
function passwordInputs(visibleCount) {
|
|
return {
|
|
count: async () => visibleCount,
|
|
nth: () => ({ isVisible: async () => true }),
|
|
};
|
|
}
|
|
|
|
(async () => {
|
|
const logs = [];
|
|
const page = {
|
|
waitForLoadState: async () => {},
|
|
url: () => 'https://myaccount.google.com/signinoptions/password?rapt=test',
|
|
locator: selector => {
|
|
assert.strictEqual(selector, 'input[type="password"]');
|
|
return passwordInputs(2);
|
|
},
|
|
};
|
|
|
|
assert.strictEqual(await checkNeedPassword(page, message => logs.push(message)), false);
|
|
assert(logs.some(message => message.includes('双输入框')),
|
|
'两栏新密码表单应明确跳过旧密码验证');
|
|
|
|
const authenticatorLogs = [];
|
|
let networkIdleWaited = false;
|
|
const authenticatorPage = {
|
|
waitForLoadState: async () => { networkIdleWaited = true; },
|
|
url: () => 'https://myaccount.google.com/two-step-verification/authenticator?utm_source=test',
|
|
locator: () => { throw new Error('设置页快速路径不应扫描密码输入框'); },
|
|
};
|
|
assert.strictEqual(
|
|
await checkNeedPassword(authenticatorPage, message => authenticatorLogs.push(message)),
|
|
false,
|
|
);
|
|
assert.strictEqual(networkIdleWaited, false, 'Authenticator 设置页不应等待 networkidle');
|
|
assert(authenticatorLogs.some(message => message.includes('Authenticator 设置页')),
|
|
'日志应说明命中了设置页快速路径');
|
|
|
|
// 真实回归:reCAPTCHA 页面在初次密码检测结束后才跳到 challenge/pwd。
|
|
// 身份验证循环必须重新识别并提交密码,不能把它当成未知 challenge 空等。
|
|
{
|
|
let currentUrl = 'https://accounts.google.com/v3/signin/challenge/recaptcha';
|
|
const fills = [];
|
|
let submitCount = 0;
|
|
|
|
const missing = () => ({
|
|
first() { return this; },
|
|
nth() { return this; },
|
|
or(other) { return other; },
|
|
count: async () => 0,
|
|
waitFor: async () => { throw new Error('not visible'); },
|
|
isVisible: async () => false,
|
|
textContent: async () => '',
|
|
innerText: async () => '',
|
|
});
|
|
const visiblePassword = () => ({
|
|
first() { return this; },
|
|
nth() { return this; },
|
|
or() { return this; },
|
|
count: async () => 1,
|
|
waitFor: async () => {},
|
|
isVisible: async () => true,
|
|
fill: async value => { fills.push(value); },
|
|
press: async () => { submitCount++; currentUrl = 'https://myaccount.google.com/'; },
|
|
});
|
|
const visibleSubmit = () => ({
|
|
first() { return this; },
|
|
nth() { return this; },
|
|
or() { return this; },
|
|
count: async () => 1,
|
|
waitFor: async () => {},
|
|
isVisible: async () => true,
|
|
evaluate: async () => { submitCount++; currentUrl = 'https://myaccount.google.com/'; },
|
|
});
|
|
const page = {
|
|
url: () => currentUrl,
|
|
waitForLoadState: async () => {},
|
|
waitForTimeout: async () => {
|
|
if (currentUrl.includes('/recaptcha')) {
|
|
currentUrl = 'https://accounts.google.com/v3/signin/challenge/pwd';
|
|
}
|
|
},
|
|
locator: selector => {
|
|
if (selector === 'body') return { ...missing(), innerText: async () => '' };
|
|
if (selector === 'input[type="password"]' && currentUrl.includes('/pwd')) {
|
|
return visiblePassword();
|
|
}
|
|
if (selector === 'button:has-text("Next")' && currentUrl.includes('/pwd')) {
|
|
return visibleSubmit();
|
|
}
|
|
return missing();
|
|
},
|
|
};
|
|
|
|
const delayedLogs = [];
|
|
const result = await handleIdentityVerification(
|
|
page,
|
|
{ password: 'correct-password' },
|
|
message => delayedLogs.push(message),
|
|
);
|
|
assert.deepStrictEqual(result, [true, null]);
|
|
assert.deepStrictEqual(fills, ['', 'correct-password']);
|
|
assert.strictEqual(submitCount, 1, '延迟密码页只能提交一次');
|
|
assert(delayedLogs.some(message => message.includes('延迟出现的密码验证页')),
|
|
'日志应明确记录异步出现的密码页恢复路径');
|
|
}
|
|
|
|
console.log('common_auth_password_change_form.test.js: PASS');
|
|
})().catch(error => {
|
|
console.error(error);
|
|
process.exitCode = 1;
|
|
});
|