Spaces:
Paused
Paused
| ; | |
| /** | |
| * Web Notifications module. | |
| * @module Growl | |
| */ | |
| /** | |
| * Save timer references to avoid Sinon interfering (see GH-237). | |
| */ | |
| var Date = global.Date; | |
| var setTimeout = global.setTimeout; | |
| var EVENT_RUN_END = require('../runner').constants.EVENT_RUN_END; | |
| var isBrowser = require('../utils').isBrowser; | |
| /** | |
| * Checks if browser notification support exists. | |
| * | |
| * @public | |
| * @see {@link https://caniuse.com/#feat=notifications|Browser support (notifications)} | |
| * @see {@link https://caniuse.com/#feat=promises|Browser support (promises)} | |
| * @see {@link Mocha#growl} | |
| * @see {@link Mocha#isGrowlCapable} | |
| * @return {boolean} whether browser notification support exists | |
| */ | |
| exports.isCapable = function() { | |
| var hasNotificationSupport = 'Notification' in window; | |
| var hasPromiseSupport = typeof Promise === 'function'; | |
| return isBrowser() && hasNotificationSupport && hasPromiseSupport; | |
| }; | |
| /** | |
| * Implements browser notifications as a pseudo-reporter. | |
| * | |
| * @public | |
| * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/notification|Notification API} | |
| * @see {@link https://developers.google.com/web/fundamentals/push-notifications/display-a-notification|Displaying a Notification} | |
| * @see {@link Growl#isPermitted} | |
| * @see {@link Mocha#_growl} | |
| * @param {Runner} runner - Runner instance. | |
| */ | |
| exports.notify = function(runner) { | |
| var promise = isPermitted(); | |
| /** | |
| * Attempt notification. | |
| */ | |
| var sendNotification = function() { | |
| // If user hasn't responded yet... "No notification for you!" (Seinfeld) | |
| Promise.race([promise, Promise.resolve(undefined)]) | |
| .then(canNotify) | |
| .then(function() { | |
| display(runner); | |
| }) | |
| .catch(notPermitted); | |
| }; | |
| runner.once(EVENT_RUN_END, sendNotification); | |
| }; | |
| /** | |
| * Checks if browser notification is permitted by user. | |
| * | |
| * @private | |
| * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Notification/permission|Notification.permission} | |
| * @see {@link Mocha#growl} | |
| * @see {@link Mocha#isGrowlPermitted} | |
| * @returns {Promise<boolean>} promise determining if browser notification | |
| * permissible when fulfilled. | |
| */ | |
| function isPermitted() { | |
| var permitted = { | |
| granted: function allow() { | |
| return Promise.resolve(true); | |
| }, | |
| denied: function deny() { | |
| return Promise.resolve(false); | |
| }, | |
| default: function ask() { | |
| return Notification.requestPermission().then(function(permission) { | |
| return permission === 'granted'; | |
| }); | |
| } | |
| }; | |
| return permitted[Notification.permission](); | |
| } | |
| /** | |
| * @summary | |
| * Determines if notification should proceed. | |
| * | |
| * @description | |
| * Notification shall <strong>not</strong> proceed unless `value` is true. | |
| * | |
| * `value` will equal one of: | |
| * <ul> | |
| * <li><code>true</code> (from `isPermitted`)</li> | |
| * <li><code>false</code> (from `isPermitted`)</li> | |
| * <li><code>undefined</code> (from `Promise.race`)</li> | |
| * </ul> | |
| * | |
| * @private | |
| * @param {boolean|undefined} value - Determines if notification permissible. | |
| * @returns {Promise<undefined>} Notification can proceed | |
| */ | |
| function canNotify(value) { | |
| if (!value) { | |
| var why = value === false ? 'blocked' : 'unacknowledged'; | |
| var reason = 'not permitted by user (' + why + ')'; | |
| return Promise.reject(new Error(reason)); | |
| } | |
| return Promise.resolve(); | |
| } | |
| /** | |
| * Displays the notification. | |
| * | |
| * @private | |
| * @param {Runner} runner - Runner instance. | |
| */ | |
| function display(runner) { | |
| var stats = runner.stats; | |
| var symbol = { | |
| cross: '\u274C', | |
| tick: '\u2705' | |
| }; | |
| var logo = require('../../package.json').notifyLogo; | |
| var _message; | |
| var message; | |
| var 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 | |
| var options = { | |
| badge: logo, | |
| body: message, | |
| dir: 'ltr', | |
| icon: logo, | |
| lang: 'en-US', | |
| name: 'mocha', | |
| requireInteraction: false, | |
| timestamp: Date.now() | |
| }; | |
| var notification = new Notification(title, options); | |
| // Autoclose after brief delay (makes various browsers act same) | |
| var FORCE_DURATION = 4000; | |
| setTimeout(notification.close.bind(notification), FORCE_DURATION); | |
| } | |
| /** | |
| * As notifications are tangential to our purpose, just log the error. | |
| * | |
| * @private | |
| * @param {Error} err - Why notification didn't happen. | |
| */ | |
| function notPermitted(err) { | |
| console.error('notification error:', err.message); | |
| } | |