growl.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. 'use strict';
  2. /**
  3. * Desktop Notifications module.
  4. * @module Growl
  5. */
  6. const os = require('os');
  7. const path = require('path');
  8. const {sync: which} = require('which');
  9. const {EVENT_RUN_END} = require('./runner').constants;
  10. /**
  11. * @summary
  12. * Checks if Growl notification support seems likely.
  13. *
  14. * @description
  15. * Glosses over the distinction between an unsupported platform
  16. * and one that lacks prerequisite software installations.
  17. *
  18. * @public
  19. * @see {@link https://github.com/tj/node-growl/blob/master/README.md|Prerequisite Installs}
  20. * @see {@link Mocha#growl}
  21. * @see {@link Mocha#isGrowlCapable}
  22. * @return {boolean} whether Growl notification support can be expected
  23. */
  24. exports.isCapable = () => {
  25. if (!process.browser) {
  26. return getSupportBinaries().reduce(
  27. (acc, binary) => acc || Boolean(which(binary, {nothrow: true})),
  28. false
  29. );
  30. }
  31. return false;
  32. };
  33. /**
  34. * Implements desktop notifications as a pseudo-reporter.
  35. *
  36. * @public
  37. * @see {@link Mocha#_growl}
  38. * @param {Runner} runner - Runner instance.
  39. */
  40. exports.notify = runner => {
  41. runner.once(EVENT_RUN_END, () => {
  42. display(runner);
  43. });
  44. };
  45. /**
  46. * Displays the notification.
  47. *
  48. * @private
  49. * @param {Runner} runner - Runner instance.
  50. */
  51. const display = runner => {
  52. const growl = require('growl');
  53. const stats = runner.stats;
  54. const symbol = {
  55. cross: '\u274C',
  56. tick: '\u2705'
  57. };
  58. let _message;
  59. let message;
  60. let title;
  61. if (stats.failures) {
  62. _message = `${stats.failures} of ${stats.tests} tests failed`;
  63. message = `${symbol.cross} ${_message}`;
  64. title = 'Failed';
  65. } else {
  66. _message = `${stats.passes} tests passed in ${stats.duration}ms`;
  67. message = `${symbol.tick} ${_message}`;
  68. title = 'Passed';
  69. }
  70. // Send notification
  71. const options = {
  72. image: logo(),
  73. name: 'mocha',
  74. title
  75. };
  76. growl(message, options, onCompletion);
  77. };
  78. /**
  79. * @summary
  80. * Callback for result of attempted Growl notification.
  81. *
  82. * @description
  83. * Despite its appearance, this is <strong>not</strong> an Error-first
  84. * callback -- all parameters are populated regardless of success.
  85. *
  86. * @private
  87. * @callback Growl~growlCB
  88. * @param {*} err - Error object, or <code>null</code> if successful.
  89. */
  90. function onCompletion(err) {
  91. if (err) {
  92. // As notifications are tangential to our purpose, just log the error.
  93. const message =
  94. err.code === 'ENOENT' ? 'prerequisite software not found' : err.message;
  95. console.error('notification error:', message);
  96. }
  97. }
  98. /**
  99. * Returns Mocha logo image path.
  100. *
  101. * @private
  102. * @return {string} Pathname of Mocha logo
  103. */
  104. const logo = () => {
  105. return path.join(__dirname, '..', 'assets', 'mocha-logo-96.png');
  106. };
  107. /**
  108. * @summary
  109. * Gets platform-specific Growl support binaries.
  110. *
  111. * @description
  112. * Somewhat brittle dependency on `growl` package implementation, but it
  113. * rarely changes.
  114. *
  115. * @private
  116. * @see {@link https://github.com/tj/node-growl/blob/master/lib/growl.js#L28-L126|setupCmd}
  117. * @return {string[]} names of Growl support binaries
  118. */
  119. const getSupportBinaries = () => {
  120. const binaries = {
  121. Darwin: ['terminal-notifier', 'growlnotify'],
  122. Linux: ['notify-send', 'growl'],
  123. Windows_NT: ['growlnotify.exe']
  124. };
  125. return binaries[os.type()] || [];
  126. };