Skip to content

Commit 21c9e22

Browse files
committed
Added test suite and made Push test compatible
1 parent 965630f commit 21c9e22

5 files changed

Lines changed: 261 additions & 27 deletions

File tree

gulpfile.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
var gulp = require('gulp'),
22
rename = require('gulp-rename'),
33
uglify = require('gulp-uglify'),
4-
concat = require('gulp-concat');
4+
concat = require('gulp-concat'),
5+
path = require('path'),
6+
Server = require('karma').Server;
57

68
gulp.task('build', function () {
7-
gulp.src(['./src/*.js'])
8-
.pipe(concat('push.min.js'))
9+
gulp.src(['./*.js', '!./gulpfile.js'])
910
.pipe(uglify())
11+
.pipe(rename('push.min.js'))
1012
.pipe(gulp.dest('bin'));
1113

12-
gulp.src(['./src/*.js'])
13-
.pipe(concat('push.js'))
14+
gulp.src(['./*.js', '!./gulpfile.js'])
1415
.pipe(gulp.dest('bin'));
1516
});
1617

18+
gulp.task('test', function (cb) {
19+
new Server({
20+
configFile: path.resolve('karma.conf.js')
21+
}, cb).start();
22+
});
23+
1724
gulp.task('default', ['build']);

karma.conf.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Karma configuration
2+
// Generated on Tue Jul 21 2015 22:34:30 GMT-0400 (EDT)
3+
4+
module.exports = function(config) {
5+
config.set({
6+
7+
// base path that will be used to resolve all patterns (eg. files, exclude)
8+
basePath: '',
9+
10+
11+
// frameworks to use
12+
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
13+
frameworks: ['jasmine'],
14+
15+
plugins: [
16+
'karma-jasmine',
17+
'karma-firefox-launcher',
18+
'karma-mocha-reporter',
19+
'karma-coverage'
20+
],
21+
22+
// list of files / patterns to load in the browser
23+
files: [
24+
'push.js',
25+
'test/*.js'
26+
],
27+
28+
29+
// list of files to exclude
30+
exclude: [
31+
'gulpfile.js'
32+
],
33+
34+
35+
// preprocess matching files before serving them to the browser
36+
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
37+
preprocessors: {
38+
'push.js': ['coverage']
39+
},
40+
41+
42+
// test results reporter to use
43+
// possible values: 'dots', 'progress'
44+
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
45+
reporters: ['progress', 'mocha', 'coverage'],
46+
47+
48+
// web server port
49+
port: 9876,
50+
51+
52+
// enable / disable colors in the output (reporters and logs)
53+
colors: true,
54+
55+
56+
// level of logging
57+
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
58+
logLevel: config.LOG_INFO,
59+
60+
61+
// enable / disable watching file and executing tests whenever any file changes
62+
autoWatch: false,
63+
64+
65+
// start these browsers
66+
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
67+
browsers: ['Firefox'],
68+
69+
70+
// Continuous Integration mode
71+
// if true, Karma captures browsers, runs the tests and exits
72+
singleRun: true
73+
});
74+
};

package.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,16 @@
1818
"homepage": "https://github.com/Nickersoft/push.js",
1919
"devDependencies": {
2020
"gulp": "^3.9.0",
21-
"gulp-coffee": "^2.3.1",
2221
"gulp-concat": "^2.6.0",
22+
"gulp-karma": "0.0.4",
2323
"gulp-rename": "^1.2.2",
24-
"gulp-uglify": "^1.2.0"
24+
"gulp-uglify": "^1.2.0",
25+
"jasmine-core": "^2.3.4",
26+
"karma": "^0.13.2",
27+
"karma-coverage": "^0.4.2",
28+
"karma-firefox-launcher": "^0.1.6",
29+
"karma-jasmine": "^0.3.6",
30+
"karma-mocha-reporter": "^1.0.2",
31+
"phantomjs": "^1.9.17"
2532
}
2633
}

push.js

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
/**
22
* push.js
3-
* --------
3+
* =======
44
* A compact, cross-browser solution for Javascript desktop notifications
55
*
6+
* Credits
7+
* -------
8+
* Tsvetan Tsvetkov (ttsvetko)
9+
* Alex Gibson (alexgibson)
10+
*
11+
* License
12+
* -------
13+
*
614
* The MIT License (MIT)
715
*
816
* Copyright (c) 2015 Tyler Nickerson
@@ -25,8 +33,6 @@
2533
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2634
* THE SOFTWARE.
2735
*
28-
* Inspired by the work of
29-
* Tsvetan Tsvetkov (ttsvetko) and Alex Gibson (alexgibson)
3036
*/
3137

3238
// Window root
@@ -61,12 +67,18 @@ var root = (window !== 'undefined' ? window : self);
6167
isString = function (obj) { return obj && obj.constructor === String; },
6268
isFunction = function (obj) { return obj && obj.constructor === Function; },
6369

