Skip to content
This repository has been archived by the owner on Sep 16, 2019. It is now read-only.

add gosquared #14

Merged
merged 1 commit into from
May 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/resin-event-log/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"bluebird": "^3.4.7",
"lodash": "^4.0.0",
"resin-mixpanel-client": "^2.1.0",
"resin-universal-ga": "^1.1.0"
"resin-universal-ga": "^1.1.0",
"resin-universal-gosquared": "^0.1.0"
},
"devDependencies": {
"base-64": "^0.1.0",
Expand Down
36 changes: 36 additions & 0 deletions packages/resin-event-log/src/adaptors/gosquared.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
var ResinGsClient = require('resin-universal-gosquared')

module.exports = function (options) {
var debug = options.debug,
gosquaredId = options.gosquaredId,
apiKey = options.gosquaredApiKey,
isBrowser = typeof window !== 'undefined'

if (!gosquaredId) {
if (debug) {
console.warn("`gosquaredId` is not set, gosquared tracking is disabled")
}
return null
}

if (!isBrowser && !apiKey) {
if (debug) {
console.warn("`gosquaredApiKey` is not set, gosquared tracking is disabled")
}
return null
}

var gsClient = ResinGsClient(gosquaredId, apiKey, debug)

return {
login: function(user) {
return gsClient.login(user.id)
},
logout: function() {
return gsClient.logout()
},
track: function (prefix, type, data) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why ignoring prefix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I now pass them down like we do for mixpanel so events are named like so: [ prefix ] eventType.

return gsClient.track(prefix, type, data)
}
}
}
6 changes: 4 additions & 2 deletions packages/resin-event-log/src/resin-event-log.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ var EVENTS = {
application: [ 'create', 'open', 'delete', 'osDownload' ],
environmentVariable: [ 'create', 'edit', 'delete' ],
device: [ 'open', 'rename', 'delete', 'terminalOpen', 'terminalClose' ],
deviceEnvironmentVariable: [ 'create', 'edit', 'delete' ]
deviceEnvironmentVariable: [ 'create', 'edit', 'delete' ],
page: [ 'visit' ]
}

