const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const source = fs.readFileSync('flows/openai/background/steps/fill-password.js', 'utf8'); const globalScope = {}; const api = new Function('self', `${source}; return self.MultiPageBackgroundStep3;`)(globalScope); test('step 3 reuses existing generated password when rerunning the same email flow', async () => { const events = { passwordStates: [], messages: [], }; const executor = api.createStep3Executor({ addLog: async () => {}, chrome: { tabs: { update: async () => {} } }, ensureContentScriptReadyOnTab: async () => {}, generatePassword: () => 'Generated-Should-Not-Be-Used', getTabId: async () => 88, isTabAlive: async () => true, sendToContentScript: async (_source, message) => { events.messages.push(message); }, setPasswordState: async (password) => { events.passwordStates.push(password); }, setState: async () => {}, OPENAI_AUTH_INJECT_FILES: [], }); await executor.executeStep3({ email: 'keep@example.com', password: 'Secret123!', customPassword: '', accounts: [], }); assert.deepStrictEqual(events.passwordStates, ['Secret123!']); assert.deepStrictEqual(events.messages, [ { type: 'EXECUTE_NODE', nodeId: 'fill-password', step: 3, source: 'background', payload: { email: 'keep@example.com', phoneNumber: '', accountIdentifierType: 'email', accountIdentifier: 'keep@example.com', password: 'Secret123!', }, }, ]); }); test('step 3 supports phone-only signup identity when password page is present', async () => { const events = { passwordStates: [], messages: [], stateUpdates: [], logs: [], }; const executor = api.createStep3Executor({ addLog: async (message) => { events.logs.push(message); }, chrome: { tabs: { update: async () => {} } }, ensureContentScriptReadyOnTab: async () => {}, generatePassword: () => 'Generated123!', getTabId: async () => 88, isTabAlive: async () => true, sendToContentScript: async (_source, message) => { events.messages.push(message); }, setPasswordState: async (password) => { events.passwordStates.push(password); }, setState: async (updates) => { events.stateUpdates.push(updates); }, OPENAI_AUTH_INJECT_FILES: [], }); await executor.executeStep3({ email: '', signupPhoneNumber: '66959916439', accountIdentifierType: 'phone', accountIdentifier: '66959916439', customPassword: 'PhoneSecret123!', accounts: [], }); assert.deepStrictEqual(events.passwordStates, ['PhoneSecret123!']); assert.equal(events.logs.some((message) => /注册手机号为 66959916439/.test(message)), true); assert.equal(events.stateUpdates.length, 1); assert.deepStrictEqual(events.stateUpdates[0].accounts.map((account) => ({ email: account.email, phoneNumber: account.phoneNumber, accountIdentifierType: account.accountIdentifierType, accountIdentifier: account.accountIdentifier, })), [ { email: '', phoneNumber: '66959916439', accountIdentifierType: 'phone', accountIdentifier: '66959916439', }, ]); assert.deepStrictEqual(events.messages, [ { type: 'EXECUTE_NODE', nodeId: 'fill-password', step: 3, source: 'background', payload: { email: '', phoneNumber: '66959916439', accountIdentifierType: 'phone', accountIdentifier: '66959916439', password: 'PhoneSecret123!', }, }, ]); }); test('step 3 phone signup intent does not fall back to a stale email identity', async () => { const events = { passwordStates: [], messages: [], stateUpdates: [], }; const executor = api.createStep3Executor({ addLog: async () => {}, chrome: { tabs: { update: async () => {} } }, ensureContentScriptReadyOnTab: async () => {}, generatePassword: () => 'Generated123!', getTabId: async () => 88, isTabAlive: async () => true, resolveSignupMethod: () => 'phone', sendToContentScript: async (_source, message) => { events.messages.push(message); }, setPasswordState: async (password) => { events.passwordStates.push(password); }, setState: async (updates) => { events.stateUpdates.push(updates); }, OPENAI_AUTH_INJECT_FILES: [], }); await assert.rejects( () => executor.executeStep3({ email: 'stale@example.com', signupMethod: 'phone', resolvedSignupMethod: 'phone', accountIdentifierType: null, accountIdentifier: '', customPassword: 'PhoneSecret123!', accounts: [], }), /缺少注册手机号,请先完成步骤 2 或在侧栏填写注册手机号后再执行步骤 3。/ ); assert.deepStrictEqual(events.passwordStates, []); assert.deepStrictEqual(events.stateUpdates, []); assert.deepStrictEqual(events.messages, []); }); test('step 3 respects resolved email fallback when phone signup is unavailable', async () => { const events = { messages: [], }; const executor = api.createStep3Executor({ addLog: async () => {}, chrome: { tabs: { update: async () => {} } }, ensureContentScriptReadyOnTab: async () => {}, generatePassword: () => 'Generated123!', getTabId: async () => 88, isTabAlive: async () => true, resolveSignupMethod: () => 'email', sendToContentScript: async (_source, message) => { events.messages.push(message); }, setPasswordState: async () => {}, setState: async () => {}, OPENAI_AUTH_INJECT_FILES: [], }); await executor.executeStep3({ email: 'fallback@example.com', signupMethod: 'phone', resolvedSignupMethod: 'email', customPassword: 'EmailSecret123!', accounts: [], }); assert.equal(events.messages[0].payload.accountIdentifierType, 'email'); assert.equal(events.messages[0].payload.accountIdentifier, 'fallback@example.com'); });