|
|
@@ -0,0 +1,127 @@
|
|
|
+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: [],
|
|
|
+ };
|
|
|
+
|
|
|
+ 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 () => '',
|
|
|
+ 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: () => {},
|
|
|
+ notifyStepError: () => {},
|
|
|
+ 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, []);
|
|
|
+});
|