70+
/* Whether Push has permission to notify */
71+
hasPermission = false,
72+
6473
/**
6574
* Callback function for the 'create' method
6675
* @return {void}
6776
*/
6877
create_callback = function (title, options) {
6978

79+
/* Set empty settings if none are specified */
80+
options = options || {};
81+
7082
/* Safari 6+, Chrome 23+ */
7183
if (w.Notification) {
7284

@@ -135,18 +147,10 @@ var root = (window !== 'undefined' ? window : self);
135147
};
136148

137149
/* Autoclose timeout */
138-
if (notification &&
139-
notification.addEventListener &&
140-
options.timeout) {
141-
142-
notification.addEventListener('show', function () {
143-
144-
setTimeout(function () {
145-
wrapper.close();
146-
}, options.timeout);
147-
148-
});
149-
150+
if (options.timeout) {
151+
setTimeout(function () {
152+
wrapper.close();
153+
}, options.timeout);
150154
}
151155

152156
/* Notification callbacks */
@@ -189,13 +193,29 @@ var root = (window !== 'undefined' ? window : self);
189193
* @param {Function} callback - Function to execute once permission is granted
190194
* @return {void}
191195
*/
192-
self.Permission.request = function (callback) {
196+
self.Permission.request = function (onGranted, onDenied) {
193197

194198
/* Return if Push not supported */
195199
if (!self.isSupported) { return; }
196200

197-
/* Set an empty callback if an invalid one is specified */
198-
callback = isFunction(callback) ? callback : function () {};
201+
/* Default callback */
202+
callback = function (result) {
203+
204+
switch (result) {
205+
206+
case self.Permission.GRANTED:
207+
hasPermission = true;
208+
if (onGranted) onGranted();
209+
break;
210+
211+
case self.Permission.DENIED:
212+
hasPermission = false;
213+
if (onDenied) onDenied();
214+
break;
215+
216+
}
217+
218+
};
199219

200220
/* Legacy webkit browsers */
201221
if (w.webkitNotifications && w.webkitNotifications.checkPermission) {
@@ -208,6 +228,14 @@ var root = (window !== 'undefined' ? window : self);
208228

209229
};
210230

231+
/**
232+
* Returns whether Push has been granted permission to run
233+
* @return {Boolean}
234+
*/
235+
self.Permission.has = function () {
236+
return hasPermission;
237+
};
238+
211239
/**
212240
* Gets the permission level
213241
* @return {Permission} The permission level
@@ -290,15 +318,24 @@ var root = (window !== 'undefined' ? window : self);
290318

291319
/* Fail if the browser is not supported */
292320
if (!self.isSupported) {
293-
console.error('push.js is incompatible with self browser.');
321+
console.error('PushError: push.js is incompatible with self browser.');
294322
return;
295323
}
296324

325+
/* Fail if no or an invalid title is provided */
326+
if (typeof title !== 'string') {
327+
throw 'PushError: Title of notification must be a string';
328+
}
329+
330+
console.log(self.Permission.has());
331+
297332
/* Request permission if it isn't granted */
298-
if (self.Permission.get() !== self.Permission.GRANTED) {
333+
if (!self.Permission.has()) {
299334
self.Permission.request(function () {
300335
create_callback(title, options);
301336
});
337+
} else {
338+
create_callback(title, options);
302339
}
303340

304341
};

test/push_spec.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
describe('initialization', function () {
2+
3+
it('should create a new instance', function () {
4+
expect(window.Push !== undefined).toBeTruthy();
5+
});
6+
7+
it('isSupported should return a boolean', function () {
8+
expect(typeof Push.isSupported).toBe('boolean');
9+
});
10+
11+
});
12+
13+
describe('permission', function () {
14+
15+
var callback, // Empty callback
16+
noop; // No operator (empty function)
17+
18+
beforeEach(function () {
19+
callback = jasmine.createSpy('callback');
20+
noop = function () {};
21+
});
22+
23+
it('should have permission stored as a string constant', function () {
24+
expect(typeof Push.Permission.get()).toBe('string');
25+
});
26+
27+
it('should update permission value if permission is denied and execute callback', function (done) {
28+
29+
spyOn(window.Notification, 'requestPermission').and.callFake(function (cb) {
30+
cb(Push.Permission.DENIED);
31+
});
32+
33+
Push.Permission.request(noop, callback);
34+
35+
setTimeout(function () {
36+
expect(Push.Permission.has()).toBe(false);
37+
expect(callback).toHaveBeenCalled();
38+
done();
39+
}, 500);
40+
});
41+
42+
it('should update permission value if permission is granted and execute callback', function (done) {
43+
44+
spyOn(window.Notification, 'requestPermission').and.callFake(function (cb) {
45+
cb(Push.Permission.GRANTED);
46+
});
47+
48+
Push.Permission.request(callback, noop);
49+
50+
setTimeout(function () {
51+
expect(Push.Permission.has()).toBe(true);
52+
expect(callback).toHaveBeenCalled();
53+
done();
54+
}, 500);
55+
});
56+
57+
});
58+
59+
describe('creating notifications', function () {
60+
61+
var callback;
62+
63+
beforeAll(function () {
64+
jasmine.clock().install();
65+
});
66+
67+
beforeEach(function () {
68+
callback = jasmine.createSpy('callback');
69+
});
70+
71+
it('should throw exception if no title is provided', function () {
72+
expect(function() {
73+
Push.create();
74+
}).toThrow();
75+
});
76+
77+
it('should request permission if permission is not granted', function () {
78+
79+
spyOn(window.Notification, 'requestPermission').and.callFake(function (cb) {
80+
cb(Push.Permission.DENIED);
81+
});
82+
83+
Push.Permission.request();
84+
85+
Push.create('hello world!');
86+
87+
expect(window.Notification.requestPermission).toHaveBeenCalled();
88+
});
89+
90+
it('should close notifications if a timeout is specified', function () {
91+
92+
spyOn(window.Notification, 'requestPermission').and.callFake(function (cb) {
93+
cb(Push.Permission.GRANTED);
94+
});
95+
96+
spyOn(window.Notification.prototype, 'close');
97+
98+
Push.create('hello world!', {
99+
timeout: 1000
100+
});
101+
102+
expect(window.Notification.prototype.close).not.toHaveBeenCalled();
103+
104+
jasmine.clock().tick(1000);
105+
106+
expect(window.Notification.prototype.close).toHaveBeenCalled();
107+
108+
});
109+
});

0 commit comments

Comments
 (0)