diff --git a/.eslintrc.yml b/.eslintrc.yml
index 2d4721b8ed..77037f48b3 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -24,6 +24,7 @@ overrides:
- bin/*
- lib/cli/**/*.js
- test/node-unit/**/*.js
+ - lib/growl.js
parserOptions:
ecmaVersion: 6
env:
diff --git a/lib/growl.js b/lib/growl.js
index ee3d23232a..eae2281823 100644
--- a/lib/growl.js
+++ b/lib/growl.js
@@ -5,9 +5,9 @@
* @module Growl
*/
-var fs = require('fs');
-var os = require('os');
-var path = require('path');
+const os = require('os');
+const path = require('path');
+const {sync: which} = require('which');
/**
* @summary
@@ -23,8 +23,14 @@ var path = require('path');
* @see {@link Mocha#isGrowlCapable}
* @return {boolean} whether Growl notification support can be expected
*/
-exports.isCapable = function() {
- return !process.browser && which(getSupportBinaries()) !== '';
+exports.isCapable = () => {
+ if (!process.browser) {
+ return getSupportBinaries().reduce(
+ (acc, binary) => acc || Boolean(which(binary, {nothrow: true})),
+ false
+ );
+ }
+ return false;
};
/**
@@ -34,11 +40,10 @@ exports.isCapable = function() {
* @see {@link Mocha#_growl}
* @param {Runner} runner - Runner instance.
*/
-exports.notify = function(runner) {
- var sendNotification = function() {
+exports.notify = runner => {
+ runner.once('end', () => {
display(runner);
- };
- runner.once('end', sendNotification);
+ });
};
/**
@@ -47,35 +52,35 @@ exports.notify = function(runner) {
* @private
* @param {Runner} runner - Runner instance.
*/
-function display(runner) {
- var growl = require('growl');
- var stats = runner.stats;
- var symbol = {
+const display = runner => {
+ const growl = require('growl');
+ const stats = runner.stats;
+ const symbol = {
cross: '\u274C',
tick: '\u2705'
};
- var _message;
- var message;
- var title;
+ let _message;
+ let message;
+ let title;
if (stats.failures) {
- _message = stats.failures + ' of ' + runner.total + ' tests failed';
- message = symbol.cross + ' ' + _message;
+ _message = `${stats.failures} of ${runner.total} tests failed`;
+ message = `${symbol.cross} ${_message}`;
title = 'Failed';
} else {
- _message = stats.passes + ' tests passed in ' + stats.duration + 'ms';
- message = symbol.tick + ' ' + _message;
+ _message = `${stats.passes} tests passed in ${stats.duration}ms`;
+ message = `${symbol.tick} ${_message}`;
title = 'Passed';
}
// Send notification
- var options = {
+ const options = {
image: logo(),
name: 'mocha',
- title: title
+ title
};
growl(message, options, onCompletion);
-}
+};
/**
* @summary
@@ -88,15 +93,11 @@ function display(runner) {
* @private
* @callback Growl~growlCB
* @param {*} err - Error object, or null
if successful.
- * @param {string} stdout - stdout
from notification delivery
- * process.
- * @param {string} stderr - stderr
from notification delivery
- * process. It will include timestamp and executed command with arguments.
*/
-function onCompletion(err, stdout, stderr) {
+function onCompletion(err) {
if (err) {
// As notifications are tangential to our purpose, just log the error.
- var message =
+ const message =
err.code === 'ENOENT' ? 'prerequisite software not found' : err.message;
console.error('notification error:', message);
}
@@ -108,36 +109,9 @@ function onCompletion(err, stdout, stderr) {
* @private
* @return {string} Pathname of Mocha logo
*/
-function logo() {
+const logo = () => {
return path.join(__dirname, '..', 'assets', 'mocha-logo-96.png');
-}
-
-/**
- * @summary
- * Locates a binary in the user's `PATH` environment variable.
- *
- * @description
- * Takes a list of command names and searches the path for each executable
- * file that would be run had these commands actually been invoked.
- *
- * @private
- * @param {string[]} binaries - Names of binary files to search for.
- * @return {string} absolute path of first binary found, or empty string if none
- */
-function which(binaries) {
- var paths = process.env.PATH.split(path.delimiter);
-
- for (var n = 0, blen = binaries.length; n < blen; n++) {
- var binary = binaries[n];
- for (var i = 0, plen = paths.length; i < plen; i++) {
- var loc = path.join(paths[i], binary);
- if (fs.existsSync(loc)) {
- return loc;
- }
- }
- }
- return '';
-}
+};
/**
* @summary
@@ -151,11 +125,11 @@ function which(binaries) {
* @see {@link https://github.com/tj/node-growl/blob/master/lib/growl.js#L28-L126|setupCmd}
* @return {string[]} names of Growl support binaries
*/
-function getSupportBinaries() {
- var binaries = {
+const getSupportBinaries = () => {
+ const binaries = {
Darwin: ['terminal-notifier', 'growlnotify'],
Linux: ['notify-send', 'growl'],
Windows_NT: ['growlnotify.exe']
};
return binaries[os.type()] || [];
-}
+};
diff --git a/package-lock.json b/package-lock.json
index 3de8118bc2..ff5e41de3c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13263,15 +13263,6 @@
"semver": "^5.1.0"
}
},
- "package-json-versionify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/package-json-versionify/-/package-json-versionify-1.0.4.tgz",
- "integrity": "sha1-WGBYepRIc6a35tJujlH/siMVvxc=",
- "dev": true,
- "requires": {
- "browserify-package-json": "^1.0.0"
- }
- },
"pako": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
@@ -17850,9 +17841,9 @@
}
},
"which": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
- "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"requires": {
"isexe": "^2.0.0"
}
diff --git a/package.json b/package.json
index 96a2e48636..d7ca05579e 100644
--- a/package.json
+++ b/package.json
@@ -488,6 +488,7 @@
"object.assign": "4.1.0",
"strip-json-comments": "2.0.1",
"supports-color": "^6.0.0",
+ "which": "1.3.1",
"wide-align": "1.1.3",
"yargs": "12.0.5",
"yargs-parser": "11.1.1",