123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- 'use strict';
- /**
- * 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;
- /**
- * 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 process.browser && 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').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);
- }
|