var DEFAULT_HOOKS = {
Expand All @@ -23,7 +24,8 @@ var DEFAULT_HOOKS = {

var ADAPTORS = [
require('./adaptors/ga'),
require('./adaptors/mixpanel')
require('./adaptors/mixpanel'),
require('./adaptors/gosquared')
]

module.exports = function(options) {
Expand Down
154 changes: 152 additions & 2 deletions packages/resin-event-log/test/resin-event-log.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ var _ = require('lodash')
var expect = require('chai').expect
var base64Decode = require('base-64').decode
var querystring = require('querystring')

var mock = require('resin-universal-http-mock')

var IS_BROWSER = typeof window !== 'undefined'
Expand All @@ -24,6 +23,9 @@ var SYSTEM = 'TEST'
var MIXPANEL_HOST = 'http://api.mixpanel.com'
var GA_ID = 'UA-123456-0'
var GA_SITE = 'resintest.io'
var GOSQUARED_ID = 'GSN-575655-Q'
var GOSQUARED_API_KEY = '12345'
var GOSQUARED_HOST = 'https://api.gosquared.com'
var GA_HOST = 'https://www.google-analytics.com'
var FAKE_USER = {
username: 'fake',
Expand Down Expand Up @@ -114,8 +116,32 @@ function createGaMock(endpoint) {
return aggregateMock(mocks)
}

function validateGsQuery(queryString) {
return (
queryString.site_token === GOSQUARED_ID &&
queryString.api_key === GOSQUARED_API_KEY
)
}

function createGsMock(options, times) {
times = times || 1

_.defaults(options, {
host: GOSQUARED_HOST,
method: 'POST',
filterQuery: validateGsQuery,
filterBody: function() { return true },
response: '1'
})

var mocks = _.range(times).map(function () {
return mock.create(options)
})

return aggregateMock(mocks)
}

describe('ResinEventLog', function () {
this.timeout(EXTRA_DEBUG ? 0 : 3000)

before(mock.init)
afterEach(mock.reset)
Expand Down Expand Up @@ -253,4 +279,128 @@ describe('ResinEventLog', function () {
})
})
})

describe('gosquared track', function () {
this.timeout(15000)
var endpoint = '/tracking/v1/event'
var eventLog

afterEach(function() {
return eventLog.end()
})

it('should make request to gosquared', function (done) {
var EXPECTED_EVENT = 'x'
var mockedRequest = createGsMock({
endpoint: endpoint,
method: 'POST',
filterBody: function (body, eventName) {
return (body.event.name === '[' + SYSTEM + '] ' + EXPECTED_EVENT)
}
})
eventLog = ResinEventLog({
gosquaredId: GOSQUARED_ID,
gosquaredApiKey: GOSQUARED_API_KEY,
prefix: SYSTEM,
debug: true,
afterCreate: function(err, type, jsonData, applicationId, deviceId) {
if (err) {
console.error('gosquared error:', err)
}
expect(!err).to.be.ok
expect(type).to.be.equal(EXPECTED_EVENT)

if (!IS_BROWSER) {
expect(mockedRequest.isDone()).to.be.ok
done()
} else {
// TODO: mock browser tests.
// see: https://github.com/resin-io-modules/resin-analytics/pull/14
done()
}
}
})

eventLog.start(FAKE_USER).then(function () {
eventLog.create(EXPECTED_EVENT)
})
})

it('should have semantic methods like device.rename that send requests to gosquared', function (done) {
var EXPECTED_EVENT = 'Device Rename'
var mockedRequest = createGsMock({
endpoint: endpoint,
filterBody: function (body, eventName) {
return (body.event.name === '[' + SYSTEM + '] ' + EXPECTED_EVENT)
}
})

eventLog = ResinEventLog({
gosquaredId: GOSQUARED_ID,
gosquaredApiKey: GOSQUARED_API_KEY,
prefix: SYSTEM,
debug: true,
afterCreate: function(err, type, jsonData, applicationId, deviceId) {
if (err) {
console.error('gosquared error:', err)
}
expect(!err).to.be.ok
expect(type).to.be.equal(EXPECTED_EVENT)

if (!IS_BROWSER) {
expect(mockedRequest.isDone()).to.be.ok
done()
} else {
// TODO: mock browser tests.
// see: https://github.com/resin-io-modules/resin-analytics/pull/14
done()
}
}
})

eventLog.start(FAKE_USER).then(function () {
eventLog.device.rename()
})
})

it('should attach person to event when user is given', function (done) {
var EXPECTED_EVENT = 'y'
var mockedRequest = createGsMock({
endpoint: endpoint,
filterBody: function (body, eventName) {
return (
body.event.name === '[' + SYSTEM + '] ' + EXPECTED_EVENT &&
body.person_id == FAKE_USER.id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT but can be strict comparison for consistency

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can't because user.id is a number and the body.person_id is a string. I can do explicit type conversion but implicit is better in this case no?

)
}
})

eventLog = ResinEventLog({
gosquaredId: GOSQUARED_ID,
gosquaredApiKey: GOSQUARED_API_KEY,
prefix: SYSTEM,
debug: true,
afterCreate: function(err, type, jsonData, applicationId, deviceId) {
if (err) {
console.error('gosquared error:', err)
}
expect(!err).to.be.ok
expect(type).to.be.equal(EXPECTED_EVENT)

if (!IS_BROWSER) {
expect(mockedRequest.isDone()).to.be.ok
done()
} else {
// TODO: mock browser tests.
// see: https://github.com/resin-io-modules/resin-analytics/pull/14
done()
}
}
})

eventLog.start(FAKE_USER).then(function () {
eventLog.create(EXPECTED_EVENT)
})
})
})
})
3 changes: 3 additions & 0 deletions packages/resin-universal-gosquared/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 0.1.0

