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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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, keeps 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, 3, '旧的 stopped 记录应在新结构中保留');
  88. assert.equal(storedHistory.some((item) => item.email === 'stop@example.com' && item.finalStatus === 'stopped'), true);
  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. const stoppedRecord = helpers.buildAccountRunHistoryRecord({ email: 'a@b.com', password: 'x' }, 'stopped', 'stop');
  95. assert.equal(stoppedRecord.recordId, 'a@b.com');
  96. assert.equal(stoppedRecord.email, 'a@b.com');
  97. assert.equal(stoppedRecord.password, 'x');
  98. assert.equal(stoppedRecord.finalStatus, 'stopped');
  99. assert.equal(stoppedRecord.retryCount, 0);
  100. assert.equal(stoppedRecord.failureLabel, '流程已停止');
  101. assert.equal(stoppedRecord.failureDetail, 'stop');
  102. assert.equal(stoppedRecord.failedStep, null);
  103. assert.equal(stoppedRecord.source, 'manual');
  104. assert.equal(stoppedRecord.autoRunContext, null);
  105. assert.ok(stoppedRecord.finishedAt);
  106. });
  107. test('account run history helper clears persisted records and syncs full snapshot payload to local helper', async () => {
  108. const source = fs.readFileSync('background/account-run-history.js', 'utf8');
  109. const globalScope = {};
  110. const api = new Function('self', `${source}; return self.MultiPageBackgroundAccountRunHistory;`)(globalScope);
  111. let storedHistory = [{
  112. recordId: 'user@example.com',
  113. email: 'user@example.com',
  114. password: 'secret',
  115. finalStatus: 'failed',
  116. finishedAt: '2026-04-17T01:00:00.000Z',
  117. retryCount: 1,
  118. failureLabel: '步骤 6 失败',
  119. failureDetail: '步骤 6:判断失败后已重试 2 次,仍未成功。',
  120. failedStep: 6,
  121. source: 'auto',
  122. autoRunContext: {
  123. currentRun: 1,
  124. totalRuns: 5,
  125. attemptRun: 2,
  126. },
  127. }];
  128. const fetchCalls = [];
  129. global.fetch = async (url, options = {}) => {
  130. fetchCalls.push({
  131. url,
  132. options,
  133. });
  134. return {
  135. ok: true,
  136. json: async () => ({
  137. ok: true,
  138. filePath: 'C:/tmp/account-run-history.json',
  139. }),
  140. };
  141. };
  142. const logs = [];
  143. const helpers = api.createAccountRunHistoryHelpers({
  144. ACCOUNT_RUN_HISTORY_STORAGE_KEY: 'accountRunHistory',
  145. addLog: async (message, level) => {
  146. logs.push({ message, level });
  147. },
  148. buildLocalHelperEndpoint: (baseUrl, path) => `${baseUrl}${path}`,
  149. chrome: {
  150. storage: {
  151. local: {
  152. get: async () => ({ accountRunHistory: storedHistory }),
  153. set: async (payload) => {
  154. storedHistory = payload.accountRunHistory;
  155. },
  156. },
  157. },
  158. },
  159. getErrorMessage: (error) => error?.message || String(error || ''),
  160. getState: async () => ({
  161. accountRunHistoryTextEnabled: true,
  162. accountRunHistoryHelperBaseUrl: 'http://127.0.0.1:17373',
  163. }),
  164. normalizeAccountRunHistoryHelperBaseUrl: (value) => String(value || '').trim(),
  165. });
  166. const payload = helpers.buildAccountRunHistorySnapshotPayload(storedHistory);
  167. assert.deepStrictEqual(payload.summary, {
  168. total: 1,
  169. success: 0,
  170. failed: 1,
  171. stopped: 0,
  172. retryTotal: 1,
  173. });
  174. const clearResult = await helpers.clearAccountRunHistory();
  175. assert.deepStrictEqual(clearResult, { clearedCount: 1 });
  176. assert.deepStrictEqual(storedHistory, []);
  177. assert.equal(fetchCalls.length, 1);
  178. assert.equal(fetchCalls[0].url, 'http://127.0.0.1:17373/sync-account-run-records');
  179. assert.deepStrictEqual(JSON.parse(fetchCalls[0].options.body), {
  180. generatedAt: JSON.parse(fetchCalls[0].options.body).generatedAt,
  181. summary: {
  182. total: 0,
  183. success: 0,
  184. failed: 0,
  185. stopped: 0,
  186. retryTotal: 0,
  187. },
  188. records: [],
  189. });
  190. assert.equal(logs[0].message, '账号记录快照已同步到本地:C:/tmp/account-run-history.json');
  191. });