修复问题

This commit is contained in:
QLHazyCoder
2026-05-04 19:38:12 +08:00
parent f2e6a1ed3e
commit 0795108014
12 changed files with 836 additions and 39 deletions
@@ -181,6 +181,34 @@ test('message router syncs signup phone runtime state from step 2 payload immedi
assert.deepStrictEqual(events.signupPhoneStates, []);
});
test('message router clears stale signup phone runtime when step 2 resolves email identity', async () => {
const { router, events } = createRouter({
state: {
stepStatuses: { 3: 'pending' },
accountIdentifierType: 'phone',
accountIdentifier: '+66959916439',
signupPhoneNumber: '+66959916439',
signupPhoneActivation: { activationId: 'old', phoneNumber: '+66959916439' },
},
});
await router.handleStepData(2, {
email: 'user@example.com',
accountIdentifierType: 'email',
accountIdentifier: 'user@example.com',
});
assert.deepStrictEqual(events.emailStates, ['user@example.com']);
assert.deepStrictEqual(events.signupPhoneSilentStates, [null]);
assert.ok(events.stateUpdates.some((updates) => (
updates.accountIdentifierType === 'email'
&& updates.accountIdentifier === 'user@example.com'
&& updates.signupPhoneNumber === ''
&& updates.signupPhoneActivation === null
&& updates.signupPhoneCompletedActivation === null
)));
});
test('message router does not overwrite a completed step 3 when step 2 is replayed', async () => {
const { router, events } = createRouter({
state: { stepStatuses: { 3: 'completed' } },
@@ -180,6 +180,146 @@ test('step 2 uses phone activation when resolved signup method is phone', async
]);
});
test('step 2 reuses existing signup phone activation without acquiring a new number', async () => {
const completedPayloads = [];
const sequence = [];
const sentPayloads = [];
const activation = {
activationId: 'existing-signup-activation',
phoneNumber: '+446700000001',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 16,
countryLabel: 'United Kingdom',
};
const executor = step2Api.createStep2Executor({
addLog: async () => {},
chrome: { tabs: { update: async () => {} } },
completeStepFromBackground: async (step, payload) => {
completedPayloads.push({ step, payload });
},
ensureContentScriptReadyOnTab: async () => {},
ensureSignupEntryPageReady: async () => ({ tabId: 15 }),
ensureSignupPostIdentityPageReadyInTab: async () => ({
state: 'phone_verification_page',
url: 'https://auth.openai.com/phone-verification',
}),
getTabId: async () => 15,
isTabAlive: async () => true,
phoneVerificationHelpers: {
normalizeActivation: (record) => record,
prepareSignupPhoneActivation: async () => {
throw new Error('prepareSignupPhoneActivation should not run when signup activation already exists');
},
cancelSignupPhoneActivation: async () => {
throw new Error('activation should not be cancelled on success');
},
},
resolveSignupMethod: () => 'phone',
resolveSignupEmailForFlow: async () => {
throw new Error('email resolver should not run for phone signup');
},
sendToContentScriptResilient: async (_source, message) => {
if (message.type === 'ENSURE_SIGNUP_PHONE_ENTRY_READY') {
sequence.push('ensureSignupPhoneEntryReady');
return { ready: true, state: 'phone_entry' };
}
sequence.push('submitSignupPhone');
sentPayloads.push(message.payload);
return { submitted: true };
},
SIGNUP_PAGE_INJECT_FILES: [],
});
await executor.executeStep2({
signupMethod: 'phone',
signupPhoneActivation: activation,
});
assert.deepStrictEqual(sequence, [
'ensureSignupPhoneEntryReady',
'submitSignupPhone',
]);
assert.deepStrictEqual(sentPayloads, [
{
signupMethod: 'phone',
phoneNumber: '+446700000001',
countryId: 16,
countryLabel: 'United Kingdom',
},
]);
assert.equal(completedPayloads[0].payload.signupPhoneActivation, activation);
});
test('step 2 submits manual signup phone without acquiring a number', async () => {
const completedPayloads = [];
const sentPayloads = [];
const executor = step2Api.createStep2Executor({
addLog: async () => {},
chrome: { tabs: { update: async () => {} } },
completeStepFromBackground: async (step, payload) => {
completedPayloads.push({ step, payload });
},
ensureContentScriptReadyOnTab: async () => {},
ensureSignupEntryPageReady: async () => ({ tabId: 16 }),
ensureSignupPostIdentityPageReadyInTab: async () => ({
state: 'phone_verification_page',
url: 'https://auth.openai.com/phone-verification',
}),
getTabId: async () => 16,
isTabAlive: async () => true,
phoneVerificationHelpers: {
prepareSignupPhoneActivation: async () => {
throw new Error('prepareSignupPhoneActivation should not run for manual signup phone');
},
},
resolveSignupMethod: () => 'phone',
resolveSignupEmailForFlow: async () => {
throw new Error('email resolver should not run for phone signup');
},
sendToContentScriptResilient: async (_source, message) => {
if (message.type === 'ENSURE_SIGNUP_PHONE_ENTRY_READY') {
return { ready: true, state: 'phone_entry' };
}
sentPayloads.push(message.payload);
return { submitted: true };
},
SIGNUP_PAGE_INJECT_FILES: [],
});
await executor.executeStep2({
signupMethod: 'phone',
signupPhoneNumber: '+446700000002',
accountIdentifierType: 'phone',
accountIdentifier: '+446700000002',
});
assert.deepStrictEqual(sentPayloads, [
{
signupMethod: 'phone',
phoneNumber: '+446700000002',
countryId: null,
countryLabel: '',
},
]);
assert.deepStrictEqual(completedPayloads, [
{
step: 2,
payload: {
accountIdentifierType: 'phone',
accountIdentifier: '+446700000002',
signupPhoneNumber: '+446700000002',
signupPhoneActivation: null,
nextSignupState: 'phone_verification_page',
nextSignupUrl: 'https://auth.openai.com/phone-verification',
skippedPasswordStep: true,
},
},
]);
});
test('step 2 stops with an explicit error instead of silently skipping 3/4/5 on chatgpt home', async () => {
const completedPayloads = [];
const logs = [];
+63
View File
@@ -0,0 +1,63 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
function loadPhoneCountryUtils() {
const source = fs.readFileSync('content/phone-country-utils.js', 'utf8');
const root = {};
return new Function('self', `${source}; return self.MultiPagePhoneCountryUtils;`)(root);
}
test('phone country utils extracts dial codes from current OpenAI country labels', () => {
const utils = loadPhoneCountryUtils();
assert.equal(utils.extractDialCodeFromText('United Kingdom (+44)'), '44');
assert.equal(utils.extractDialCodeFromText('United Kingdom +(44)'), '44');
assert.equal(utils.extractDialCodeFromText('United Kingdom +44'), '44');
});
test('phone country utils resolves country dial code from provider phone numbers', () => {
const utils = loadPhoneCountryUtils();
assert.equal(utils.resolveDialCodeFromPhoneNumber('447423278610'), '44');
assert.equal(utils.resolveDialCodeFromPhoneNumber('+8613800138000'), '86');
assert.equal(utils.resolveDialCodeFromPhoneNumber('12461234567'), '1246');
});
test('phone country utils finds country options by phone dial code and country aliases', () => {
const utils = loadPhoneCountryUtils();
const options = [
{ value: 'ID', textContent: 'Indonesia +(62)' },
{ value: 'GB', textContent: 'United Kingdom +(44)' },
];
assert.equal(utils.findOptionByPhoneNumber(options, '447423278610'), options[1]);
assert.equal(utils.findOptionByCountryLabel(options, 'England'), options[1]);
});
test('phone country utils is loaded before phone auth content scripts', () => {
const manifest = JSON.parse(fs.readFileSync('manifest.json', 'utf8'));
const authScript = manifest.content_scripts.find((entry) => (
Array.isArray(entry.matches)
&& entry.matches.some((match) => match.includes('auth.openai.com'))
));
assert.ok(authScript, 'missing auth content script');
assert.ok(authScript.js.includes('content/phone-country-utils.js'));
assert.ok(
authScript.js.indexOf('content/phone-country-utils.js') < authScript.js.indexOf('content/phone-auth.js'),
'phone-country-utils.js must load before phone-auth.js'
);
assert.ok(
authScript.js.indexOf('content/phone-country-utils.js') < authScript.js.indexOf('content/signup-page.js'),
'phone-country-utils.js must load before signup-page.js'
);
const background = fs.readFileSync('background.js', 'utf8');
const injectLine = background.match(/const\s+SIGNUP_PAGE_INJECT_FILES\s*=\s*\[[^\n]+\]/)?.[0] || '';
assert.ok(injectLine.includes("'content/phone-country-utils.js'"));
assert.ok(
injectLine.indexOf("'content/phone-country-utils.js'") < injectLine.indexOf("'content/phone-auth.js'"),
'dynamic signup injection must load phone-country-utils.js before phone-auth.js'
);
});