Files
FlowPilot/tests/phone-verification-flow.test.js
T
2026-04-21 13:17:17 +08:00

427 lines
13 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const source = fs.readFileSync('background/phone-verification-flow.js', 'utf8');
const globalScope = {};
const api = new Function('self', `${source}; return self.MultiPageBackgroundPhoneVerification;`)(globalScope);
test('phone verification helper requests HeroSMS numbers with fixed OpenAI and Thailand parameters', async () => {
const requests = [];
const helpers = api.createPhoneVerificationHelpers({
addLog: async () => {},
ensureStep8SignupPageReady: async () => {},
fetchImpl: async (url) => {
requests.push(new URL(url));
return {
ok: true,
text: async () => 'ACCESS_NUMBER:123456:66959916439',
};
},
getState: async () => ({ heroSmsApiKey: 'demo-key' }),
sendToContentScriptResilient: async () => ({}),
setState: async () => {},
sleepWithStop: async () => {},
throwIfStopped: () => {},
});
const activation = await helpers.requestPhoneActivation({ heroSmsApiKey: 'demo-key' });
assert.deepStrictEqual(activation, {
activationId: '123456',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 0,
maxUses: 3,
});
assert.equal(requests.length, 1);
assert.equal(requests[0].searchParams.get('action'), 'getNumber');
assert.equal(requests[0].searchParams.get('service'), 'dr');
assert.equal(requests[0].searchParams.get('country'), '52');
assert.equal(requests[0].searchParams.get('api_key'), 'demo-key');
});
test('phone verification helper completes add-phone flow, clears current activation, and stores reusable number state', async () => {
const requests = [];
const stateUpdates = [];
let currentState = {
heroSmsApiKey: 'demo-key',
verificationResendCount: 1,
currentPhoneActivation: null,
reusablePhoneActivation: null,
};
const helpers = api.createPhoneVerificationHelpers({
addLog: async () => {},
ensureStep8SignupPageReady: async () => {},
fetchImpl: async (url) => {
const parsedUrl = new URL(url);
requests.push(parsedUrl);
const action = parsedUrl.searchParams.get('action');
if (action === 'getNumber') {
return {
ok: true,
text: async () => 'ACCESS_NUMBER:123456:66959916439',
};
}
if (action === 'getStatus') {
return {
ok: true,
text: async () => 'STATUS_OK:654321',
};
}
if (action === 'setStatus') {
return {
ok: true,
text: async () => 'ACCESS_ACTIVATION',
};
}
throw new Error(`Unexpected HeroSMS action: ${action}`);
},
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
getState: async () => ({ ...currentState }),
sendToContentScriptResilient: async (_source, message) => {
if (message.type === 'SUBMIT_PHONE_NUMBER') {
return {
phoneVerificationPage: true,
url: 'https://auth.openai.com/phone-verification',
};
}
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
return {
success: true,
consentReady: true,
url: 'https://auth.openai.com/authorize',
};
}
throw new Error(`Unexpected content-script message: ${message.type}`);
},
setState: async (updates) => {
stateUpdates.push(updates);
currentState = { ...currentState, ...updates };
},
sleepWithStop: async () => {},
throwIfStopped: () => {},
});
const result = await helpers.completePhoneVerificationFlow(1, {
addPhonePage: true,
phoneVerificationPage: false,
url: 'https://auth.openai.com/add-phone',
});
assert.deepStrictEqual(result, {
success: true,
consentReady: true,
url: 'https://auth.openai.com/authorize',
});
assert.deepStrictEqual(stateUpdates, [
{
currentPhoneActivation: {
activationId: '123456',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 0,
maxUses: 3,
},
},
{
reusablePhoneActivation: {
activationId: '123456',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 1,
maxUses: 3,
},
},
{
currentPhoneActivation: null,
},
]);
const actions = requests.map((url) => url.searchParams.get('action'));
assert.deepStrictEqual(actions, ['getNumber', 'getStatus', 'setStatus']);
});
test('phone verification helper uses the configured HeroSMS country for both number acquisition and add-phone submission', async () => {
const requests = [];
const submittedPayloads = [];
let currentState = {
heroSmsApiKey: 'demo-key',
heroSmsCountryId: 16,
heroSmsCountryLabel: 'United Kingdom',
verificationResendCount: 0,
currentPhoneActivation: null,
reusablePhoneActivation: null,
};
const helpers = api.createPhoneVerificationHelpers({
addLog: async () => {},
ensureStep8SignupPageReady: async () => {},
fetchImpl: async (url) => {
const parsedUrl = new URL(url);
requests.push(parsedUrl);
const action = parsedUrl.searchParams.get('action');
if (action === 'getNumber') {
return {
ok: true,
text: async () => 'ACCESS_NUMBER:654321:447911123456',
};
}
if (action === 'getStatus') {
return {
ok: true,
text: async () => 'STATUS_OK:112233',
};
}
if (action === 'setStatus') {
return {
ok: true,
text: async () => 'ACCESS_ACTIVATION',
};
}
throw new Error(`Unexpected HeroSMS action: ${action}`);
},
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
getState: async () => ({ ...currentState }),
sendToContentScriptResilient: async (_source, message) => {
if (message.type === 'SUBMIT_PHONE_NUMBER') {
submittedPayloads.push(message.payload);
return {
phoneVerificationPage: true,
url: 'https://auth.openai.com/phone-verification',
};
}
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
return {
success: true,
consentReady: true,
url: 'https://auth.openai.com/authorize',
};
}
throw new Error(`Unexpected content-script message: ${message.type}`);
},
setState: async (updates) => {
currentState = { ...currentState, ...updates };
},
sleepWithStop: async () => {},
throwIfStopped: () => {},
});
const result = await helpers.completePhoneVerificationFlow(1, {
addPhonePage: true,
phoneVerificationPage: false,
url: 'https://auth.openai.com/add-phone',
});
assert.deepStrictEqual(result, {
success: true,
consentReady: true,
url: 'https://auth.openai.com/authorize',
});
assert.equal(requests[0].searchParams.get('action'), 'getNumber');
assert.equal(requests[0].searchParams.get('country'), '16');
assert.deepStrictEqual(submittedPayloads, [{
phoneNumber: '447911123456',
countryId: 16,
countryLabel: 'United Kingdom',
}]);
});
test('phone verification helper throws a step-7 restart error after 60 seconds plus one resend window without SMS', async () => {
const requests = [];
const messages = [];
let currentState = {
heroSmsApiKey: 'demo-key',
verificationResendCount: 0,
currentPhoneActivation: null,
reusablePhoneActivation: null,
};
const statusCallsById = {};
const realDateNow = Date.now;
let fakeNow = 0;
Date.now = () => fakeNow;
try {
const helpers = api.createPhoneVerificationHelpers({
addLog: async () => {},
ensureStep8SignupPageReady: async () => {},
fetchImpl: async (url) => {
const parsedUrl = new URL(url);
requests.push(parsedUrl);
const action = parsedUrl.searchParams.get('action');
const id = parsedUrl.searchParams.get('id');
if (action === 'getNumber') {
return {
ok: true,
text: async () => 'ACCESS_NUMBER:123456:66959916439',
};
}
if (action === 'getStatus') {
statusCallsById[id] = (statusCallsById[id] || 0) + 1;
return {
ok: true,
text: async () => 'STATUS_WAIT_CODE',
};
}
if (action === 'setStatus') {
return {
ok: true,
text: async () => 'ACCESS_ACTIVATION',
};
}
throw new Error(`Unexpected HeroSMS action: ${action}`);
},
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
getState: async () => ({ ...currentState }),
sendToContentScriptResilient: async (_source, message) => {
messages.push(message.type);
if (message.type === 'SUBMIT_PHONE_NUMBER') {
return {
phoneVerificationPage: true,
url: 'https://auth.openai.com/phone-verification',
};
}
if (message.type === 'RESEND_PHONE_VERIFICATION_CODE') {
return {
resent: true,
url: 'https://auth.openai.com/phone-verification',
};
}
throw new Error(`Unexpected content-script message: ${message.type}`);
},
setState: async (updates) => {
currentState = { ...currentState, ...updates };
},
sleepWithStop: async () => {
fakeNow += 61000;
},
throwIfStopped: () => {},
});
await assert.rejects(
helpers.completePhoneVerificationFlow(1, {
addPhonePage: true,
phoneVerificationPage: false,
url: 'https://auth.openai.com/add-phone',
}),
/Restart step 7 with a new number/i
);
assert.ok(statusCallsById['123456'] >= 2, 'first number should be polled twice before being replaced');
assert.deepStrictEqual(messages, [
'SUBMIT_PHONE_NUMBER',
'RESEND_PHONE_VERIFICATION_CODE',
]);
const actions = requests.map((url) => `${url.searchParams.get('action')}:${url.searchParams.get('id') || ''}`);
assert.deepStrictEqual(actions, [
'getNumber:',
'getStatus:123456',
'setStatus:123456',
'getStatus:123456',
'setStatus:123456',
]);
assert.equal(currentState.currentPhoneActivation, null);
} finally {
Date.now = realDateNow;
}
});
test('phone verification helper reuses the same number up to three successful registrations', async () => {
const requests = [];
let currentState = {
heroSmsApiKey: 'demo-key',
verificationResendCount: 0,
currentPhoneActivation: null,
reusablePhoneActivation: {
activationId: '123456',
phoneNumber: '66959916439',
provider: 'hero-sms',
serviceCode: 'dr',
countryId: 52,
successfulUses: 2,
maxUses: 3,
},
};
const helpers = api.createPhoneVerificationHelpers({
addLog: async () => {},
ensureStep8SignupPageReady: async () => {},
fetchImpl: async (url) => {
const parsedUrl = new URL(url);
requests.push(parsedUrl);
const action = parsedUrl.searchParams.get('action');
if (action === 'reactivate') {
return {
ok: true,
text: async () => JSON.stringify({
activationId: '222333',
phoneNumber: '66959916439',
}),
};
}
if (action === 'getStatus') {
return {
ok: true,
text: async () => 'STATUS_OK:654321',
};
}
if (action === 'setStatus') {
return {
ok: true,
text: async () => 'ACCESS_ACTIVATION',
};
}
throw new Error(`Unexpected HeroSMS action: ${action}`);
},
getOAuthFlowStepTimeoutMs: async (defaultTimeoutMs) => defaultTimeoutMs,
getState: async () => ({ ...currentState }),
sendToContentScriptResilient: async (_source, message) => {
if (message.type === 'SUBMIT_PHONE_NUMBER') {
return {
phoneVerificationPage: true,
url: 'https://auth.openai.com/phone-verification',
};
}
if (message.type === 'SUBMIT_PHONE_VERIFICATION_CODE') {
return {
success: true,
consentReady: true,
url: 'https://auth.openai.com/authorize',
};
}
throw new Error(`Unexpected content-script message: ${message.type}`);
},
setState: async (updates) => {
currentState = { ...currentState, ...updates };
},
sleepWithStop: async () => {},
throwIfStopped: () => {},
});
const result = await helpers.completePhoneVerificationFlow(1, {
addPhonePage: true,
phoneVerificationPage: false,
url: 'https://auth.openai.com/add-phone',
});
assert.deepStrictEqual(result, {
success: true,
consentReady: true,
url: 'https://auth.openai.com/authorize',
});
assert.equal(requests[0].searchParams.get('action'), 'reactivate');
assert.equal(requests[0].searchParams.get('id'), '123456');
assert.deepStrictEqual(currentState.reusablePhoneActivation, null);
});