background-account-run-history-module.test.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. const test = require('node:test');
  2. const assert = require('node:assert/strict');
  3. const fs = require('node:fs');
  4. test('background imports account run history module', () => {
  5. const source = fs.readFileSync('background.js', 'utf8');
  6. assert.match(source, /background\/account-run-history\.js/);
  7. });
  8. test('account run history module exposes a factory', () => {
  9. const source = fs.readFileSync('background/account-run-history.js', 'utf8');
  10. const globalScope = {};
  11. const api = new Function('self', `${source}; return self.MultiPageBackgroundAccountRunHistory;`)(globalScope);
  12. assert.equal(typeof api?.createAccountRunHistoryHelpers, 'function');
  13. });
  14. test('account run history helper upgrades old records, filters stopped items and stores normalized failed snapshot records', async () => {
  15. const source = fs.readFileSync('background/account-run-history.js', 'utf8');
  16. const globalScope = {};
  17. const api = new Function('self', `${source}; return self.MultiPageBackgroundAccountRunHistory;`)(globalScope);
  18. let storedHistory = [
  19. { email: 'old@example.com', password: 'old-pass', status: 'success', recordedAt: '2026-04-17T00:00:00.000Z' },
  20. { email: 'stop@example.com', password: 'stop-pass', status: 'stopped', recordedAt: '2026-04-17T00:10:00.000Z' },
  21. ];
  22. let fetchCalled = false;
  23. global.fetch = async () => {
  24. fetchCalled = true;
  25. throw new Error('should not call fetch');
  26. };
  27. const helpers = api.createAccountRunHistoryHelpers({
  28. ACCOUNT_RUN_HISTORY_STORAGE_KEY: 'accountRunHistory',
  29. addLog: async () => {},
  30. buildLocalHelperEndpoint: (baseUrl, path) => `${baseUrl}${path}`,
  31. chrome: {
  32. storage: {
  33. local: {
  34. get: async () => ({ accountRunHistory: storedHistory }),
  35. set: async (payload) => {
  36. storedHistory = payload.accountRunHistory;
  37. },
  38. },
  39. },
  40. },
  41. getErrorMessage: (error) => error?.message || String(error || ''),
  42. getState: async () => ({
  43. email: ' latest@example.com ',
  44. password: ' secret ',
  45. autoRunning: true,
  46. autoRunCurrentRun: 2,
  47. autoRunTotalRuns: 10,
  48. autoRunAttemptRun: 3,
  49. accountRunHistoryTextEnabled: false,
  50. accountRunHistoryHelperBaseUrl: '',
  51. }),
  52. normalizeAccountRunHistoryHelperBaseUrl: (value) => String(value || '').trim(),
  53. });
  54. const record = helpers.buildAccountRunHistoryRecord(
  55. {
  56. email: ' latest@example.com ',
  57. password: ' secret ',
  58. autoRunning: true,
  59. autoRunCurrentRun: 2,
  60. autoRunTotalRuns: 10,
  61. autoRunAttemptRun: 3,
  62. },
  63. 'step8_failed',
  64. '步骤 8:认证页进入了手机号页面,当前不是 OAuth 同意页,无法继续自动授权。'
  65. );
  66. assert.deepStrictEqual(record, {
  67. recordId: 'latest@example.com',
  68. email: 'latest@example.com',
  69. password: 'secret',
  70. finalStatus: 'failed',
  71. finishedAt: record.finishedAt,
  72. retryCount: 2,
  73. failureLabel: '出现手机号验证',
  74. failureDetail: '步骤 8:认证页进入了手机号页面,当前不是 OAuth 同意页,无法继续自动授权。',
  75. failedStep: 8,
  76. source: 'auto',
  77. autoRunContext: {
  78. currentRun: 2,
  79. totalRuns: 10,
  80. attemptRun: 3,
  81. },
  82. });
  83. const appended = await helpers.appendAccountRunRecord('step8_failed', null, '步骤 8:认证页进入了手机号页面,当前不是 OAuth 同意页,无法继续自动授权。');
  84. assert.equal(appended.email, 'latest@example.com');
  85. assert.equal(appended.finalStatus, 'failed');
  86. assert.equal(appended.failureLabel, '出现手机号验证');
  87. assert.equal(storedHistory.length, 2, '旧的 stopped 记录应在新结构中被过滤掉');
  88. assert.equal(storedHistory.some((item) => item.email === 'stop@example.com'), false);
  89. assert.equal(storedHistory.some((item) => item.email === 'latest@example.com' && item.retryCount === 2), true);
  90. assert.equal(storedHistory.some((item) => item.email === 'old@example.com'), true);
  91. assert.equal(fetchCalled, false);
  92. assert.equal(helpers.shouldAppendAccountRunTextFile({ accountRunHistoryTextEnabled: false, accountRunHistoryHelperBaseUrl: 'http://127.0.0.1:17373' }), false);
  93. assert.equal(helpers.shouldAppendAccountRunTextFile({ accountRunHistoryTextEnabled: true, accountRunHistoryHelperBaseUrl: 'http://127.0.0.1:17373' }), true);
  94. assert.equal(helpers.buildAccountRunHistoryRecord({ email: 'a@b.com', password: 'x' }, 'stopped', 'stop'), null);
  95. });
  96. test('account run history helper clears persisted records and syncs full snapshot payload to local helper', async () => {
  97. const source = fs.readFileSync('background/account-run-history.js', 'utf8');
  98. const globalScope = {};
  99. const api = new Function('self', `${source}; return self.MultiPageBackgroundAccountRunHistory;`)(globalScope);
  100. let storedHistory = [{
  101. recordId: 'user@example.com',
  102. email: 'user@example.com',
  103. password: 'secret',
  104. finalStatus: 'failed',
  105. finishedAt: '2026-04-17T01:00:00.000Z',
  106. retryCount: 1,
  107. failureLabel: '步骤 6 失败',
  108. failureDetail: '步骤 6:判断失败后已重试 2 次,仍未成功。',
  109. failedStep: 6,
  110. source: 'auto',
  111. autoRunContext: {
  112. currentRun: 1,
  113. totalRuns: 5,
  114. attemptRun: 2,
  115. },
  116. }];
  117. const fetchCalls = [];
  118. global.fetch = async (url, options = {}) => {
  119. fetchCalls.push({
  120. url,
  121. options,
  122. });
  123. return {
  124. ok: true,
  125. json: async () => ({
  126. ok: true,
  127. filePath: 'C:/tmp/account-run-history.json',
  128. }),
  129. };
  130. };
  131. const logs = [];
  132. const helpers = api.createAccountRunHistoryHelpers({
  133. ACCOUNT_RUN_HISTORY_STORAGE_KEY: 'accountRunHistory',
  134. addLog: async (message, level) => {
  135. logs.push({ message, level });
  136. },
  137. buildLocalHelperEndpoint: (baseUrl, path) => `${baseUrl}${path}`,
  138. chrome: {
  139. storage: {
  140. local: {
  141. get: async () => ({ accountRunHistory: storedHistory }),
  142. set: async (payload) => {
  143. storedHistory = payload.accountRunHistory;
  144. },
  145. },
  146. },
  147. },
  148. getErrorMessage: (error) => error?.message || String(error || ''),
  149. getState: async () => ({
  150. accountRunHistoryTextEnabled: true,
  151. accountRunHistoryHelperBaseUrl: 'http://127.0.0.1:17373',
  152. }),
  153. normalizeAccountRunHistoryHelperBaseUrl: (value) => String(value || '').trim(),
  154. });
  155. const payload = helpers.buildAccountRunHistorySnapshotPayload(storedHistory);
  156. assert.deepStrictEqual(payload.summary, {
  157. total: 1,
  158. success: 0,
  159. failed: 1,
  160. retryTotal: 1,
  161. });
  162. const clearResult = await helpers.clearAccountRunHistory();
  163. assert.deepStrictEqual(clearResult, { clearedCount: 1 });
  164. assert.deepStrictEqual(storedHistory, []);
  165. assert.equal(fetchCalls.length, 1);
  166. assert.equal(fetchCalls[0].url, 'http://127.0.0.1:17373/sync-account-run-records');
  167. assert.deepStrictEqual(JSON.parse(fetchCalls[0].options.body), {
  168. generatedAt: JSON.parse(fetchCalls[0].options.body).generatedAt,
  169. summary: {
  170. total: 0,
  171. success: 0,
  172. failed: 0,
  173. retryTotal: 0,
  174. },
  175. records: [],
  176. });
  177. assert.equal(logs[0].message, '账号记录快照已同步到本地:C:/tmp/account-run-history.json');
  178. });