Skip to content

Commit

Permalink
Merge pull request #341 from mikaelbr/timeoutNotifySend
Browse files Browse the repository at this point in the history
feat: implements proper timeout/wait behaviour for notify-send
  • Loading branch information
mikaelbr committed Aug 13, 2020
2 parents 1c74ea9 + e3decb2 commit ee7916a
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 37 deletions.
3 changes: 2 additions & 1 deletion .prettierrc
@@ -1,4 +1,5 @@
{
"printWidth": 80,
"singleQuote": true
"singleQuote": true,
"trailingComma": "none"
}
6 changes: 6 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog

### `v8.0.0`

Breaking changes:

- Expire time for notify-send is made to match macOS and Windows with default time of 10 seconds. The API is changed to take seconds as input and converting it to milliseconds before passing it on to notify-send. See [#341](https://github.com/mikaelbr/node-notifier/pull/341).

### `v7.0.2`

- Updates dependencies
Expand Down
16 changes: 9 additions & 7 deletions README.md
Expand Up @@ -70,16 +70,16 @@ notifier.notify(
sound: true, // Only Notification Center or Windows Toasters
wait: true // Wait with callback, until user action is taken against notification, does not apply to Windows Toasters as they always wait or notify-send as it does not support the wait option
},
function(err, response) {
function (err, response) {
// Response is response from notification
}
);

notifier.on('click', function(notifierObject, options, event) {
notifier.on('click', function (notifierObject, options, event) {
// Triggers if `wait: true` and user clicks notification
});

notifier.on('timeout', function(notifierObject, options) {
notifier.on('timeout', function (notifierObject, options) {
// Triggers if `wait: true` and notification closes
});
```
Expand Down Expand Up @@ -179,7 +179,7 @@ notifier.notify(
dropdownLabel: undefined, // String. Label to be used if multiple actions
reply: false // Boolean. If notification should take input. Value passed as third argument in callback and event emitter.
},
function(error, response, metadata) {
function (error, response, metadata) {
console.log(response, metadata);
}
);
Expand Down Expand Up @@ -278,7 +278,7 @@ notifier.notify(
remove: undefined, // Number. Refer to previously created notification to close.
install: undefined // String (path, application, app id). Creates a shortcut <path> in the start menu which point to the executable <application>, appID used for the notifications.
},
function(error, response) {
function (error, response) {
console.log(response);
}
);
Expand Down Expand Up @@ -333,7 +333,7 @@ notifier.notify(
wait: false, // Wait for User Action against Notification
type: 'info' // The notification type : info | warn | error
},
function(error, response) {
function (error, response) {
console.log(response);
}
);
Expand All @@ -355,10 +355,12 @@ notifier.notify({
message: 'Hello World',
icon: __dirname + '/coulson.jpg',

wait: false, // Defaults no exipre time set. If true expire time of 5 seconds is used
timeout: 10, // Alias for expire-time, time etc. Time before notify-send expires. Defaults to 10 seconds.

// .. and other notify-send flags:
'app-name': 'node-notifier',
urgency: undefined,
time: undefined,
category: undefined,
hint: undefined
});
Expand Down
11 changes: 11 additions & 0 deletions lib/utils.js
Expand Up @@ -162,13 +162,24 @@ module.exports.mapToNotifySend = function (options) {
options = mapAppIcon(options);
options = mapText(options);

if (options.timeout === false) {
delete options.timeout;
}
if (options.wait === true) {
options['expire-time'] = 5; // 5 seconds default time (multipled below)
}
for (var key in options) {
if (key === 'message' || key === 'title') continue;
if (options.hasOwnProperty(key) && notifySendFlags[key] !== key) {
options[notifySendFlags[key]] = options[key];
delete options[key];
}
}
if (typeof options['expire-time'] === 'undefined') {
options['expire-time'] = 10 * 1000; // 10 sec timeout by default
} else if (typeof options['expire-time'] === 'number') {
options['expire-time'] = options['expire-time'] * 1000; // notify send uses milliseconds
}

return options;
};
Expand Down
52 changes: 33 additions & 19 deletions test/notify-send.js
Expand Up @@ -2,83 +2,97 @@ var Notify = require('../notifiers/notifysend');
var utils = require('../lib/utils');
var os = require('os');

describe('notify-send', function() {
describe('notify-send', function () {
var original = utils.command;
var originalType = os.type;

beforeEach(function() {
os.type = function() {
beforeEach(function () {
os.type = function () {
return 'Linux';
};
});

afterEach(function() {
afterEach(function () {
utils.command = original;
os.type = originalType;
});

function expectArgsListToBe(expected, done) {
utils.command = function(notifier, argsList, callback) {
utils.command = function (notifier, argsList, callback) {
expect(argsList).toEqual(expected);
done();
};
}

it('should pass on title and body', function(done) {
var expected = ['"title"', '"body"'];
it('should pass on title and body', function (done) {
var expected = ['"title"', '"body"', '--expire-time', '"10000"'];
expectArgsListToBe(expected, done);
var notifier = new Notify({ suppressOsdCheck: true });
notifier.notify({ title: 'title', message: 'body' });
});

it('should pass have default title', function(done) {
var expected = ['"Node Notification:"', '"body"'];
it('should pass have default title', function (done) {
var expected = [
'"Node Notification:"',
'"body"',
'--expire-time',
'"10000"'
];

expectArgsListToBe(expected, done);
var notifier = new Notify({ suppressOsdCheck: true });
notifier.notify({ message: 'body' });
});

it('should throw error if no message is passed', function(done) {
utils.command = function(notifier, argsList, callback) {
it('should throw error if no message is passed', function (done) {
utils.command = function (notifier, argsList, callback) {
expect(argsList).toBeUndefined();
};

var notifier = new Notify({ suppressOsdCheck: true });
notifier.notify({}, function(err) {
notifier.notify({}, function (err) {
expect(err.message).toBe('Message is required.');
done();
});
});

it('should escape message input', function(done) {
it('should escape message input', function (done) {
var excapedNewline = process.platform === 'win32' ? '\\r\\n' : '\\n';
var expected = [
'"Node Notification:"',
'"some' + excapedNewline + ' \\"me\'ss\\`age\\`\\""'
'"some' + excapedNewline + ' \\"me\'ss\\`age\\`\\""',
'--expire-time',
'"10000"'
];

expectArgsListToBe(expected, done);
var notifier = new Notify({ suppressOsdCheck: true });
notifier.notify({ message: 'some\n "me\'ss`age`"' });
});

it('should send additional parameters as --"keyname"', function(done) {
var expected = ['"title"', '"body"', '--icon', '"icon-string"'];
it('should send additional parameters as --"keyname"', function (done) {
var expected = [
'"title"',
'"body"',
'--icon',
'"icon-string"',
'--expire-time',
'"10000"'
];

expectArgsListToBe(expected, done);
var notifier = new Notify({ suppressOsdCheck: true });
notifier.notify({ title: 'title', message: 'body', icon: 'icon-string' });
});

it('should remove extra options that are not supported by notify-send', function(done) {
it('should remove extra options that are not supported by notify-send', function (done) {
var expected = [
'"title"',
'"body"',
'--icon',
'"icon-string"',
'--expire-time',
'"100"'
'"1000"'
];

expectArgsListToBe(expected, done);
Expand All @@ -87,7 +101,7 @@ describe('notify-send', function() {
title: 'title',
message: 'body',
icon: 'icon-string',
time: 100,
time: 1,
tullball: 'notValid'
});
});
Expand Down
25 changes: 15 additions & 10 deletions test/utils.js
Expand Up @@ -2,9 +2,9 @@ var path = require('path');
var fs = require('fs');
var _ = require('../lib/utils');

describe('utils', function() {
describe('clone', function() {
it('should clone nested objects', function() {
describe('utils', function () {
describe('clone', function () {
it('should clone nested objects', function () {
var obj = { a: { b: 42 }, c: 123 };
var obj2 = _.clone(obj);

Expand All @@ -15,9 +15,14 @@ describe('utils', function() {
});
});

describe('mapping', function() {
it('should map icon for notify-send', function() {
var expected = { title: 'Foo', message: 'Bar', icon: 'foobar' };
describe('mapping', function () {
it('should map icon for notify-send', function () {
var expected = {
title: 'Foo',
message: 'Bar',
icon: 'foobar',
'expire-time': 10000
};

expect(
_.mapToNotifySend({ title: 'Foo', message: 'Bar', appIcon: 'foobar' })
Expand All @@ -28,7 +33,7 @@ describe('utils', function() {
).toEqual(expected);
});

it('should map short hand for notify-sned', function() {
it('should map short hand for notify-sned', function () {
var expected = {
urgency: 'a',
'expire-time': 'b',
Expand All @@ -42,7 +47,7 @@ describe('utils', function() {
).toEqual(expected);
});

it('should map icon for notification center', function() {
it('should map icon for notification center', function () {
var expected = {
title: 'Foo',
message: 'Bar',
Expand All @@ -60,7 +65,7 @@ describe('utils', function() {
);
});

it('should map icon for growl', function() {
it('should map icon for growl', function () {
var icon = path.join(__dirname, 'fixture', 'coulson.jpg');
var iconRead = fs.readFileSync(icon);

Expand All @@ -78,7 +83,7 @@ describe('utils', function() {
expect(Buffer.isBuffer(obj.icon)).toBeTruthy();
});

it('should not map icon url for growl', function() {
it('should not map icon url for growl', function () {
var icon = 'http://hostname.com/logo.png';

var expected = { title: 'Foo', message: 'Bar', icon: icon };
Expand Down

0 comments on commit ee7916a

Please sign in to comment.