| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- const test = require('node:test');
- const assert = require('node:assert/strict');
- const fs = require('node:fs');
- const source = fs.readFileSync('background/message-router.js', 'utf8');
- const globalScope = {};
- const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
- function createRouter(overrides = {}) {
- const events = {
- logs: [],
- stepStatuses: [],
- emailStates: [],
- finalizePayloads: [],
- notifyCompletions: [],
- notifyErrors: [],
- };
- const router = api.createMessageRouter({
- addLog: async (message, level) => {
- events.logs.push({ message, level });
- },
- appendAccountRunRecord: async () => null,
- batchUpdateLuckmailPurchases: async () => {},
- buildLocalhostCleanupPrefix: () => '',
- buildLuckmailSessionSettingsPayload: () => ({}),
- buildPersistentSettingsPayload: () => ({}),
- broadcastDataUpdate: () => {},
- cancelScheduledAutoRun: async () => {},
- checkIcloudSession: async () => {},
- clearAutoRunTimerAlarm: async () => {},
- clearLuckmailRuntimeState: async () => {},
- clearStopRequest: () => {},
- closeLocalhostCallbackTabs: async () => {},
- closeTabsByUrlPrefix: async () => {},
- deleteHotmailAccount: async () => {},
- deleteHotmailAccounts: async () => {},
- deleteIcloudAlias: async () => {},
- deleteUsedIcloudAliases: async () => {},
- disableUsedLuckmailPurchases: async () => {},
- doesStepUseCompletionSignal: () => false,
- ensureManualInteractionAllowed: async () => ({}),
- executeStep: async () => {},
- executeStepViaCompletionSignal: async () => {},
- exportSettingsBundle: async () => ({}),
- fetchGeneratedEmail: async () => '',
- finalizeStep3Completion: overrides.finalizeStep3Completion || (async (payload) => {
- events.finalizePayloads.push(payload);
- }),
- finalizeIcloudAliasAfterSuccessfulFlow: async () => {},
- findHotmailAccount: async () => null,
- flushCommand: async () => {},
- getCurrentLuckmailPurchase: () => null,
- getPendingAutoRunTimerPlan: () => null,
- getSourceLabel: () => '',
- getState: async () => overrides.state || { stepStatuses: { 3: 'pending' } },
- getStopRequested: () => false,
- handleAutoRunLoopUnhandledError: async () => {},
- importSettingsBundle: async () => {},
- invalidateDownstreamAfterStepRestart: async () => {},
- isAutoRunLockedState: () => false,
- isHotmailProvider: () => false,
- isLocalhostOAuthCallbackUrl: () => true,
- isLuckmailProvider: () => false,
- isStopError: () => false,
- launchAutoRunTimerPlan: async () => {},
- listIcloudAliases: async () => [],
- listLuckmailPurchasesForManagement: async () => [],
- normalizeHotmailAccounts: (items) => items,
- normalizeRunCount: (value) => value,
- AUTO_RUN_TIMER_KIND_SCHEDULED_START: 'scheduled',
- notifyStepComplete: (step, payload) => {
- events.notifyCompletions.push({ step, payload });
- },
- notifyStepError: (step, error) => {
- events.notifyErrors.push({ step, error });
- },
- patchHotmailAccount: async () => {},
- registerTab: async () => {},
- requestStop: async () => {},
- resetState: async () => {},
- resumeAutoRun: async () => {},
- scheduleAutoRun: async () => {},
- selectLuckmailPurchase: async () => {},
- setCurrentHotmailAccount: async () => {},
- setEmailState: async (email) => {
- events.emailStates.push(email);
- },
- setEmailStateSilently: async () => {},
- setIcloudAliasPreservedState: async () => {},
- setIcloudAliasUsedState: async () => {},
- setLuckmailPurchaseDisabledState: async () => {},
- setLuckmailPurchasePreservedState: async () => {},
- setLuckmailPurchaseUsedState: async () => {},
- setPersistentSettings: async () => {},
- setState: async () => {},
- setStepStatus: async (step, status) => {
- events.stepStatuses.push({ step, status });
- },
- skipAutoRunCountdown: async () => false,
- skipStep: async () => {},
- startAutoRunLoop: async () => {},
- syncHotmailAccounts: async () => {},
- testHotmailAccountMailAccess: async () => {},
- upsertHotmailAccount: async () => {},
- verifyHotmailAccount: async () => {},
- });
- return { router, events };
- }
- test('message router skips step 3 when step 2 lands on verification page', async () => {
- const { router, events } = createRouter({
- state: { stepStatuses: { 3: 'pending' } },
- });
- await router.handleStepData(2, {
- email: 'user@example.com',
- skippedPasswordStep: true,
- });
- assert.deepStrictEqual(events.emailStates, ['user@example.com']);
- assert.deepStrictEqual(events.stepStatuses, [{ step: 3, status: 'skipped' }]);
- assert.equal(events.logs[0]?.message, '步骤 2:提交邮箱后页面直接进入邮箱验证码页,已自动跳过步骤 3。');
- });
- test('message router does not overwrite a completed step 3 when step 2 is replayed', async () => {
- const { router, events } = createRouter({
- state: { stepStatuses: { 3: 'completed' } },
- });
- await router.handleStepData(2, {
- skippedPasswordStep: true,
- });
- assert.deepStrictEqual(events.stepStatuses, []);
- });
- test('message router finalizes step 3 before marking it completed', async () => {
- const { router, events } = createRouter();
- const response = await router.handleMessage({
- type: 'STEP_COMPLETE',
- step: 3,
- source: 'signup-page',
- payload: {
- email: 'user@example.com',
- signupVerificationRequestedAt: 123,
- },
- }, {});
- assert.deepStrictEqual(events.finalizePayloads, [
- {
- email: 'user@example.com',
- signupVerificationRequestedAt: 123,
- },
- ]);
- assert.deepStrictEqual(events.stepStatuses, [{ step: 3, status: 'completed' }]);
- assert.deepStrictEqual(events.emailStates, ['user@example.com']);
- assert.deepStrictEqual(events.notifyCompletions, [
- {
- step: 3,
- payload: {
- email: 'user@example.com',
- signupVerificationRequestedAt: 123,
- },
- },
- ]);
- assert.deepStrictEqual(response, { ok: true });
- });
- test('message router marks step 3 failed when post-submit finalize fails', async () => {
- const { router, events } = createRouter({
- finalizeStep3Completion: async () => {
- throw new Error('步骤 3 提交后仍停留在密码页。');
- },
- });
- const response = await router.handleMessage({
- type: 'STEP_COMPLETE',
- step: 3,
- source: 'signup-page',
- payload: {
- email: 'user@example.com',
- },
- }, {});
- assert.deepStrictEqual(events.stepStatuses, [{ step: 3, status: 'failed' }]);
- assert.deepStrictEqual(events.notifyErrors, [
- {
- step: 3,
- error: '步骤 3 提交后仍停留在密码页。',
- },
- ]);
- assert.equal(events.logs.some(({ message }) => /步骤 3 失败:步骤 3 提交后仍停留在密码页。/.test(message)), true);
- assert.deepStrictEqual(response, { ok: true, error: '步骤 3 提交后仍停留在密码页。' });
- });
- test('message router suppresses duplicate content ready logs for same source tab', async () => {
- const { router, events } = createRouter();
- await router.handleMessage({
- type: 'CONTENT_SCRIPT_READY',
- source: 'checkout-stripe',
- }, { tab: { id: 662543926 } });
- await router.handleMessage({
- type: 'CONTENT_SCRIPT_READY',
- source: 'checkout-stripe',
- }, { tab: { id: 662543926 } });
- assert.deepStrictEqual(
- events.logs.filter((entry) => /内容脚本已就绪/.test(entry.message)).map((entry) => entry.message),
- ['内容脚本已就绪:(标签页 662543926)']
- );
- });
|