From b375c068deed7853084f812b5a0d5b975ae4bfb7 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Tue, 2 Jun 2015 07:51:54 -0500 Subject: [PATCH] Refactor notification service and add tests --- karma.conf.js | 1 + test/spec/notificationServicesSpec.js | 185 +++++++++++++++++- .../js/services/notificationServices.js | 184 ++++++++++------- 3 files changed, 293 insertions(+), 77 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 53a7e4999b..a6d310f33b 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -12,6 +12,7 @@ module.exports = function(config) { // list of files / patterns to load in the browser files: [ 'website/public/bower_components/jquery/dist/jquery.js', + 'website/public/bower_components/pnotify/jquery.pnotify.js', 'website/public/bower_components/angular/angular.js', 'website/public/bower_components/angular-loading-bar/build/loading-bar.min.js', 'website/public/bower_components/angular-resource/angular-resource.min.js', diff --git a/test/spec/notificationServicesSpec.js b/test/spec/notificationServicesSpec.js index fbaae22aa0..85570c8372 100644 --- a/test/spec/notificationServicesSpec.js +++ b/test/spec/notificationServicesSpec.js @@ -1,9 +1,14 @@ 'use strict'; -//TODO mock bootstrapGrowl, add remaining tests describe('notificationServices', function() { var notification; + before(function(){ + sinon.stub($, 'pnotify', function(){ + return { click: function(){}} + }); + }); + beforeEach(function() { module(function($provide){ $provide.value('User', {}); @@ -14,12 +19,190 @@ describe('notificationServices', function() { }); }); + afterEach(function() { + $.pnotify.reset(); + }); + it('notifies coins amount', function() { var SILVER_COIN = ""; var GOLD_COIN = ""; + + expect(notification.coins(0)).to.not.exist; expect(notification.coins(0.01)).to.eql("1 " + SILVER_COIN); expect(notification.coins(0.1)).to.eql("10 " + SILVER_COIN); expect(notification.coins(1)).to.eql("1 " + GOLD_COIN); expect(notification.coins(12.34)).to.eql("12 " + GOLD_COIN +" 33 " + SILVER_COIN); }); + + it('sends crit notification', function() { + notification.crit(5); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('crit'); + expect(arg.text).to.eql('Critical Hit! Bonus: 5%'); + expect(arg.icon).to.eql('glyphicon glyphicon-certificate'); + }); + + it('sends drop notification for unspecified item', function() { + notification.drop('msg'); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('drop'); + expect(arg.text).to.eql('msg'); + expect(arg.icon).to.eql(false); + }); + + it('sends drop notification for Egg', function() { + var item = { type: 'Egg', key: 'wolf' }; + notification.drop('msg', item); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('drop'); + expect(arg.text).to.eql('msg'); + expect(arg.icon).to.eql('Pet_Egg_wolf'); + }); + + it('sends drop notification for Hatching Potion', function() { + var item = { type: 'HatchingPotion', key: 'red' }; + notification.drop('msg', item); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('drop'); + expect(arg.text).to.eql('msg'); + expect(arg.icon).to.eql('Pet_HatchingPotion_red'); + }); + + it('sends drop notification for Food', function() { + var item = { type: 'Food', key: 'meat' }; + notification.drop('msg', item); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('drop'); + expect(arg.text).to.eql('msg'); + expect(arg.icon).to.eql('Pet_Food_meat'); + }); + + it('does not send exp notification if val < -50', function() { + notification.exp(-51); + expect($.pnotify).to.not.have.been.called; + }); + + it('send exp notification if val >= -50', function() { + notification.exp(50); + notification.exp(0); + notification.exp(-50); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledThrice; + expect(arg.type).to.eql('xp'); + expect(arg.text).to.eql('+ 50 XP'); + expect(arg.icon).to.eql('glyphicon glyphicon-star'); + }); + + it('send exp notification with rounded value', function() { + notification.exp(50.23333); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('xp'); + expect(arg.text).to.eql('+ 50.2 XP'); + expect(arg.icon).to.eql('glyphicon glyphicon-star'); + }); + + it('send error notification', function() { + notification.error('there was an error'); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('danger'); + expect(arg.text).to.eql('there was an error'); + expect(arg.icon).to.eql('glyphicon glyphicon-exclamation-sign'); + }); + + it('send gp gained notification', function() { + notification.gp(50, 4); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('gp'); + expect(arg.text).to.eql('+ 46 '); + expect(arg.icon).to.eql(false); + }); + + it('send hp notification', function() { + notification.hp(10); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('hp'); + expect(arg.text).to.eql('+ 10 HP'); + expect(arg.icon).to.eql('glyphicon glyphicon-heart'); + }); + + it('send level up notification', function() { + notification.lvl(10); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('lvl'); + expect(arg.text).to.eql('Level Up!'); + expect(arg.icon).to.eql('glyphicon glyphicon-chevron-up'); + }); + + it('send markdown parsed notification', function() { + notification.markdown(":smile: - task name"); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('info'); + expect(arg.text).to.eql('

:smile: - task name

\n'); + expect(arg.icon).to.eql(false); + }); + + it('does not send markdown notification if no text is given', function() { + notification.markdown(); + + expect($.pnotify).to.not.have.been.called; + }); + + it('send mp notification', function() { + notification.mp(10); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('mp'); + expect(arg.text).to.eql('+ 10 MP'); + expect(arg.icon).to.eql('glyphicon glyphicon-fire'); + }); + + it('send streak notification', function() { + notification.streak(10); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('streak'); + expect(arg.text).to.eql('Streak Achievements: 10'); + expect(arg.icon).to.eql('glyphicon glyphicon-repeat'); + }); + + it('send text notification', function() { + notification.text('task name'); + var arg = $.pnotify.args[0][0] + + expect($.pnotify).to.have.been.calledOnce; + expect(arg.type).to.eql('info'); + expect(arg.text).to.eql('task name'); + expect(arg.icon).to.eql(false); + }); + + it('does not send text notification if no text is given', function() { + notification.text(); + + expect($.pnotify).to.not.have.been.called; + }); }); diff --git a/website/public/js/services/notificationServices.js b/website/public/js/services/notificationServices.js index f6f586293c..f53894b65e 100644 --- a/website/public/js/services/notificationServices.js +++ b/website/public/js/services/notificationServices.js @@ -1,24 +1,27 @@ +'use strict' /** Set up "+1 Exp", "Level Up", etc notifications */ angular.module("habitrpg").factory("Notification", ['$filter', function($filter) { - var stack_topright = {"dir1": "down", "dir2": "left", "spacing1": 15, "spacing2": 15, "firstpos1": 60}; - function notify(html, type, icon) { - var notice = $.pnotify({ - type: type || 'warning', //('info', 'text', 'warning', 'success', 'gp', 'xp', 'hp', 'lvl', 'death', 'mp', 'crit') - text: html, - opacity: 1, - addclass: 'alert-' + type, - delay: 7000, - hide: (type == 'error') ? false : true, - mouse_reset: false, - width: "250px", - stack: stack_topright, - icon: icon || false - }).click(function() { notice.pnotify_remove() }); + + var notificationService = { + coins: coins, + crit: crit, + drop: drop, + exp: exp, + error: error, + gp: gp, + hp: hp, + lvl: lvl, + markdown: markdown, + mp: mp, + streak: streak, + text: text }; + return notificationService; + /** Show "+ 5 {gold_coin} 3 {silver_coin}" */ @@ -34,73 +37,102 @@ angular.module("habitrpg").factory("Notification", } else if (silver > 0) { return "" + silver + " "; } - }; + } - var sign = function(number){ + function crit(val) { + _notify(window.env.t('critBonus') + Math.round(val) + "%", 'crit', 'glyphicon glyphicon-certificate'); + } + + function drop(val, item) { + var dropClass = ""; + if ( item !== undefined ) { + switch ( item.type ) { + case "Egg": + dropClass = 'Pet_Egg_' + item.key; + break; + case "HatchingPotion": + dropClass = 'Pet_HatchingPotion_' + item.key; + break; + case "Food": + dropClass = 'Pet_Food_' + item.key; + break; + default: + dropClass = 'glyphicon glyphicon-gift'; + } + } + _notify(val, 'drop', dropClass); + } + + function exp(val) { + if (val < -50) return; // don't show when they level up (resetting their exp) + _notify(_sign(val) + " " + _round(val) + " " + window.env.t('xp'), 'xp', 'glyphicon glyphicon-star'); + } + + function error(error){ + _notify(error, "danger", 'glyphicon glyphicon-exclamation-sign'); + } + + function gp(val, bonus) { + _notify(_sign(val) + " " + coins(val - bonus), 'gp'); + } + + function hp(val) { + // don't show notifications if user dead + _notify(_sign(val) + " " + _round(val) + " " + window.env.t('hp'), 'hp', 'glyphicon glyphicon-heart'); + } + + function lvl(){ + _notify(window.env.t('levelUp'), 'lvl', 'glyphicon glyphicon-chevron-up'); + } + + function markdown(val){ + if (val) { + var parsed_markdown = $filter("markdown")(val); + _notify(parsed_markdown, 'info'); + } + } + + function mp(val) { + _notify(_sign(val) + " " + _round(val) + " " + window.env.t('mp'), 'mp', 'glyphicon glyphicon-fire'); + } + + function streak(val) { + _notify(window.env.t('streakName') + ': ' + val, 'streak', 'glyphicon glyphicon-repeat'); + } + + function text(val){ + if (val) { + _notify(val, 'info'); + } + } + + //-------------------------------------------------- + // Private Methods + //-------------------------------------------------- + + function _sign(number){ return number?number<0?'-':'+':'+'; } - var round = function(number){ + function _round(number){ return Math.abs(number.toFixed(1)); } - return { - coins: coins, - hp: function(val) { - // don't show notifications if user dead - notify(sign(val) + " " + round(val) + " " + window.env.t('hp'), 'hp', 'glyphicon glyphicon-heart'); - }, - exp: function(val) { - if (val < -50) return; // don't show when they level up (resetting their exp) - notify(sign(val) + " " + round(val) + " " + window.env.t('xp'), 'xp', 'glyphicon glyphicon-star'); - }, - gp: function(val, bonus) { - notify(sign(val) + " " + coins(val - bonus), 'gp'); - }, - text: function(val){ - if (val) { - notify(val, 'info'); - } - }, - markdown: function(val){ - if (val) { - var parsed_markdown = $filter("markdown")(val); - notify(parsed_markdown, 'info'); - } - }, - lvl: function(){ - notify(window.env.t('levelUp'), 'lvl', 'glyphicon glyphicon-chevron-up'); - }, - error: function(error){ - notify(error, "danger", 'glyphicon glyphicon-exclamation-sign'); - }, - mp: function(val) { - notify(sign(val) + " " + round(val) + " " + window.env.t('mp'), 'mp', 'glyphicon glyphicon-fire'); - }, - crit: function(val) { - notify(window.env.t('critBonus') + Math.round(val) + "%", 'crit', 'glyphicon glyphicon-certificate'); - }, - streak: function(val) { - notify(window.env.t('streakName') + ': ' + val, 'streak', 'glyphicon glyphicon-repeat'); - }, - drop: function(val, item) { - var dropClass = ""; - if ( item !== undefined ) { - switch ( item.type ) { - case "Egg": - dropClass = 'Pet_Egg_' + item.key; - break; - case "HatchingPotion": - dropClass = 'Pet_HatchingPotion_' + item.key; - break; - case "Food": - dropClass = 'Pet_Food_' + item.key; - break; - default: - dropClass = 'glyphicon glyphicon-gift'; - } - } - notify(val, 'drop', dropClass); - } - }; + // Used to stack notifications, must be outside of _notify + var stack_topright = {"dir1": "down", "dir2": "left", "spacing1": 15, "spacing2": 15, "firstpos1": 60}; + + function _notify(html, type, icon) { + var notice = $.pnotify({ + type: type || 'warning', //('info', 'text', 'warning', 'success', 'gp', 'xp', 'hp', 'lvl', 'death', 'mp', 'crit') + text: html, + opacity: 1, + addclass: 'alert-' + type, + delay: 7000, + hide: (type == 'error') ? false : true, + mouse_reset: false, + width: "250px", + stack: stack_topright, + icon: icon || false + }).click(function() { notice.pnotify_remove() }); + } }]);