verification-flow-polling.test.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. const test = require('node:test');
  2. const assert = require('node:assert/strict');
  3. const fs = require('node:fs');
  4. const source = fs.readFileSync('background/verification-flow.js', 'utf8');
  5. const globalScope = {};
  6. const api = new Function('self', `${source}; return self.MultiPageBackgroundVerificationFlow;`)(globalScope);
  7. test('verification flow extends 2925 polling window', () => {
  8. const helpers = api.createVerificationFlowHelpers({
  9. A4SKY_PROVIDER: 'a4sky',
  10. addLog: async () => {},
  11. chrome: { tabs: { update: async () => {} } },
  12. CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
  13. completeStepFromBackground: async () => {},
  14. confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
  15. getHotmailVerificationPollConfig: () => ({}),
  16. getHotmailVerificationRequestTimestamp: () => 0,
  17. getState: async () => ({}),
  18. getTabId: async () => 1,
  19. HOTMAIL_PROVIDER: 'hotmail-api',
  20. isStopError: () => false,
  21. LUCKMAIL_PROVIDER: 'luckmail-api',
  22. MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
  23. MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
  24. pollA4skyImapVerificationCode: async () => ({}),
  25. pollCloudflareTempEmailVerificationCode: async () => ({}),
  26. pollHotmailVerificationCode: async () => ({}),
  27. pollLuckmailVerificationCode: async () => ({}),
  28. sendToContentScript: async () => ({}),
  29. sendToMailContentScriptResilient: async () => ({}),
  30. setState: async () => {},
  31. setStepStatus: async () => {},
  32. sleepWithStop: async () => {},
  33. throwIfStopped: () => {},
  34. VERIFICATION_POLL_MAX_ROUNDS: 5,
  35. });
  36. const step4Payload = helpers.getVerificationPollPayload(4, { email: 'user@example.com', mailProvider: '2925' });
  37. const step8Payload = helpers.getVerificationPollPayload(8, { email: 'user@example.com', mailProvider: '2925' });
  38. assert.equal(step4Payload.maxAttempts, 15);
  39. assert.equal(step4Payload.intervalMs, 15000);
  40. assert.equal(step8Payload.maxAttempts, 15);
  41. assert.equal(step8Payload.intervalMs, 15000);
  42. });
  43. test('verification flow routes A4Sky provider to IMAP helper polling', async () => {
  44. let capturedPayload = null;
  45. const helpers = api.createVerificationFlowHelpers({
  46. A4SKY_PROVIDER: 'a4sky',
  47. addLog: async () => {},
  48. chrome: { tabs: { update: async () => {} } },
  49. CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
  50. completeStepFromBackground: async () => {},
  51. confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
  52. getHotmailVerificationPollConfig: () => ({}),
  53. getHotmailVerificationRequestTimestamp: () => 123,
  54. getState: async () => ({}),
  55. getTabId: async () => 1,
  56. HOTMAIL_PROVIDER: 'hotmail-api',
  57. isStopError: () => false,
  58. LUCKMAIL_PROVIDER: 'luckmail-api',
  59. MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
  60. MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
  61. pollA4skyImapVerificationCode: async (_step, _state, payload) => {
  62. capturedPayload = payload;
  63. return { code: '123456', emailTimestamp: 1 };
  64. },
  65. pollCloudflareTempEmailVerificationCode: async () => ({}),
  66. pollHotmailVerificationCode: async () => ({}),
  67. pollLuckmailVerificationCode: async () => ({}),
  68. sendToContentScript: async () => ({}),
  69. sendToMailContentScriptResilient: async () => ({}),
  70. setState: async () => {},
  71. setStepStatus: async () => {},
  72. sleepWithStop: async () => {},
  73. throwIfStopped: () => {},
  74. VERIFICATION_POLL_MAX_ROUNDS: 5,
  75. });
  76. const result = await helpers.pollFreshVerificationCode(4, {
  77. email: 'target@a4sky.com',
  78. mailProvider: 'a4sky',
  79. }, {
  80. provider: 'a4sky',
  81. label: 'A4Sky',
  82. }, {
  83. filterAfterTimestamp: 555,
  84. });
  85. assert.equal(result.code, '123456');
  86. assert.equal(capturedPayload.filterAfterTimestamp, 555);
  87. assert.equal(capturedPayload.targetEmail, 'target@a4sky.com');
  88. });
  89. test('verification flow runs beforeSubmit hook before filling the code', async () => {
  90. const events = [];
  91. const helpers = api.createVerificationFlowHelpers({
  92. addLog: async () => {},
  93. chrome: {
  94. tabs: {
  95. update: async () => {},
  96. },
  97. },
  98. CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
  99. completeStepFromBackground: async (_step, payload) => {
  100. events.push(['complete', payload.code]);
  101. },
  102. confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
  103. getHotmailVerificationPollConfig: () => ({}),
  104. getHotmailVerificationRequestTimestamp: () => 0,
  105. getState: async () => ({}),
  106. getTabId: async () => 1,
  107. HOTMAIL_PROVIDER: 'hotmail-api',
  108. isStopError: () => false,
  109. LUCKMAIL_PROVIDER: 'luckmail-api',
  110. MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
  111. MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
  112. pollCloudflareTempEmailVerificationCode: async () => ({}),
  113. pollHotmailVerificationCode: async () => ({}),
  114. pollLuckmailVerificationCode: async () => ({}),
  115. sendToContentScript: async (_source, message) => {
  116. if (message.type === 'FILL_CODE') {
  117. events.push(['submit', message.payload.code]);
  118. return {};
  119. }
  120. return {};
  121. },
  122. sendToMailContentScriptResilient: async () => ({
  123. code: '654321',
  124. emailTimestamp: 123,
  125. }),
  126. setState: async (payload) => {
  127. events.push(['state', payload.lastLoginCode || payload.lastSignupCode]);
  128. },
  129. setStepStatus: async () => {},
  130. sleepWithStop: async () => {},
  131. throwIfStopped: () => {},
  132. VERIFICATION_POLL_MAX_ROUNDS: 5,
  133. });
  134. await helpers.resolveVerificationStep(
  135. 7,
  136. { email: 'user@example.com', lastLoginCode: null },
  137. { provider: 'qq', label: 'QQ 邮箱' },
  138. {
  139. beforeSubmit: async (result) => {
  140. events.push(['beforeSubmit', result.code]);
  141. },
  142. }
  143. );
  144. assert.deepStrictEqual(events, [
  145. ['beforeSubmit', '654321'],
  146. ['state', '654321'],
  147. ['submit', '654321'],
  148. ['state', '654321'],
  149. ['complete', '654321'],
  150. ]);
  151. });
  152. test('verification flow excludes the previously submitted code on the next retry', async () => {
  153. const pollPayloads = [];
  154. let currentState = {
  155. email: 'user@example.com',
  156. signupVerificationRequestedAt: 0,
  157. lastSignupCode: null,
  158. };
  159. let submitCount = 0;
  160. const helpers = api.createVerificationFlowHelpers({
  161. addLog: async () => {},
  162. chrome: { tabs: { update: async () => {} } },
  163. CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
  164. completeStepFromBackground: async () => {},
  165. confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
  166. getHotmailVerificationPollConfig: () => ({}),
  167. getHotmailVerificationRequestTimestamp: () => 0,
  168. getState: async () => currentState,
  169. getTabId: async () => 1,
  170. HOTMAIL_PROVIDER: 'hotmail-api',
  171. isStopError: () => false,
  172. LUCKMAIL_PROVIDER: 'luckmail-api',
  173. MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
  174. MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
  175. pollCloudflareTempEmailVerificationCode: async () => ({}),
  176. pollHotmailVerificationCode: async (_step, _state, payload) => {
  177. pollPayloads.push(payload);
  178. return {
  179. code: Array.isArray(payload.excludeCodes) && payload.excludeCodes.includes('111111') ? '222222' : '111111',
  180. emailTimestamp: Date.now(),
  181. };
  182. },
  183. pollLuckmailVerificationCode: async () => ({}),
  184. sendToContentScript: async (_source, message) => {
  185. if (message.type === 'FILL_CODE') {
  186. submitCount += 1;
  187. if (submitCount === 1) {
  188. throw new Error('页面通信异常');
  189. }
  190. return {};
  191. }
  192. return {};
  193. },
  194. sendToMailContentScriptResilient: async () => ({}),
  195. setState: async (payload) => {
  196. currentState = { ...currentState, ...payload };
  197. },
  198. setStepStatus: async () => {},
  199. sleepWithStop: async () => {},
  200. throwIfStopped: () => {},
  201. VERIFICATION_POLL_MAX_ROUNDS: 5,
  202. });
  203. await assert.rejects(
  204. () => helpers.resolveVerificationStep(
  205. 4,
  206. currentState,
  207. { provider: 'hotmail-api', label: 'Hotmail' },
  208. {}
  209. ),
  210. /页面通信异常/
  211. );
  212. assert.equal(currentState.lastSignupCode, '111111');
  213. await helpers.resolveVerificationStep(
  214. 4,
  215. currentState,
  216. { provider: 'hotmail-api', label: 'Hotmail' },
  217. {}
  218. );
  219. assert.equal(currentState.lastSignupCode, '222222');
  220. assert.ok(
  221. pollPayloads.some((payload) => Array.isArray(payload.excludeCodes) && payload.excludeCodes.includes('111111')),
  222. 'next retry should exclude the previously submitted code'
  223. );
  224. });
  225. test('verification flow treats add-phone after login code submit as fatal instead of completing step 8', async () => {
  226. const events = [];
  227. const helpers = api.createVerificationFlowHelpers({
  228. addLog: async () => {},
  229. chrome: {
  230. tabs: {
  231. update: async () => {},
  232. },
  233. },
  234. CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
  235. completeStepFromBackground: async (_step, payload) => {
  236. events.push(['complete', payload.code]);
  237. },
  238. confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
  239. getHotmailVerificationPollConfig: () => ({}),
  240. getHotmailVerificationRequestTimestamp: () => 0,
  241. getState: async () => ({}),
  242. getTabId: async () => 1,
  243. HOTMAIL_PROVIDER: 'hotmail-api',
  244. isStopError: () => false,
  245. LUCKMAIL_PROVIDER: 'luckmail-api',
  246. MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
  247. MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
  248. pollCloudflareTempEmailVerificationCode: async () => ({}),
  249. pollHotmailVerificationCode: async () => ({}),
  250. pollLuckmailVerificationCode: async () => ({}),
  251. sendToContentScript: async (_source, message) => {
  252. if (message.type === 'FILL_CODE') {
  253. events.push(['submit', message.payload.code]);
  254. return {
  255. addPhonePage: true,
  256. url: 'https://auth.openai.com/add-phone',
  257. };
  258. }
  259. return {};
  260. },
  261. sendToMailContentScriptResilient: async () => ({
  262. code: '654321',
  263. emailTimestamp: 123,
  264. }),
  265. setState: async (payload) => {
  266. events.push(['state', payload.lastLoginCode || payload.lastSignupCode]);
  267. },
  268. setStepStatus: async () => {},
  269. sleepWithStop: async () => {},
  270. throwIfStopped: () => {},
  271. VERIFICATION_POLL_MAX_ROUNDS: 5,
  272. });
  273. await assert.rejects(
  274. () => helpers.resolveVerificationStep(
  275. 8,
  276. { email: 'user@example.com', lastLoginCode: null },
  277. { provider: 'qq', label: 'QQ 邮箱' },
  278. {}
  279. ),
  280. /验证码提交后页面进入手机号页面/
  281. );
  282. assert.deepStrictEqual(events, [
  283. ['state', '654321'],
  284. ['submit', '654321'],
  285. ]);
  286. });
  287. test('verification flow caps mail polling timeout to the remaining oauth budget', async () => {
  288. const mailPollCalls = [];
  289. const helpers = api.createVerificationFlowHelpers({
  290. addLog: async () => {},
  291. chrome: {
  292. tabs: {
  293. update: async () => {},
  294. },
  295. },
  296. CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
  297. completeStepFromBackground: async () => {},
  298. confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
  299. getHotmailVerificationPollConfig: () => ({}),
  300. getHotmailVerificationRequestTimestamp: () => 0,
  301. getState: async () => ({}),
  302. getTabId: async () => 1,
  303. HOTMAIL_PROVIDER: 'hotmail-api',
  304. isStopError: () => false,
  305. LUCKMAIL_PROVIDER: 'luckmail-api',
  306. MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
  307. MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
  308. pollCloudflareTempEmailVerificationCode: async () => ({}),
  309. pollHotmailVerificationCode: async () => ({}),
  310. pollLuckmailVerificationCode: async () => ({}),
  311. sendToContentScript: async (_source, message) => {
  312. if (message.type === 'FILL_CODE') {
  313. return {};
  314. }
  315. return {};
  316. },
  317. sendToMailContentScriptResilient: async (_mail, message, options) => {
  318. mailPollCalls.push({
  319. payload: message.payload,
  320. options,
  321. });
  322. return { code: '654321', emailTimestamp: 123 };
  323. },
  324. setState: async () => {},
  325. setStepStatus: async () => {},
  326. sleepWithStop: async () => {},
  327. throwIfStopped: () => {},
  328. VERIFICATION_POLL_MAX_ROUNDS: 5,
  329. });
  330. await helpers.resolveVerificationStep(
  331. 8,
  332. {
  333. email: 'user@example.com',
  334. lastLoginCode: null,
  335. },
  336. { provider: 'qq', label: 'QQ 邮箱' },
  337. {
  338. getRemainingTimeMs: async () => 5000,
  339. resendIntervalMs: 0,
  340. }
  341. );
  342. assert.ok(mailPollCalls.length >= 1);
  343. assert.equal(mailPollCalls[0].options.timeoutMs, 5000);
  344. assert.equal(mailPollCalls[0].options.responseTimeoutMs, 5000);
  345. assert.equal(mailPollCalls[0].payload.maxAttempts, 2);
  346. });
  347. test('verification flow keeps Hotmail request timestamp filtering on the first poll', async () => {
  348. const pollPayloads = [];
  349. const helpers = api.createVerificationFlowHelpers({
  350. addLog: async () => {},
  351. chrome: { tabs: { update: async () => {} } },
  352. CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
  353. completeStepFromBackground: async () => {},
  354. confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
  355. getHotmailVerificationPollConfig: () => ({}),
  356. getHotmailVerificationRequestTimestamp: () => 87654,
  357. getState: async () => ({}),
  358. getTabId: async () => 1,
  359. HOTMAIL_PROVIDER: 'hotmail-api',
  360. isStopError: () => false,
  361. LUCKMAIL_PROVIDER: 'luckmail-api',
  362. MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
  363. MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
  364. pollCloudflareTempEmailVerificationCode: async () => ({}),
  365. pollHotmailVerificationCode: async (_step, _state, payload) => {
  366. pollPayloads.push(payload);
  367. return { code: '654321', emailTimestamp: 123 };
  368. },
  369. pollLuckmailVerificationCode: async () => ({}),
  370. sendToContentScript: async (_source, message) => {
  371. if (message.type === 'FILL_CODE') {
  372. return {};
  373. }
  374. return {};
  375. },
  376. sendToMailContentScriptResilient: async () => ({}),
  377. setState: async () => {},
  378. setStepStatus: async () => {},
  379. sleepWithStop: async () => {},
  380. throwIfStopped: () => {},
  381. VERIFICATION_POLL_MAX_ROUNDS: 5,
  382. });
  383. await helpers.resolveVerificationStep(
  384. 7,
  385. {
  386. email: 'user@example.com',
  387. loginVerificationRequestedAt: 100000,
  388. lastLoginCode: null,
  389. },
  390. { provider: 'hotmail-api', label: 'Hotmail' },
  391. {}
  392. );
  393. assert.equal(pollPayloads.length, 1);
  394. assert.equal(pollPayloads[0].filterAfterTimestamp, 87654);
  395. });
  396. test('verification flow keeps fixed filter timestamp after step 4 resend', async () => {
  397. const pollPayloads = [];
  398. let submitCount = 0;
  399. const helpers = api.createVerificationFlowHelpers({
  400. addLog: async () => {},
  401. chrome: { tabs: { update: async () => {} } },
  402. CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
  403. completeStepFromBackground: async () => {},
  404. confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
  405. getHotmailVerificationPollConfig: () => ({}),
  406. getHotmailVerificationRequestTimestamp: (_step, state) => Math.max(0, Number(state.signupVerificationRequestedAt || 0) - 15000),
  407. getState: async () => ({}),
  408. getTabId: async () => 1,
  409. HOTMAIL_PROVIDER: 'hotmail-api',
  410. isStopError: () => false,
  411. LUCKMAIL_PROVIDER: 'luckmail-api',
  412. MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
  413. MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
  414. pollCloudflareTempEmailVerificationCode: async () => ({}),
  415. pollHotmailVerificationCode: async (_step, _state, payload) => {
  416. pollPayloads.push(payload);
  417. return {
  418. code: pollPayloads.length === 1 ? '111111' : '222222',
  419. emailTimestamp: pollPayloads.length,
  420. };
  421. },
  422. pollLuckmailVerificationCode: async () => ({}),
  423. sendToContentScript: async (_source, message) => {
  424. if (message.type === 'FILL_CODE') {
  425. submitCount += 1;
  426. return submitCount === 1
  427. ? { invalidCode: true, errorText: '旧验证码' }
  428. : {};
  429. }
  430. if (message.type === 'RESEND_VERIFICATION_CODE') {
  431. return {};
  432. }
  433. return {};
  434. },
  435. sendToMailContentScriptResilient: async () => ({}),
  436. setState: async () => {},
  437. setStepStatus: async () => {},
  438. sleepWithStop: async () => {},
  439. throwIfStopped: () => {},
  440. VERIFICATION_POLL_MAX_ROUNDS: 5,
  441. });
  442. await helpers.resolveVerificationStep(
  443. 4,
  444. {
  445. email: 'user@example.com',
  446. signupVerificationRequestedAt: 100000,
  447. lastSignupCode: null,
  448. },
  449. { provider: 'hotmail-api', label: 'Hotmail' },
  450. {
  451. filterAfterTimestamp: 123456,
  452. }
  453. );
  454. assert.equal(pollPayloads.length, 2);
  455. assert.equal(pollPayloads[0].filterAfterTimestamp, 123456);
  456. assert.equal(pollPayloads[1].filterAfterTimestamp, 123456);
  457. });
  458. test('verification flow uses configured signup resend count for step 4', async () => {
  459. const resendSteps = [];
  460. let pollCalls = 0;
  461. const helpers = api.createVerificationFlowHelpers({
  462. addLog: async () => {},
  463. chrome: { tabs: { update: async () => {} } },
  464. CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
  465. completeStepFromBackground: async () => {},
  466. confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
  467. getHotmailVerificationPollConfig: () => ({}),
  468. getHotmailVerificationRequestTimestamp: () => 0,
  469. getState: async () => ({}),
  470. getTabId: async () => 1,
  471. HOTMAIL_PROVIDER: 'hotmail-api',
  472. isStopError: () => false,
  473. LUCKMAIL_PROVIDER: 'luckmail-api',
  474. MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
  475. MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
  476. pollCloudflareTempEmailVerificationCode: async () => ({}),
  477. pollHotmailVerificationCode: async () => ({}),
  478. pollLuckmailVerificationCode: async () => ({}),
  479. sendToContentScript: async (_source, message) => {
  480. if (message.type === 'RESEND_VERIFICATION_CODE') {
  481. resendSteps.push(message.step);
  482. }
  483. return {};
  484. },
  485. sendToMailContentScriptResilient: async () => {
  486. pollCalls += 1;
  487. return pollCalls === 2
  488. ? { code: '654321', emailTimestamp: 123 }
  489. : {};
  490. },
  491. setState: async () => {},
  492. setStepStatus: async () => {},
  493. sleepWithStop: async () => {},
  494. throwIfStopped: () => {},
  495. VERIFICATION_POLL_MAX_ROUNDS: 5,
  496. });
  497. await helpers.resolveVerificationStep(
  498. 4,
  499. {
  500. email: 'user@example.com',
  501. verificationResendCount: 2,
  502. lastSignupCode: null,
  503. },
  504. { provider: 'qq', label: 'QQ 邮箱' },
  505. {
  506. requestFreshCodeFirst: true,
  507. resendIntervalMs: 0,
  508. }
  509. );
  510. assert.deepStrictEqual(resendSteps, [4, 4]);
  511. assert.equal(pollCalls, 2);
  512. });
  513. test('verification flow uses configured login resend count for step 8', async () => {
  514. const resendSteps = [];
  515. let pollCalls = 0;
  516. const helpers = api.createVerificationFlowHelpers({
  517. addLog: async () => {},
  518. chrome: { tabs: { update: async () => {} } },
  519. CLOUDFLARE_TEMP_EMAIL_PROVIDER: 'cloudflare-temp-email',
  520. completeStepFromBackground: async () => {},
  521. confirmCustomVerificationStepBypassRequest: async () => ({ confirmed: true }),
  522. getHotmailVerificationPollConfig: () => ({}),
  523. getHotmailVerificationRequestTimestamp: () => 0,
  524. getState: async () => ({}),
  525. getTabId: async () => 1,
  526. HOTMAIL_PROVIDER: 'hotmail-api',
  527. isStopError: () => false,
  528. LUCKMAIL_PROVIDER: 'luckmail-api',
  529. MAIL_2925_VERIFICATION_INTERVAL_MS: 15000,
  530. MAIL_2925_VERIFICATION_MAX_ATTEMPTS: 15,
  531. pollCloudflareTempEmailVerificationCode: async () => ({}),
  532. pollHotmailVerificationCode: async () => ({}),
  533. pollLuckmailVerificationCode: async () => ({}),
  534. sendToContentScript: async (_source, message) => {
  535. if (message.type === 'RESEND_VERIFICATION_CODE') {
  536. resendSteps.push(message.step);
  537. }
  538. return {};
  539. },
  540. sendToMailContentScriptResilient: async () => {
  541. pollCalls += 1;
  542. return pollCalls === 3
  543. ? { code: '654321', emailTimestamp: 123 }
  544. : {};
  545. },
  546. setState: async () => {},
  547. setStepStatus: async () => {},
  548. sleepWithStop: async () => {},
  549. throwIfStopped: () => {},
  550. VERIFICATION_POLL_MAX_ROUNDS: 5,
  551. });
  552. await helpers.resolveVerificationStep(
  553. 8,
  554. {
  555. email: 'user@example.com',
  556. verificationResendCount: 2,
  557. lastLoginCode: null,
  558. },
  559. { provider: 'qq', label: 'QQ 邮箱' },
  560. {
  561. requestFreshCodeFirst: false,
  562. resendIntervalMs: 0,
  563. }
  564. );
  565. assert.deepStrictEqual(resendSteps, [8, 8]);
  566. assert.equal(pollCalls, 3);
  567. });