mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
Set up purchase tracking
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
"main": "./website/src/server.js",
|
||||
"dependencies": {
|
||||
"amazon-payments": "0.0.4",
|
||||
"amplitude": "^1.0.3",
|
||||
"amplitude": "1.0.4",
|
||||
"async": "~0.9.0",
|
||||
"aws-sdk": "^2.0.25",
|
||||
"babel": "^5.5.4",
|
||||
|
||||
@@ -6,73 +6,151 @@ var rewire = require('rewire');
|
||||
|
||||
describe('analytics', function() {
|
||||
var amplitudeMock = sinon.stub();
|
||||
var googleAnalyticsMock = sinon.stub();
|
||||
|
||||
describe('init', function() {
|
||||
var analytics = rewire('../../website/src/analytics');
|
||||
|
||||
afterEach(function(){
|
||||
amplitudeMock.reset();
|
||||
googleAnalyticsMock.reset();
|
||||
});
|
||||
|
||||
it('throws an error if no options are passed in', function() {
|
||||
expect(analytics).to.throw('No options provided');
|
||||
});
|
||||
|
||||
it('registers amplitude with token', function() {
|
||||
analytics.__set__('Amplitude', amplitudeMock);
|
||||
var options = {
|
||||
amplitudeToken: 'token'
|
||||
};
|
||||
analytics(options);
|
||||
|
||||
expect(amplitudeMock).to.be.calledOnce;
|
||||
expect(amplitudeMock).to.be.calledWith('token');
|
||||
});
|
||||
|
||||
it('registers google analytics with token', function() {
|
||||
analytics.__set__('googleAnalytics', googleAnalyticsMock);
|
||||
var options = {
|
||||
googleAnalytics: 'token'
|
||||
};
|
||||
analytics(options);
|
||||
|
||||
expect(googleAnalyticsMock).to.be.calledOnce;
|
||||
expect(googleAnalyticsMock).to.be.calledWith('token');
|
||||
});
|
||||
});
|
||||
|
||||
describe('trackPurchase', function() {
|
||||
|
||||
var purchaseData = {
|
||||
uuid: 'user-id',
|
||||
sku: 'paypal-checkout',
|
||||
paymentMethod: 'PayPal',
|
||||
itemPurchased: 'Gems',
|
||||
purchaseValue: 8,
|
||||
purchaseType: 'checkout',
|
||||
gift: false,
|
||||
quantity: 1
|
||||
}
|
||||
|
||||
var analytics = rewire('../../website/src/analytics');
|
||||
var amplitudeTrack = sinon.stub();
|
||||
var googleEvent = sinon.stub().returns({
|
||||
send: function() { return true }
|
||||
});
|
||||
var googleItem = sinon.stub().returns({
|
||||
send: function() {}
|
||||
});
|
||||
var googleTransaction = sinon.stub().returns({
|
||||
item: googleItem
|
||||
});
|
||||
var initializedAnalytics;
|
||||
|
||||
beforeEach(function() {
|
||||
analytics.__set__('Amplitude', amplitudeMock);
|
||||
initializedAnalytics = analytics({amplitudeToken: 'token', googleAnalytics: 'token'});
|
||||
analytics.__set__('amplitude.track', amplitudeTrack);
|
||||
analytics.__set__('ga.event', googleEvent);
|
||||
analytics.__set__('ga.transaction', googleTransaction);
|
||||
});
|
||||
|
||||
afterEach(function(){
|
||||
amplitudeMock.reset();
|
||||
googleEvent.reset();
|
||||
googleTransaction.reset();
|
||||
googleItem.reset();
|
||||
});
|
||||
|
||||
it('throws an error if no options are passed in', function() {
|
||||
expect(analytics.init).to.throw('No options provided');
|
||||
});
|
||||
it('calls amplitude.track', function() {
|
||||
|
||||
it('registers amplitude with token', function() {
|
||||
var options = {
|
||||
amplitudeToken: 'token',
|
||||
uuid: 'user-id'
|
||||
};
|
||||
analytics.init(options);
|
||||
initializedAnalytics.trackPurchase(purchaseData);
|
||||
|
||||
expect(amplitudeMock).to.be.calledOnce;
|
||||
expect(amplitudeMock).to.be.calledWith('token', 'user-id');
|
||||
});
|
||||
|
||||
it('does not register amplitude without token', function() {
|
||||
var options = { uuid: 'user-id' };
|
||||
analytics.init(options);
|
||||
|
||||
expect(amplitudeMock).to.not.be.called;
|
||||
});
|
||||
});
|
||||
|
||||
describe('track', function() {
|
||||
var analytics = rewire('../../website/src/analytics');
|
||||
|
||||
context('amplitude not initialized', function() {
|
||||
it('throws error', function() {
|
||||
expect(analytics.track).to.throw('Amplitude not initialized');
|
||||
expect(amplitudeTrack).to.be.calledOnce;
|
||||
expect(amplitudeTrack).to.be.calledWith({
|
||||
event_type: 'purchase',
|
||||
user_id: 'user-id',
|
||||
event_properties: {
|
||||
paymentMethod: 'PayPal',
|
||||
sku: 'paypal-checkout',
|
||||
gift: false,
|
||||
itemPurchased: 'Gems',
|
||||
purchaseType: 'checkout',
|
||||
quantity: 1
|
||||
},
|
||||
revenue: 8
|
||||
});
|
||||
});
|
||||
|
||||
context('amplitude initialized', function() {
|
||||
var amplitudeTrack = sinon.stub();
|
||||
it('calls ga.event', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
analytics.__set__('Amplitude', amplitudeMock);
|
||||
analytics.init({amplitudeToken: 'token', uuid: 'user-id'});
|
||||
analytics.__set__('amplitude.track', amplitudeTrack);
|
||||
});
|
||||
initializedAnalytics.trackPurchase(purchaseData);
|
||||
|
||||
afterEach(function(){
|
||||
amplitudeMock.reset();
|
||||
});
|
||||
expect(googleEvent).to.be.calledOnce;
|
||||
expect(googleEvent).to.be.calledWith(
|
||||
'commerce',
|
||||
'checkout',
|
||||
'PayPal',
|
||||
8
|
||||
);
|
||||
});
|
||||
|
||||
it('tracks event in amplitude', function() {
|
||||
var data = {
|
||||
foo: 'bar'
|
||||
};
|
||||
it('calls ga.transaction', function() {
|
||||
|
||||
analytics.track(data);
|
||||
initializedAnalytics.trackPurchase(purchaseData);
|
||||
|
||||
expect(amplitudeTrack).to.be.calledOnce;
|
||||
expect(amplitudeTrack).to.be.calledWith(data);
|
||||
});
|
||||
expect(googleTransaction).to.be.calledOnce;
|
||||
expect(googleTransaction).to.be.calledWith(
|
||||
'user-id',
|
||||
8
|
||||
);
|
||||
expect(googleItem).to.be.calledOnce;
|
||||
expect(googleItem).to.be.calledWith(
|
||||
8,
|
||||
1,
|
||||
'paypal-checkout',
|
||||
'Gems',
|
||||
'checkout'
|
||||
);
|
||||
});
|
||||
|
||||
it('appends gift to variation of ga.transaction.item if gift is true', function() {
|
||||
|
||||
var purchaseDataWithGift = _.clone(purchaseData);
|
||||
purchaseDataWithGift.gift = true;
|
||||
|
||||
initializedAnalytics.trackPurchase(purchaseDataWithGift);
|
||||
|
||||
expect(googleItem).to.be.calledOnce;
|
||||
expect(googleItem).to.be.calledWith(
|
||||
8,
|
||||
1,
|
||||
'paypal-checkout',
|
||||
'Gems',
|
||||
'checkout - Gift'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,22 +1,74 @@
|
||||
var _ = require('lodash');
|
||||
var Amplitude = require('amplitude');
|
||||
var googleAnalytics = require('universal-analytics');
|
||||
|
||||
var ga;
|
||||
var amplitude;
|
||||
|
||||
var analytics = {
|
||||
init: init,
|
||||
track: track
|
||||
trackPurchase: trackPurchase
|
||||
}
|
||||
|
||||
function init(options) {
|
||||
if(!options) { throw 'No options provided' }
|
||||
|
||||
if(options.amplitudeToken) {
|
||||
amplitude = new Amplitude(options.amplitudeToken, options.uuid);
|
||||
amplitude = new Amplitude(options.amplitudeToken);
|
||||
ga = googleAnalytics(options.googleAnalytics);
|
||||
|
||||
return analytics;
|
||||
}
|
||||
|
||||
function trackPurchase(data) {
|
||||
_sendPurchaseDataToAmplitude(data);
|
||||
_sendPurchaseDataToGoogle(data);
|
||||
}
|
||||
|
||||
function _sendPurchaseDataToAmplitude(data) {
|
||||
var amplitudeData = _formatDataForAmplitude(data);
|
||||
amplitudeData.event_type = 'purchase';
|
||||
amplitudeData.revenue = data.purchaseValue;
|
||||
|
||||
amplitude.track(amplitudeData)
|
||||
}
|
||||
|
||||
function _formatDataForAmplitude(data) {
|
||||
var PROPERTIES_TO_SCRUB = ['uuid', 'user', 'purchaseValue'];
|
||||
var event_properties = _.omit(data, PROPERTIES_TO_SCRUB);
|
||||
|
||||
var ampData = {
|
||||
user_id: data.uuid,
|
||||
event_properties: event_properties
|
||||
}
|
||||
|
||||
if(data.user) {
|
||||
ampData.user_properties = _formatUserData(data.user);
|
||||
}
|
||||
|
||||
return ampData;
|
||||
}
|
||||
|
||||
function track(data) {
|
||||
if(!amplitude) throw 'Amplitude not initialized';
|
||||
amplitude.track(data);
|
||||
function _formatUserData(user) {
|
||||
var data = {};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
module.exports = analytics;
|
||||
function _sendPurchaseDataToGoogle(data) {
|
||||
var label = data.paymentMethod;
|
||||
var type = data.purchaseType;
|
||||
var price = data.purchaseValue;
|
||||
var qty = data.quantity;
|
||||
var sku = data.sku;
|
||||
var itemName = data.itemPurchased;
|
||||
var variation = type;
|
||||
if(data.gift) variation += ' - Gift';
|
||||
|
||||
ga.event('commerce', type, label, price)
|
||||
.send();
|
||||
|
||||
ga.transaction(data.uuid, price)
|
||||
.item(price, qty, sku, itemName, variation)
|
||||
.send();
|
||||
}
|
||||
|
||||
module.exports = init;
|
||||
|
||||
Reference in New Issue
Block a user