Skip to content
This repository has been archived by the owner on Mar 7, 2023. It is now read-only.

Commit

Permalink
Merge pull request #95 from blockchain/analytics
Browse files Browse the repository at this point in the history
Track wallet creation and upgrades
  • Loading branch information
Pernas committed Jan 29, 2016
2 parents 51bc2ac + 3b12c3e commit e2ccf63
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 1 deletion.
1 change: 1 addition & 0 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ module.exports = function(karma) {
'node_modules/jasmine-es6-promise-matchers/jasmine-es6-promise-matchers.js',
'tests/wallet_token_endpoints.js.coffee',
'tests/wallet_network_spec.js.coffee',
'tests/analytics.js.coffee',
// 'src/shared.js',
// 'tests/**/*.coffee',
// Or specify individual test files:
Expand Down
45 changes: 45 additions & 0 deletions src/analytics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict';

var assert = require('assert');

var API = require('./api');
var CryptoJS = require('crypto-js');

// If there is a problem with the analytics endpoint, the application should
// just proceed. Therefor we're not returning a promise in the methods below.

function postEvent(name, guid) {
assert(name, "Event name required");
assert(guid, "Wallet identifier required");

var fail = function() {
console.log("Unable to post to analytics endpoint.");
}

var handleResponse = function (res) {
if (!res || !res.success)
fail();
};

var params = {
name: name,
hashed_guid: CryptoJS.SHA256(guid).toString()
};

API.request('POST', 'wallet-event', params, false)
.then(handleResponse).catch(fail);
}

function walletCreated(guid) {
this.postEvent('create_v3', guid);
}

function walletUpgraded(guid) {
this.postEvent('upgrade_v3', guid);
}

module.exports = {
postEvent: postEvent, // For tests
walletCreated: walletCreated,
walletUpgraded: walletUpgraded
};
8 changes: 7 additions & 1 deletion src/blockchain-wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var Tx = require('./wallet-transaction');
var shared = require('./shared');
var BlockchainSettingsAPI = require('./blockchain-settings-api');
var KeyRing = require('./keyring');
var Analytics = require('./analytics');

////////////////////////////////////////////////////////////////////////////////
// Wallet
Expand Down Expand Up @@ -739,7 +740,12 @@ Wallet.prototype.newHDWallet = function(firstAccountLabel, pw, success, error){
this._hd_wallets.push(newHDwallet);
var label = firstAccountLabel ? firstAccountLabel : "My Bitcoin Wallet";
var account = this.newAccount(label, pw, this._hd_wallets.length-1, true);
MyWallet.syncWallet(success, error);
var guid = this.guid;
MyWallet.syncWallet(function(res) {
Analytics.walletUpgraded(guid);
success();
}, error);

return newHDwallet;
};

Expand Down
6 changes: 6 additions & 0 deletions src/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var Wallet = require('./blockchain-wallet');
var Helpers = require('./helpers');
var shared = require('./shared');
var BlockchainSocket = require('./blockchain-socket');
var Analytics = require('./analytics');

var isInitialized = false;
MyWallet.wallet = undefined;
Expand Down Expand Up @@ -1175,6 +1176,11 @@ MyWallet.createNewWallet = function(inputedEmail, inputedPassword, firstAccountN

WalletStore.unsafeSetPassword(createdPassword);

var isHD = Helpers.isBoolean(isHD) ? isHD : true;
if (isHD) {
Analytics.walletCreated(createdGuid);
}

success(createdGuid, createdSharedKey, createdPassword);
}, function (e) {
error(e);
Expand Down
95 changes: 95 additions & 0 deletions tests/analytics.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
proxyquire = require('proxyquireify')(require)

describe "analytics", ->

API = {
request: (action, method, data, withCred) ->
# new Promise (resolve, reject) ->
# Not using an actual promise here, because the tests are synchronous,
# which is because the methods don't return promises.
{
then: (cb) ->
if data.hashed_guid == "guid|sha256"
cb({success: true})
{
catch: (cb) ->
if data.hashed_guid == "guid|sha256"
# Handled by 'then'
else if data.hashed_guid == "guid-fail-200|sha256"
cb({success: false, error: "Some reason"})
else if data.hashed_guid == "guid-fail-500|sha256"
cb("Server error")
else
cb("Unknown")
}
}
}

CryptoJS = {
SHA256: (input) -> {
toString: () ->
input + "|sha256"
}
}

Analytics = proxyquire('../src/analytics', {
'./api': API,
'crypto-js' : CryptoJS
})

describe "postEvent", ->

beforeEach ->
spyOn(API, "request").and.callThrough()
spyOn(window.console, "log")

it "should require a guid and event name", ->
expect(() -> Analytics.postEvent()).toThrow()
expect(() -> Analytics.postEvent("event")).toThrow()
expect(() -> Analytics.postEvent("event", "guid", {})).not.toThrow()

it "should not return a promise", ->
res = Analytics.postEvent("event", "guid")
expect(res).not.toBeDefined()

it "should submit the event", ->
Analytics.postEvent("event", "guid")
expect(API.request).toHaveBeenCalled()
expect(API.request.calls.argsFor(0)[2].name).toEqual('event')

it "should submit the hashed guid", ->
Analytics.postEvent("event", "guid")
expect(API.request).toHaveBeenCalled()
expect(API.request.calls.argsFor(0)[2].hashed_guid).toEqual('guid|sha256')

it "should not log to the console if all goes well", ->
Analytics.postEvent("event", "guid")
expect(window.console.log).not.toHaveBeenCalled()

it "should log to the console if server returns 500", (done) ->
Analytics.postEvent("event", "guid-fail-500")
expect(window.console.log).toHaveBeenCalled()
done()

it "should log to the console if server returns 200 and {success: false}",->
Analytics.postEvent("event", "guid-fail-200")
expect(window.console.log).toHaveBeenCalled()

describe "walletCreated", ->
it "shoud call postEvent with create_v3 and guid", ->
spyOn(Analytics, "postEvent").and.callThrough()
promise = Analytics.walletCreated("guid")

expect(Analytics.postEvent).toHaveBeenCalled()
expect(Analytics.postEvent.calls.argsFor(0)[0]).toEqual("create_v3")
expect(Analytics.postEvent.calls.argsFor(0)[1]).toEqual("guid")


describe "walletUpgraded", ->
it "shoud call postEvent with guid and upgrade_v3", ->
spyOn(Analytics, "postEvent").and.callThrough()
promise = Analytics.walletUpgraded("guid")

expect(Analytics.postEvent).toHaveBeenCalled()
expect(Analytics.postEvent.calls.argsFor(0)[0]).toEqual("upgrade_v3")
expect(Analytics.postEvent.calls.argsFor(0)[1]).toEqual("guid")

0 comments on commit e2ccf63

Please sign in to comment.