* Add node and browser modules.
11 changes: 11 additions & 0 deletions packages/resin-universal-gosquared/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Resin Universal gosquared Wrapper

Loads the `gosquared` module in Node.js and (asynchronously) the client library from the CDN in the browser.

Browser usage needs Webpack, Browserify or other bundler that tolerates the `browser` field in `package.json`.

## Installing

```sh
$ npm install resin-universal-gosquared
```
20 changes: 20 additions & 0 deletions packages/resin-universal-gosquared/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "resin-universal-gosquared",
"version": "0.1.0",
"description": "A CommonJS wrapper for both Node.js and browser (async) version of goSquared Analytics library",
"main": "src/node.js",
"browser": "src/browser.js",
"scripts": {},
"keywords": [],
"author": "Craig Mulligan <craig@resin.io>",
"license": "Apache-2.0",
"dependencies": {
"bluebird": "^3.4.7",
"gosquared": "3.1.0"
},
"repository": {
"type": "git",
"url": "git@github.com:resin-io-modules/resin-analytics.git"
},
"homepage": "https://github.com/resin-io-modules/resin-analytics"
}
45 changes: 45 additions & 0 deletions packages/resin-universal-gosquared/src/browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require('./gs-loader')

var Promise = require('bluebird')
var TRACKER_NAME = 'resinAnalytics'

module.exports = function (gosquaredId, apiKey, debug) {
loggedIn = false
return {
login: function (userId) {
// automatically track pageviews in debug mode
window._gs(gosquaredId, TRACKER_NAME, debug)
window._gs(TRACKER_NAME + '.set', 'trackLocal', debug)

if (userId) {
window._gs(TRACKER_NAME + '.identify', {
id: userId
})
}
loggedIn = true
},
logout: function () {
if (!loggedIn) return Promise.reject(new Error("gosquared logout called before login"))

return Promise.fromCallback(function (callback) {
window._gs(function() {
window._gs(TRACKER_NAME + '.unidentify')
loggedIn = false
callback()
})
})
},
track: function (prefix, type, data) {
if (!loggedIn) return Promise.reject(new Error("Can't record gosquared events without a login first"))

return Promise.fromCallback(function (callback) {
if (type === 'Page Visit') {
window._gs(TRACKER_NAME + '.track', data.url || window.location.pathname)
} else {
window._gs(TRACKER_NAME + '.event', '[' + prefix + '] ' + type, data)
}
callback()
})
},
}
}
10 changes: 10 additions & 0 deletions packages/resin-universal-gosquared/src/gs-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
(function(i,s,o,g,r,a,m){i['goSquaredObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(
window,
document,
'script',
'https://d1l6p2sc9645hc.cloudfront.net/tracker.js',
'_gs'
);
38 changes: 38 additions & 0 deletions packages/resin-universal-gosquared/src/node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
var Promise = require('bluebird')
var GoSquared = require('gosquared')

module.exports = function(gosquaredId, apiKey, debug) {
var visitor = null
function createVisitor(userId) {
if (visitor) return visitor
var gosquared = new GoSquared({
api_key: apiKey,
site_token: gosquaredId
})
if (userId) {
visitor = gosquared.createPerson(userId);
} else {
visitor = gosquared
}
}
function destroyVisitor() {
visitor = null
}
return {
login: function(userId) {
createVisitor(userId)
},
logout: function() {
destroyVisitor()
},
track: function(prefix, type, data) {
// if called before `login` create an event without user attached.
createVisitor()
return Promise.fromCallback(function (callback) {
// node sdk doesn't support pageviews so no conditional here.
// https://www.gosquared.com/docs/api/tracking/pageview/node/
visitor.trackEvent('[' + prefix + '] ' + type, data, callback)
})
}
}
}