reporter-spec.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. const Reporter = require('../lib/reporter');
  2. const semver = require('semver');
  3. const os = require('os');
  4. const path = require('path');
  5. let osVersion = `${os.platform()}-${os.arch()}-${os.release()}`;
  6. let getReleaseChannel = version => {
  7. return version.indexOf('beta') > -1
  8. ? 'beta'
  9. : version.indexOf('dev') > -1
  10. ? 'dev'
  11. : 'stable';
  12. };
  13. // describe('Reporter', () => {
  14. // let reporter,
  15. // requests,
  16. // initialStackTraceLimit,
  17. // initialHomeDirectory,
  18. // mockActivePackages;
  19. //
  20. // beforeEach(() => {
  21. // reporter = new Reporter({
  22. // request: (url, options) => requests.push(Object.assign({ url }, options)),
  23. // alwaysReport: true,
  24. // reportPreviousErrors: false
  25. // });
  26. // requests = [];
  27. // mockActivePackages = [];
  28. // spyOn(atom.packages, 'getActivePackages').andCallFake(
  29. // () => mockActivePackages
  30. // );
  31. //
  32. // initialStackTraceLimit = Error.stackTraceLimit;
  33. // Error.stackTraceLimit = 1;
  34. //
  35. // initialHomeDirectory = process.env.HOME;
  36. // });
  37. //
  38. // afterEach(() => {
  39. // process.env.HOME = initialHomeDirectory;
  40. // Error.stackTraceLimit = initialStackTraceLimit;
  41. // });
  42. //
  43. // describe('.reportUncaughtException(error)', () => {
  44. // it('posts errors originated inside Pulsar Core to BugSnag', () => {
  45. // const repositoryRootPath = path.join(__dirname, '..');
  46. // reporter = new Reporter({
  47. // request: (url, options) =>
  48. // requests.push(Object.assign({ url }, options)),
  49. // alwaysReport: true,
  50. // reportPreviousErrors: false,
  51. // resourcePath: repositoryRootPath
  52. // });
  53. //
  54. // let error = new Error();
  55. // Error.captureStackTrace(error);
  56. // reporter.reportUncaughtException(error);
  57. // let [lineNumber, columnNumber] = error.stack
  58. // .match(/.js:(\d+):(\d+)/)
  59. // .slice(1)
  60. // .map(s => parseInt(s));
  61. //
  62. // expect(requests.length).toBe(1);
  63. // let [request] = requests;
  64. // expect(request.method).toBe('POST');
  65. // expect(request.url).toBe('https://notify.bugsnag.com');
  66. // expect(request.headers.get('Content-Type')).toBe('application/json');
  67. // let body = JSON.parse(request.body);
  68. // // Delete `inProject` field because tests may fail when run as part of Pulsar Core
  69. // // (i.e. when this test file will be located under `node_modules/exception-reporting/spec`)
  70. // delete body.events[0].exceptions[0].stacktrace[0].inProject;
  71. //
  72. // expect(body).toEqual({
  73. // apiKey: Reporter.API_KEY,
  74. // notifier: {
  75. // name: 'Atom',
  76. // version: Reporter.LIB_VERSION,
  77. // url: 'https://www.atom.io'
  78. // },
  79. // events: [
  80. // {
  81. // payloadVersion: '2',
  82. // exceptions: [
  83. // {
  84. // errorClass: 'Error',
  85. // message: '',
  86. // stacktrace: [
  87. // {
  88. // method: semver.gt(process.versions.electron, '1.6.0')
  89. // ? 'Spec.<anonymous>'
  90. // : '<anonymous>',
  91. // file: 'spec/reporter-spec.js',
  92. // lineNumber: lineNumber,
  93. // columnNumber: columnNumber
  94. // }
  95. // ]
  96. // }
  97. // ],
  98. // severity: 'error',
  99. // user: {},
  100. // app: {
  101. // version: atom.getVersion(),
  102. // releaseStage: getReleaseChannel(atom.getVersion())
  103. // },
  104. // device: {
  105. // osVersion: osVersion
  106. // }
  107. // }
  108. // ]
  109. // });
  110. // });
  111. //
  112. // it('posts errors originated outside Pulsar Core to BugSnag', () => {
  113. // process.env.HOME = path.join(__dirname, '..', '..');
  114. //
  115. // let error = new Error();
  116. // Error.captureStackTrace(error);
  117. // reporter.reportUncaughtException(error);
  118. // let [lineNumber, columnNumber] = error.stack
  119. // .match(/.js:(\d+):(\d+)/)
  120. // .slice(1)
  121. // .map(s => parseInt(s));
  122. //
  123. // expect(requests.length).toBe(1);
  124. // let [request] = requests;
  125. // expect(request.method).toBe('POST');
  126. // expect(request.url).toBe('https://notify.bugsnag.com');
  127. // expect(request.headers.get('Content-Type')).toBe('application/json');
  128. // let body = JSON.parse(request.body);
  129. // // Delete `inProject` field because tests may fail when run as part of Pulsar Core
  130. // // (i.e. when this test file will be located under `node_modules/exception-reporting/spec`)
  131. // delete body.events[0].exceptions[0].stacktrace[0].inProject;
  132. //
  133. // expect(body).toEqual({
  134. // apiKey: Reporter.API_KEY,
  135. // notifier: {
  136. // name: 'Atom',
  137. // version: Reporter.LIB_VERSION,
  138. // url: 'https://www.atom.io'
  139. // },
  140. // events: [
  141. // {
  142. // payloadVersion: '2',
  143. // exceptions: [
  144. // {
  145. // errorClass: 'Error',
  146. // message: '',
  147. // stacktrace: [
  148. // {
  149. // method: semver.gt(process.versions.electron, '1.6.0')
  150. // ? 'Spec.<anonymous>'
  151. // : '<anonymous>',
  152. // file: '~/exception-reporting/spec/reporter-spec.js',
  153. // lineNumber: lineNumber,
  154. // columnNumber: columnNumber
  155. // }
  156. // ]
  157. // }
  158. // ],
  159. // severity: 'error',
  160. // user: {},
  161. // app: {
  162. // version: atom.getVersion(),
  163. // releaseStage: getReleaseChannel(atom.getVersion())
  164. // },
  165. // device: {
  166. // osVersion: osVersion
  167. // }
  168. // }
  169. // ]
  170. // });
  171. // });
  172. //
  173. // describe('when the error object has `privateMetadata` and `privateMetadataDescription` fields', () => {
  174. // let [error, notification] = [];
  175. //
  176. // beforeEach(() => {
  177. // atom.notifications.clear();
  178. // spyOn(atom.notifications, 'addInfo').andCallThrough();
  179. //
  180. // error = new Error();
  181. // Error.captureStackTrace(error);
  182. //
  183. // error.metadata = { foo: 'bar' };
  184. // error.privateMetadata = { baz: 'quux' };
  185. // error.privateMetadataDescription = 'The contents of baz';
  186. // });
  187. //
  188. // it('posts a notification asking for consent', () => {
  189. // reporter.reportUncaughtException(error);
  190. // expect(atom.notifications.addInfo).toHaveBeenCalled();
  191. // });
  192. //
  193. // it('submits the error with the private metadata if the user consents', () => {
  194. // spyOn(reporter, 'reportUncaughtException').andCallThrough();
  195. // reporter.reportUncaughtException(error);
  196. // reporter.reportUncaughtException.reset();
  197. //
  198. // notification = atom.notifications.getNotifications()[0];
  199. //
  200. // let notificationOptions = atom.notifications.addInfo.argsForCall[0][1];
  201. // expect(notificationOptions.buttons[1].text).toMatch(/Yes/);
  202. //
  203. // notificationOptions.buttons[1].onDidClick();
  204. // expect(reporter.reportUncaughtException).toHaveBeenCalledWith(error);
  205. // expect(reporter.reportUncaughtException.callCount).toBe(1);
  206. // expect(error.privateMetadata).toBeUndefined();
  207. // expect(error.privateMetadataDescription).toBeUndefined();
  208. // expect(error.metadata).toEqual({ foo: 'bar', baz: 'quux' });
  209. //
  210. // expect(notification.isDismissed()).toBe(true);
  211. // });
  212. //
  213. // it('submits the error without the private metadata if the user does not consent', () => {
  214. // spyOn(reporter, 'reportUncaughtException').andCallThrough();
  215. // reporter.reportUncaughtException(error);
  216. // reporter.reportUncaughtException.reset();
  217. //
  218. // notification = atom.notifications.getNotifications()[0];
  219. //
  220. // let notificationOptions = atom.notifications.addInfo.argsForCall[0][1];
  221. // expect(notificationOptions.buttons[0].text).toMatch(/No/);
  222. //
  223. // notificationOptions.buttons[0].onDidClick();
  224. // expect(reporter.reportUncaughtException).toHaveBeenCalledWith(error);
  225. // expect(reporter.reportUncaughtException.callCount).toBe(1);
  226. // expect(error.privateMetadata).toBeUndefined();
  227. // expect(error.privateMetadataDescription).toBeUndefined();
  228. // expect(error.metadata).toEqual({ foo: 'bar' });
  229. //
  230. // expect(notification.isDismissed()).toBe(true);
  231. // });
  232. //
  233. // it('submits the error without the private metadata if the user dismisses the notification', () => {
  234. // spyOn(reporter, 'reportUncaughtException').andCallThrough();
  235. // reporter.reportUncaughtException(error);
  236. // reporter.reportUncaughtException.reset();
  237. //
  238. // notification = atom.notifications.getNotifications()[0];
  239. // notification.dismiss();
  240. //
  241. // expect(reporter.reportUncaughtException).toHaveBeenCalledWith(error);
  242. // expect(reporter.reportUncaughtException.callCount).toBe(1);
  243. // expect(error.privateMetadata).toBeUndefined();
  244. // expect(error.privateMetadataDescription).toBeUndefined();
  245. // expect(error.metadata).toEqual({ foo: 'bar' });
  246. // });
  247. // });
  248. //
  249. // it('treats packages located in atom.packages.getPackageDirPaths as user packages', () => {
  250. // mockActivePackages = [
  251. // {
  252. // name: 'user-1',
  253. // path: '/Users/user/.atom/packages/user-1',
  254. // metadata: { version: '1.0.0' }
  255. // },
  256. // {
  257. // name: 'user-2',
  258. // path: '/Users/user/.atom/packages/user-2',
  259. // metadata: { version: '1.2.0' }
  260. // },
  261. // {
  262. // name: 'bundled-1',
  263. // path:
  264. // '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-1',
  265. // metadata: { version: '1.0.0' }
  266. // },
  267. // {
  268. // name: 'bundled-2',
  269. // path:
  270. // '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-2',
  271. // metadata: { version: '1.2.0' }
  272. // }
  273. // ];
  274. //
  275. // const packageDirPaths = ['/Users/user/.atom/packages'];
  276. //
  277. // spyOn(atom.packages, 'getPackageDirPaths').andReturn(packageDirPaths);
  278. //
  279. // let error = new Error();
  280. // Error.captureStackTrace(error);
  281. // reporter.reportUncaughtException(error);
  282. //
  283. // expect(error.metadata.userPackages).toEqual({
  284. // 'user-1': '1.0.0',
  285. // 'user-2': '1.2.0'
  286. // });
  287. // expect(error.metadata.bundledPackages).toEqual({
  288. // 'bundled-1': '1.0.0',
  289. // 'bundled-2': '1.2.0'
  290. // });
  291. // });
  292. //
  293. // it('adds previous error messages and assertion failures to the reported metadata', () => {
  294. // reporter.reportPreviousErrors = true;
  295. //
  296. // reporter.reportUncaughtException(new Error('A'));
  297. // reporter.reportUncaughtException(new Error('B'));
  298. // reporter.reportFailedAssertion(new Error('X'));
  299. // reporter.reportFailedAssertion(new Error('Y'));
  300. //
  301. // reporter.reportUncaughtException(new Error('C'));
  302. //
  303. // expect(requests.length).toBe(5);
  304. //
  305. // const lastRequest = requests[requests.length - 1];
  306. // const body = JSON.parse(lastRequest.body);
  307. //
  308. // console.log(body);
  309. // expect(body.events[0].metaData.previousErrors).toEqual(['A', 'B']);
  310. // expect(body.events[0].metaData.previousAssertionFailures).toEqual([
  311. // 'X',
  312. // 'Y'
  313. // ]);
  314. // });
  315. // });
  316. //
  317. // describe('.reportFailedAssertion(error)', () => {
  318. // it('posts warnings to bugsnag', () => {
  319. // process.env.HOME = path.join(__dirname, '..', '..');
  320. //
  321. // let error = new Error();
  322. // Error.captureStackTrace(error);
  323. // reporter.reportFailedAssertion(error);
  324. // let [lineNumber, columnNumber] = error.stack
  325. // .match(/.js:(\d+):(\d+)/)
  326. // .slice(1)
  327. // .map(s => parseInt(s));
  328. //
  329. // expect(requests.length).toBe(1);
  330. // let [request] = requests;
  331. // expect(request.method).toBe('POST');
  332. // expect(request.url).toBe('https://notify.bugsnag.com');
  333. // expect(request.headers.get('Content-Type')).toBe('application/json');
  334. // let body = JSON.parse(request.body);
  335. // // Delete `inProject` field because tests may fail when run as part of Pulsar Core
  336. // // (i.e. when this test file will be located under `node_modules/exception-reporting/spec`)
  337. // delete body.events[0].exceptions[0].stacktrace[0].inProject;
  338. //
  339. // expect(body).toEqual({
  340. // apiKey: Reporter.API_KEY,
  341. // notifier: {
  342. // name: 'Atom',
  343. // version: Reporter.LIB_VERSION,
  344. // url: 'https://www.atom.io'
  345. // },
  346. // events: [
  347. // {
  348. // payloadVersion: '2',
  349. // exceptions: [
  350. // {
  351. // errorClass: 'Error',
  352. // message: '',
  353. // stacktrace: [
  354. // {
  355. // method: semver.gt(process.versions.electron, '1.6.0')
  356. // ? 'Spec.<anonymous>'
  357. // : '<anonymous>',
  358. // file: '~/exception-reporting/spec/reporter-spec.js',
  359. // lineNumber: lineNumber,
  360. // columnNumber: columnNumber
  361. // }
  362. // ]
  363. // }
  364. // ],
  365. // severity: 'warning',
  366. // user: {},
  367. // app: {
  368. // version: atom.getVersion(),
  369. // releaseStage: getReleaseChannel(atom.getVersion())
  370. // },
  371. // device: {
  372. // osVersion: osVersion
  373. // }
  374. // }
  375. // ]
  376. // });
  377. // });
  378. //
  379. // describe('when the error object has `privateMetadata` and `privateMetadataDescription` fields', () => {
  380. // let [error, notification] = [];
  381. //
  382. // beforeEach(() => {
  383. // atom.notifications.clear();
  384. // spyOn(atom.notifications, 'addInfo').andCallThrough();
  385. //
  386. // error = new Error();
  387. // Error.captureStackTrace(error);
  388. //
  389. // error.metadata = { foo: 'bar' };
  390. // error.privateMetadata = { baz: 'quux' };
  391. // error.privateMetadataDescription = 'The contents of baz';
  392. // });
  393. //
  394. // it('posts a notification asking for consent', () => {
  395. // reporter.reportFailedAssertion(error);
  396. // expect(atom.notifications.addInfo).toHaveBeenCalled();
  397. // });
  398. //
  399. // it('submits the error with the private metadata if the user consents', () => {
  400. // spyOn(reporter, 'reportFailedAssertion').andCallThrough();
  401. // reporter.reportFailedAssertion(error);
  402. // reporter.reportFailedAssertion.reset();
  403. //
  404. // notification = atom.notifications.getNotifications()[0];
  405. //
  406. // let notificationOptions = atom.notifications.addInfo.argsForCall[0][1];
  407. // expect(notificationOptions.buttons[1].text).toMatch(/Yes/);
  408. //
  409. // notificationOptions.buttons[1].onDidClick();
  410. // expect(reporter.reportFailedAssertion).toHaveBeenCalledWith(error);
  411. // expect(reporter.reportFailedAssertion.callCount).toBe(1);
  412. // expect(error.privateMetadata).toBeUndefined();
  413. // expect(error.privateMetadataDescription).toBeUndefined();
  414. // expect(error.metadata).toEqual({ foo: 'bar', baz: 'quux' });
  415. //
  416. // expect(notification.isDismissed()).toBe(true);
  417. // });
  418. //
  419. // it('submits the error without the private metadata if the user does not consent', () => {
  420. // spyOn(reporter, 'reportFailedAssertion').andCallThrough();
  421. // reporter.reportFailedAssertion(error);
  422. // reporter.reportFailedAssertion.reset();
  423. //
  424. // notification = atom.notifications.getNotifications()[0];
  425. //
  426. // let notificationOptions = atom.notifications.addInfo.argsForCall[0][1];
  427. // expect(notificationOptions.buttons[0].text).toMatch(/No/);
  428. //
  429. // notificationOptions.buttons[0].onDidClick();
  430. // expect(reporter.reportFailedAssertion).toHaveBeenCalledWith(error);
  431. // expect(reporter.reportFailedAssertion.callCount).toBe(1);
  432. // expect(error.privateMetadata).toBeUndefined();
  433. // expect(error.privateMetadataDescription).toBeUndefined();
  434. // expect(error.metadata).toEqual({ foo: 'bar' });
  435. //
  436. // expect(notification.isDismissed()).toBe(true);
  437. // });
  438. //
  439. // it('submits the error without the private metadata if the user dismisses the notification', () => {
  440. // spyOn(reporter, 'reportFailedAssertion').andCallThrough();
  441. // reporter.reportFailedAssertion(error);
  442. // reporter.reportFailedAssertion.reset();
  443. //
  444. // notification = atom.notifications.getNotifications()[0];
  445. // notification.dismiss();
  446. //
  447. // expect(reporter.reportFailedAssertion).toHaveBeenCalledWith(error);
  448. // expect(reporter.reportFailedAssertion.callCount).toBe(1);
  449. // expect(error.privateMetadata).toBeUndefined();
  450. // expect(error.privateMetadataDescription).toBeUndefined();
  451. // expect(error.metadata).toEqual({ foo: 'bar' });
  452. // });
  453. //
  454. // it("only notifies the user once for a given 'privateMetadataRequestName'", () => {
  455. // let fakeStorage = {};
  456. // spyOn(global.localStorage, 'setItem').andCallFake(
  457. // (key, value) => (fakeStorage[key] = value)
  458. // );
  459. // spyOn(global.localStorage, 'getItem').andCallFake(
  460. // key => fakeStorage[key]
  461. // );
  462. //
  463. // error.privateMetadataRequestName = 'foo';
  464. //
  465. // reporter.reportFailedAssertion(error);
  466. // expect(atom.notifications.addInfo).toHaveBeenCalled();
  467. // atom.notifications.addInfo.reset();
  468. //
  469. // reporter.reportFailedAssertion(error);
  470. // expect(atom.notifications.addInfo).not.toHaveBeenCalled();
  471. //
  472. // let error2 = new Error();
  473. // Error.captureStackTrace(error2);
  474. // error2.privateMetadataDescription = 'Something about you';
  475. // error2.privateMetadata = { baz: 'quux' };
  476. // error2.privateMetadataRequestName = 'bar';
  477. //
  478. // reporter.reportFailedAssertion(error2);
  479. // expect(atom.notifications.addInfo).toHaveBeenCalled();
  480. // });
  481. // });
  482. //
  483. // it('treats packages located in atom.packages.getPackageDirPaths as user packages', () => {
  484. // mockActivePackages = [
  485. // {
  486. // name: 'user-1',
  487. // path: '/Users/user/.atom/packages/user-1',
  488. // metadata: { version: '1.0.0' }
  489. // },
  490. // {
  491. // name: 'user-2',
  492. // path: '/Users/user/.atom/packages/user-2',
  493. // metadata: { version: '1.2.0' }
  494. // },
  495. // {
  496. // name: 'bundled-1',
  497. // path:
  498. // '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-1',
  499. // metadata: { version: '1.0.0' }
  500. // },
  501. // {
  502. // name: 'bundled-2',
  503. // path:
  504. // '/Applications/Atom.app/Contents/Resources/app.asar/node_modules/bundled-2',
  505. // metadata: { version: '1.2.0' }
  506. // }
  507. // ];
  508. //
  509. // const packageDirPaths = ['/Users/user/.atom/packages'];
  510. //
  511. // spyOn(atom.packages, 'getPackageDirPaths').andReturn(packageDirPaths);
  512. //
  513. // let error = new Error();
  514. // Error.captureStackTrace(error);
  515. // reporter.reportFailedAssertion(error);
  516. //
  517. // expect(error.metadata.userPackages).toEqual({
  518. // 'user-1': '1.0.0',
  519. // 'user-2': '1.2.0'
  520. // });
  521. // expect(error.metadata.bundledPackages).toEqual({
  522. // 'bundled-1': '1.0.0',
  523. // 'bundled-2': '1.2.0'
  524. // });
  525. // });
  526. //
  527. // it('adds previous error messages and assertion failures to the reported metadata', () => {
  528. // reporter.reportPreviousErrors = true;
  529. //
  530. // reporter.reportUncaughtException(new Error('A'));
  531. // reporter.reportUncaughtException(new Error('B'));
  532. // reporter.reportFailedAssertion(new Error('X'));
  533. // reporter.reportFailedAssertion(new Error('Y'));
  534. //
  535. // reporter.reportFailedAssertion(new Error('C'));
  536. //
  537. // expect(requests.length).toBe(5);
  538. //
  539. // const lastRequest = requests[requests.length - 1];
  540. // const body = JSON.parse(lastRequest.body);
  541. //
  542. // expect(body.events[0].metaData.previousErrors).toEqual(['A', 'B']);
  543. // expect(body.events[0].metaData.previousAssertionFailures).toEqual([
  544. // 'X',
  545. // 'Y'
  546. // ]);
  547. // });
  548. // });
  549. // });