diff --git a/test/spec/services/analyticsServicesSpec.js b/test/spec/services/analyticsServicesSpec.js index 11054cea54..798e0fab47 100644 --- a/test/spec/services/analyticsServicesSpec.js +++ b/test/spec/services/analyticsServicesSpec.js @@ -1,6 +1,3 @@ -/** - * Created by Sabe on 6/11/2015. - */ 'use strict'; describe('Analytics Service', function () { @@ -20,86 +17,185 @@ describe('Analytics Service', function () { }); }); - context('error handling', function() { - - beforeEach(function() { - sandbox.stub(console, 'log'); - }); - - it('does not accept tracking events without required properties', function() { - analytics.track('action'); - analytics.track({'hitType':'pageview','eventCategory':'green'}); - analytics.track({'hitType':'pageview','eventAction':'eat'}); - analytics.track({'eventCategory':'green','eventAction':'eat'}); - analytics.track({'hitType':'pageview'}); - analytics.track({'eventCategory':'green'}); - analytics.track({'eventAction':'eat'}); - expect(console.log.callCount).to.eql(7); - }); - - it('does not accept tracking events with incorrect hit type', function () { - analytics.track({'hitType':'moogly','eventCategory':'green','eventAction':'eat'}); - expect(console.log).to.have.been.calledOnce; - }); - }); - - context('Amplitude', function() { - - beforeEach(function() { - sandbox.stub(amplitude, 'setUserId'); - sandbox.stub(amplitude, 'logEvent'); - sandbox.stub(amplitude, 'setUserProperties'); - }); + context('functions', function() { describe('register', function() { - it('sets up tracking when user registers', function() { + + beforeEach(function() { + sandbox.stub(amplitude, 'setUserId'); + sandbox.stub(window, 'ga'); + }); + + it('sets up user with amplitude', function() { analytics.register(); expect(amplitude.setUserId).to.have.been.calledOnce; + expect(amplitude.setUserId).to.have.been.calledWith(user._id); + }); + + it('sets up user with google analytics', function() { + analytics.register(); + expect(ga).to.have.been.calledOnce; + expect(ga).to.have.been.calledWith('set', {userId: user._id}); }); }); describe('login', function() { - it('sets up tracking when user logs in', function() { + + beforeEach(function() { + sandbox.stub(amplitude, 'setUserId'); + sandbox.stub(window, 'ga'); + }); + + it('sets up tracking for amplitude', function() { analytics.login(); + expect(amplitude.setUserId).to.have.been.calledOnce; + expect(amplitude.setUserId).to.have.been.calledWith(user._id); + }); + + it('sets up tracking for google analytics', function() { + analytics.login(); + + expect(ga).to.have.been.calledOnce; + expect(ga).to.have.been.calledWith('set', {userId: user._id}); }); }); describe('track', function() { - it('tracks a simple user action', function() { - analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'cron'}); - expect(amplitude.logEvent).to.have.been.calledOnce; - expect(amplitude.logEvent).to.have.been.calledWith('cron',{'hitType':'event','eventCategory':'behavior','eventAction':'cron'}); + + beforeEach(function() { + sandbox.stub(amplitude, 'logEvent'); + sandbox.stub(window, 'ga'); }); - it('tracks a user action with additional properties', function() { - analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'cron','booleanProperty':true,'numericProperty':17,'stringProperty':'bagel'}); - expect(amplitude.logEvent).to.have.been.calledOnce; - expect(amplitude.logEvent).to.have.been.calledWith('cron',{'hitType':'event','eventCategory':'behavior','eventAction':'cron','booleanProperty':true,'numericProperty':17,'stringProperty':'bagel'}); + context('succeful tracking', function() { + + it('tracks a simple user action with amplitude', function() { + var properties = {'hitType':'event','eventCategory':'behavior','eventAction':'cron'}; + analytics.track(properties); + + expect(amplitude.logEvent).to.have.been.calledOnce; + expect(amplitude.logEvent).to.have.been.calledWith('cron', properties); + }); + + it('tracks a simple user action with google analytics', function() { + var properties = {'hitType':'event','eventCategory':'behavior','eventAction':'cron'}; + analytics.track(properties); + + expect(ga).to.have.been.calledOnce; + expect(ga).to.have.been.calledWith('send', properties); + }); + + it('tracks a user action with additional properties in amplitude', function() { + var properties = {'hitType':'event','eventCategory':'behavior','eventAction':'cron','booleanProperty':true,'numericProperty':17,'stringProperty':'bagel'}; + analytics.track(properties); + + expect(amplitude.logEvent).to.have.been.calledOnce; + expect(amplitude.logEvent).to.have.been.calledWith('cron', properties); + }); + + it('tracks a user action with additional properties in google analytics', function() { + var properties = {'hitType':'event','eventCategory':'behavior','eventAction':'cron','booleanProperty':true,'numericProperty':17,'stringProperty':'bagel'}; + analytics.track(properties); + + expect(ga).to.have.been.calledOnce; + expect(ga).to.have.been.calledWith('send', properties); + }); + }); + + context('unsuccesful tracking', function() { + + beforeEach(function() { + sandbox.stub(console, 'log'); + }); + + context('events without requird properties', function() { + beforeEach(function(){ + analytics.track('action'); + analytics.track({'hitType':'pageview','eventCategory':'green'}); + analytics.track({'hitType':'pageview','eventAction':'eat'}); + analytics.track({'eventCategory':'green','eventAction':'eat'}); + analytics.track({'hitType':'pageview'}); + analytics.track({'eventCategory':'green'}); + analytics.track({'eventAction':'eat'}); + }); + + it('logs errors to console', function() { + expect(console.log.callCount).to.eql(7); + }); + + it('does not call out to amplitude', function() { + expect(amplitude.logEvent).to.not.be.called; + }); + + it('does not call out to google analytics', function() { + expect(ga).to.not.be.called; + }); + }); + + context('incorrect hit type', function() { + beforeEach(function() { + analytics.track({'hitType':'moogly','eventCategory':'green','eventAction':'eat'}); + }); + + it('logs error to console', function () { + expect(console.log).to.have.been.calledOnce; + }); + + it('does not call out to amplitude', function() { + expect(amplitude.logEvent).to.not.be.called; + }); + + it('does not call out to google analytics', function() { + expect(ga).to.not.be.called; + }); + }); }); }); describe('updateUser', function() { - it('updates user-level properties with values provided in properties', function() { - analytics.updateUser({'userBoolean': false, 'userNumber': -8, 'userString': 'Enlightened'}); - expect(amplitude.setUserProperties).to.have.been.calledOnce; - expect(amplitude.setUserProperties).to.have.been.calledWith({'userBoolean': false, 'userNumber': -8, 'userString': 'Enlightened'}); + + beforeEach(function() { + sandbox.stub(amplitude, 'setUserProperties'); + sandbox.stub(window, 'ga'); }); - it('updates user-level properties with certain user values when no properties are provided', function() { - user._id = 'unique-user-id'; - user.stats.class = 'wizard'; - user.stats.exp = 35.7; - user.stats.gp = 43.2; - user.stats.hp = 47.8; - user.stats.lvl = 24; - user.stats.mp = 41; - user.contributor.level = 1; - user.purchased.plan.planId = 'unique-plan-id'; + context('properties argument provided', function(){ + var properties = {'userBoolean': false, 'userNumber': -8, 'userString': 'Enlightened'}; + var expectedProperties = _.cloneDeep(properties); + expectedProperties.UUID = 'unique-user-id'; + expectedProperties.Class = 'wizard'; + expectedProperties.Experience = 35; + expectedProperties.Gold = 43; + expectedProperties.Health = 48; + expectedProperties.Level = 24; + expectedProperties.Mana = 41; - analytics.updateUser(); - expect(amplitude.setUserProperties).to.have.been.calledOnce; - expect(amplitude.setUserProperties).to.have.been.calledWith({ + beforeEach(function() { + user._id = 'unique-user-id'; + user.stats.class = 'wizard'; + user.stats.exp = 35.7; + user.stats.gp = 43.2; + user.stats.hp = 47.8; + user.stats.lvl = 24; + user.stats.mp = 41; + + analytics.updateUser(properties); + }); + + it('calls amplitude with provided properties and select user info', function() { + expect(amplitude.setUserProperties).to.have.been.calledOnce; + expect(amplitude.setUserProperties).to.have.been.calledWith(expectedProperties); + }); + + it('calls google analytics with provided properties and select user info', function() { + expect(ga).to.have.been.calledOnce; + expect(ga).to.have.been.calledWith('set', expectedProperties); + }); + }); + + context('no properties argument provided', function() { + var expectedProperties = { UUID: 'unique-user-id', Class: 'wizard', Experience: 35, @@ -109,117 +205,32 @@ describe('Analytics Service', function () { Mana: 41, contributorLevel: 1, subscription: 'unique-plan-id' + }; + + beforeEach(function() { + user._id = 'unique-user-id'; + user.stats.class = 'wizard'; + user.stats.exp = 35.7; + user.stats.gp = 43.2; + user.stats.hp = 47.8; + user.stats.lvl = 24; + user.stats.mp = 41; + user.contributor.level = 1; + user.purchased.plan.planId = 'unique-plan-id'; + + analytics.updateUser(); + }); + + it('calls amplitude with select user info', function() { + expect(amplitude.setUserProperties).to.have.been.calledOnce; + expect(amplitude.setUserProperties).to.have.been.calledWith(expectedProperties); + }); + + it('calls google analytics with select user info', function() { + expect(ga).to.have.been.calledOnce; + expect(ga).to.have.been.calledWith('set', expectedProperties); }); }); }); }); - - context('Google Analytics', function() { - - beforeEach(function() { - sandbox.stub(window, 'ga'); - }); - - describe('register', function() { - it('sets up tracking when user registers', function() { - analytics.register(); - expect(ga).to.have.been.calledOnce; - expect(ga).to.have.been.calledWith('set'); - }); - }); - - describe('login', function() { - it('sets up tracking when user logs in', function() { - analytics.login(); - expect(ga).to.have.been.calledOnce; - expect(ga).to.have.been.calledWith('set'); - }); - }); - - describe('track', function() { - it('tracks a simple user action', function() { - analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'cron'}); - expect(ga).to.have.been.calledOnce; - expect(ga).to.have.been.calledWith('send',{'hitType':'event','eventCategory':'behavior','eventAction':'cron'}); - }); - - it('tracks a user action with additional properties', function() { - analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'cron','booleanProperty':true,'numericProperty':17,'stringProperty':'bagel'}); - expect(ga).to.have.been.calledOnce; - expect(ga).to.have.been.calledWith('send',{'hitType':'event','eventCategory':'behavior','eventAction':'cron','booleanProperty':true,'numericProperty':17,'stringProperty':'bagel'}); - }); - }); - - describe('updateUser', function() { - it('updates user-level properties with values provided in properties', function() { - analytics.updateUser({'userBoolean': false, 'userNumber': -8, 'userString': 'Enlightened'}); - expect(ga).to.have.been.calledOnce; - expect(ga).to.have.been.calledWith('set', {'userBoolean': false, 'userNumber': -8, 'userString': 'Enlightened'}); - }); - - it('updates user-level properties', function() { - user._id = 'unique-user-id'; - user.stats.class = 'wizard'; - user.stats.exp = 35.7; - user.stats.gp = 43.2; - user.stats.hp = 47.8; - user.stats.lvl = 24; - user.stats.mp = 41; - user.contributor.level = 1; - user.purchased.plan.planId = 'unique-plan-id'; - - analytics.updateUser(); - expect(ga).to.have.been.calledOnce; - expect(ga).to.have.been.calledWith('set',{ - UUID: 'unique-user-id', - Class: 'wizard', - Experience: 35, - Gold: 43, - Health: 48, - Level: 24, - Mana: 41, - contributorLevel: 1, - subscription: 'unique-plan-id' - }); - }); - }); - }); - - context.skip('Mixpanel', function() { // Mixpanel not currently in use - - beforeEach(function() { - sandbox.stub(mixpanel, 'alias'); - sandbox.stub(mixpanel, 'identify'); - sandbox.stub(mixpanel, 'track'); - sandbox.stub(mixpanel, 'register'); - }); - - it('sets up tracking when user registers', function() { - analytics.register(); - expect(mixpanel.alias).to.have.been.calledOnce; - }); - - it('sets up tracking when user logs in', function() { - analytics.login(); - expect(mixpanel.identify).to.have.been.calledOnce; - }); - - it('tracks a simple user action', function() { - analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'cron'}); - expect(mixpanel.track).to.have.been.calledOnce; - expect(mixpanel.track).to.have.been.calledWith('cron',{'hitType':'event','eventCategory':'behavior','eventAction':'cron'}); - }); - - it('tracks a user action with additional properties', function() { - analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'cron','booleanProperty':true,'numericProperty':17,'stringProperty':'bagel'}); - expect(mixpanel.track).to.have.been.calledOnce; - expect(mixpanel.track).to.have.been.calledWith('cron',{'hitType':'event','eventCategory':'behavior','eventAction':'cron','booleanProperty':true,'numericProperty':17,'stringProperty':'bagel'}); - }); - - it('updates user-level properties', function() { - analytics.updateUser({'userBoolean': false, 'userNumber': -8, 'userString': 'Enlightened'}); - expect(mixpanel.register).to.have.been.calledOnce; - expect(mixpanel.register).to.have.been.calledWith({'userBoolean': false, 'userNumber': -8, 'userString': 'Enlightened'}); - }); - }); }); diff --git a/website/public/js/services/analyticsServices.js b/website/public/js/services/analyticsServices.js index e1915e8f2f..417b89e649 100644 --- a/website/public/js/services/analyticsServices.js +++ b/website/public/js/services/analyticsServices.js @@ -1,6 +1,3 @@ -/** - * Created by Sabe on 6/15/2015. - */ 'use strict'; angular @@ -119,25 +116,27 @@ function analyticsFactory(User) { } function updateUser(properties) { - if (!properties) { - properties = {}; + if (!properties) properties = {}; - if (user._id) properties.UUID = user._id; - if (user.stats.class) properties.Class = user.stats.class; - if (user.stats.exp) properties.Experience = Math.floor(user.stats.exp); - if (user.stats.gp) properties.Gold = Math.floor(user.stats.gp); - if (user.stats.hp) properties.Health = Math.ceil(user.stats.hp); - if (user.stats.lvl) properties.Level = user.stats.lvl; - if (user.stats.mp) properties.Mana = Math.floor(user.stats.mp); - if (user.contributor.level) properties.contributorLevel = user.contributor.level; - if (user.purchased.plan.planId) properties.subscription = user.purchased.plan.planId; - } + _gatherUserStats(user, properties); amplitude.setUserProperties(properties); ga('set',properties); // mixpanel.register(properties); } + function _gatherUserStats(user, properties) { + if (user._id) properties.UUID = user._id; + if (user.stats.class) properties.Class = user.stats.class; + if (user.stats.exp) properties.Experience = Math.floor(user.stats.exp); + if (user.stats.gp) properties.Gold = Math.floor(user.stats.gp); + if (user.stats.hp) properties.Health = Math.ceil(user.stats.hp); + if (user.stats.lvl) properties.Level = user.stats.lvl; + if (user.stats.mp) properties.Mana = Math.floor(user.stats.mp); + if (user.contributor.level) properties.contributorLevel = user.contributor.level; + if (user.purchased.plan.planId) properties.subscription = user.purchased.plan.planId; + } + return { loadScripts: loadScripts, register: register,