| 'use strict'; |
| |
| /** |
| * Desktop Notifications module. |
| * @module Growl |
| */ |
| |
| const os = require('os'); |
| const path = require('path'); |
| const {sync: which} = require('which'); |
| const {EVENT_RUN_END} = require('./runner').constants; |
| |
| /** |
| * @summary |
| * Checks if Growl notification support seems likely. |
| * |
| * @description |
| * Glosses over the distinction between an unsupported platform |
| * and one that lacks prerequisite software installations. |
| * |
| * @public |
| * @see {@link https://github.com/tj/node-growl/blob/master/README.md|Prerequisite Installs} |
| * @see {@link Mocha#growl} |
| * @see {@link Mocha#isGrowlCapable} |
| * @return {boolean} whether Growl notification support can be expected |
| */ |
| exports.isCapable = () => { |
| if (!process.browser) { |
| return getSupportBinaries().reduce( |
| (acc, binary) => acc || Boolean(which(binary, {nothrow: true})), |
| false |
| ); |
| } |
| return false; |
| }; |
| |
| /** |
| * Implements desktop notifications as a pseudo-reporter. |
| * |
| * @public |
| * @see {@link Mocha#_growl} |
| * @param {Runner} runner - Runner instance. |
| */ |
| exports.notify = runner => { |
| runner.once(EVENT_RUN_END, () => { |
| display(runner); |
| }); |
| }; |
| |
| /** |
| * Displays the notification. |
| * |
| * @private |
| * @param {Runner} runner - Runner instance. |
| */ |
| const display = runner => { |
| const growl = require('growl'); |
| const stats = runner.stats; |
| const symbol = { |
| cross: '\u274C', |
| tick: '\u2705' |
| }; |
| let _message; |
| let message; |
| let title; |
| |
| if (stats.failures) { |
| _message = `${stats.failures} of ${stats.tests} tests failed`; |
| message = `${symbol.cross} ${_message}`; |
| title = 'Failed'; |
| } else { |
| _message = `${stats.passes} tests passed in ${stats.duration}ms`; |
| message = `${symbol.tick} ${_message}`; |
| title = 'Passed'; |
| } |
| |
| // Send notification |
| const options = { |
| image: logo(), |
| name: 'mocha', |
| title |
| }; |
| growl(message, options, onCompletion); |
| }; |
| |
| /** |
| * @summary |
| * Callback for result of attempted Growl notification. |
| * |
| * @description |
| * Despite its appearance, this is <strong>not</strong> an Error-first |
| * callback -- all parameters are populated regardless of success. |
| * |
| * @private |
| * @callback Growl~growlCB |
| * @param {*} err - Error object, or <code>null</code> if successful. |
| */ |
| function onCompletion(err) { |
| if (err) { |
| // As notifications are tangential to our purpose, just log the error. |
| const message = |
| err.code === 'ENOENT' ? 'prerequisite software not found' : err.message; |
| console.error('notification error:', message); |
| } |
| } |
| |
| /** |
| * Returns Mocha logo image path. |
| * |
| * @private |
| * @return {string} Pathname of Mocha logo |
| */ |
| const logo = () => { |
| return path.join(__dirname, '..', 'assets', 'mocha-logo-96.png'); |
| }; |
| |
| /** |
| * @summary |
| * Gets platform-specific Growl support binaries. |
| * |
| * @description |
| * Somewhat brittle dependency on `growl` package implementation, but it |
| * rarely changes. |
| * |
| * @private |
| * @see {@link https://github.com/tj/node-growl/blob/master/lib/growl.js#L28-L126|setupCmd} |
| * @return {string[]} names of Growl support binaries |
| */ |
| const getSupportBinaries = () => { |
| const binaries = { |
| Darwin: ['terminal-notifier', 'growlnotify'], |
| Linux: ['notify-send', 'growl'], |
| Windows_NT: ['growlnotify.exe'] |
| }; |
| return binaries[os.type()] || []; |
| }; |