This commit is contained in:
David Tai
2015-07-24 15:13:38 -07:00
parent 39e0e3a208
commit 30b8692832
5 changed files with 233 additions and 172 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ Iexec = require('shortcake').exec
option '-b', '--browser [browserName]', 'browser to test with'
task 'build', 'Build module and bundled crowdcontrol.js', ->
task 'build', 'Build module and bundled espy.js', ->
exec 'node_modules/.bin/requisite src/index.coffee -o espy.js'
task 'build-min', 'Build minified espy.min.js', ->
+99 -76
View File
File diff suppressed because one or more lines are too long
+85 -53
View File
@@ -6,8 +6,8 @@ if window?
window.console.log = ()->
store = require 'store'
cookie = require 'cookies-js'
useragent = require 'ua-parser-js'
cookies = require 'cookies-js'
userAgent = require 'ua-parser-js'
qs = require 'query-string'
uuid = require 'node-uuid'
@@ -15,7 +15,7 @@ if window?
userIdCookie = '__cs-uid'
sessionIdCookie = '__cs-sid'
class Record
newRecord =
pageId: ''
lastPageId: ''
pageViewId: ''
@@ -27,44 +27,55 @@ if window?
getTimestamp = ()->
return (new Date).getMilliseconds()
cachedDomain = ''
getDomain = ()->
if !cachedDomain
cachedDomain = if document.domain != 'localhost' then '.' + document.domain else ''
return cachedDomain
# Local Storage Record Management
useRecord = (fn)->
record = store.get(getSessionId()) ? new Record
fn record
getRecord = ()->
store.get(getSessionId()) ? newRecord
saveRecord = (record)->
store.set getSessionId(), record
# User/Session Id Management (on cookies)
cachedUserId
cachedUserId = ''
getUserId = ()->
if cachedUserId?
if cachedUserId
return cachedUserId
userId = cookie.get userIdCookie
if !userId?
userId = cookies.get userIdCookie
if !userId
userId = uuid.v4()
cookies.set userIdCookie, userId,
domain: '.' + document.domain
domain: getDomain()
cachedUserId = userId
return userId
# cache the session id so we can resume if user leaves and returns to browser
cachedSessionId
cachedSessionId = ''
getSessionId = ()->
if cachedSessionId?
if cachedSessionId
return cachedSessionId
sessionId = cookie.get sessionIdCookie
if !sessionId?
sessionId = cookies.get sessionIdCookie
if !sessionId
sessionId = getUserId() + '_' + getTimestamp()
cookies.set sessionIdCookie, sessionId,
domain: '.' + document.domain
domain: getDomain()
expires: 1800
useRecord (record)->
cachedSessionId = sessionId
record = getRecord()
record.count = 0
saveRecord(record)
cachedSessionId = sessionId
return sessionId
refreshSession = ()->
@@ -75,8 +86,8 @@ if window?
expires: 1800
# Page Transitions (in localstorage)
cachedPageId
cachedPageViewId
cachedPageId = ''
cachedPageViewId = ''
getPageId = ()->
return cachedPageId
@@ -84,19 +95,22 @@ if window?
return cachedPageViewId
getQueryParams = ()->
return qs.parse window.location.search
return qs.parse(window.location.search || window.location.hash.split('?')[1])
updatePage = ()->
record = getRecord()
newPageId = window.location.pathname + window.location.hash
if newPageId != cachedPageId
if newPageId != record.pageId
cachedPageId = newPageId
cachedPageViewId = cachedPageId + '_' + getTimestamp()
useRecord (record)->
record.lastPageId = record.pageId
record.lastPageViewId = record.pageViewId
record.pageId = cachedPageId
record.pageViewId = cachedPageViewId
record = getRecord()
record.lastPageId = record.pageId
record.lastPageViewId = record.pageViewId
record.pageId = cachedPageId
record.pageViewId = cachedPageViewId
saveRecord record
Espy 'PageView',
lastPageId: record.lastPageId
@@ -108,59 +122,77 @@ if window?
Espy = (name, data)->
ua = window.navigator.userAgent
useRecord (record)->
record.queue.push
userId: getUserId()
sessionId: getSessionId()
record = getRecord()
record.queue.push
userId: getUserId()
sessionId: getSessionId()
pageId: record.pageId
pageViewId: record.pageViewId
pageId: record.pageId
pageViewId: record.pageViewId
uaString: ua
ua: userAgent ua
timestamp: new Date()
uaString: ua
ua: userAgent ua
timestamp: new Date()
event: name
data: data
count: record.count
event: name
data: data
count: record.count
record.count++
record.count++
saveRecord record
refreshSession()
# Flush Queue
flush = ()->
useRecord (record)->
record = getRecord()
if record.queue.length > 0
Espy.onflush record
retry = 0
data = record.queue.slice(0)
data = JSON.stringify record.queue
xhr = new XMLHttpRequest
xhr.onreadystatechange = ()->
if xhr.readyState == 4
if xhr.status != 200
if xhr.status != 204
retry++
if retry == 3
console.log('Espy: failed to send', data)
console.log 'Espy: failed to send', JSON.parse data
else
console.log('Espy: retrying send x' + retry)
xhr.open 'POST', Espy.url
xhr.send data
console.log 'Espy: retrying send x' + retry
xhr.open 'POST', Espy.url
xhr.send(data)
xhr.setRequestHeader 'Content-Type', 'application/json'
xhr.send data
record.queue.length = 0
saveRecord record
# Bind Page Transitions
window.addEspyListener 'hashchange', updatePage
window.addEspyListener 'popstate', updatePage
window.addEventListener 'hashchange', updatePage
window.addEventListener 'popstate', updatePage
window.beforeUnload 'beforeunload', ()->
Espy 'PageLeave'
window.addEventListener 'beforeunload', ()->
Espy 'PageChange'
flush()
updatePage()
setInterval ()->
flush()
, 2000
next = ()->
setTimeout ()->
flush()
next()
Espy.flushRate || 200
# prevent blocking page load
setTimeout ()->
next()
, 1
window.Espy = Espy
Espy.url = 'https://analytics.crowdstart.com/'
Espy.onflush = ()->
Espy.flushRate = 200
module.exports = Espy
+39 -41
View File
@@ -3,55 +3,53 @@ should = require('chai').should()
{getBrowser} = require './util'
describe "Cuckoo (#{process.env.BROWSER})", ->
describe "Espy (#{process.env.BROWSER})", ->
@timeout 90000
browser = getBrowser()
testPage = "http://localhost:#{process.env.PORT ? 3333}/test.html"
describe 'Cuckoo can capture uncaptured events', ->
it 'should capture a click on an element without a handler', (done) ->
describe 'Espy should queue events', ->
it 'should capture page view', (done) ->
browser
.url testPage
.waitForExist '#somelink', 5000
.click '#somelink'
.getText '#result', (err, res) ->
res.should.equal 'clicked: somelink'
.waitForExist '#flush'
.getText '#flush', (err, res) ->
record = JSON.parse(res)
queue = record.queue
queue.length.should.equal 1
event = queue[0]
event.userId.should.exist
event.sessionId.should.exist
event.pageId.should.equal '/test.html'
event.pageViewId.substring(0, 11).should.equal '/test.html_'
event.uaString.should.exist
event.ua.should.exist
event.timestamp.should.exist
event.event.should.equal 'PageView'
event.data.should.exist
event.data.queryParams.should.exist
event.data.lastPageId.should.equal ''
event.data.lastPageViewId.should.equal ''
event.data.referrerUrl.should.equal ''
event.data.url.should.equal 'http://localhost:3333/test.html'
.call done
it 'should capture window events like hashchange', (done) ->
it 'should capture query params', (done) ->
browser
.url testPage
.waitForExist '#linktobookmark', 5000
.click '#linktobookmark'
.getText '#result', (err, res) ->
res.should.equal 'hashchangeed: undefined'
.url testPage + '#test?q=1'
.waitForExist '#flush'
.getText '#flush', (err, res) ->
record = JSON.parse(res)
queue = record.queue
queue.length.should.equal 1
event = queue[0]
event.event.should.equal 'PageView'
event.data.url.should.equal 'http://localhost:3333/test.html#test?q=1'
event.data.queryParams.q.should.equal '1'
.call done
it 'should filter events', (done) ->
browser
.url testPage
.setValue '#changeinput', 'somethingelse'
.getValue '#changeinput', (err, res) ->
res.should.equal('somethingelse')
.getText '#rejected', (err, res) ->
res.should.equal 'changeed: changeinput'
.call done
describe 'Cuckoo can capture captured events', ->
it 'should capture propagated events', (done) ->
browser
.url testPage
.waitForExist '#clickablediv', 5000
.click '#clickablediv'
.getText '#result', (err, res) ->
res.should.equal 'clicked: clickablediv'
.call done
it 'should capture unpropagated events', (done) ->
browser
.url testPage
.waitForExist '#dontstopmenow', 5000
.click '#dontstopmenow'
.getText '#result', (err, res) ->
res.should.equal 'clicked: dontstopmenow'
.call done
#it 'should capture page leave', (done) ->
+9 -1
View File
@@ -1,5 +1,5 @@
<!doctype html>
<html class="no-js" lang="">
<html class="no-js" lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
@@ -12,5 +12,13 @@
<script src="espy.js"></script>
</head>
<body>
<div id="flush"></div>
<script>
Espy.url = "http://localhost:8080/analytics/?token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJiaXQiOjIwLCJqdGkiOiJiZ1hRYkpyWGtDQSIsInN1YiI6IkdQVHE2ZTM2c1IifQ.7SllMXMCydU5kTivZlMDBHfkUQm5l742l7Y0x7Pci03x7iHKL_ggrEeiGDkfYUoThv7p1vXjqVE1ps3JY0exjw"
Espy.flushRate = 10000
Espy.onflush = function(record) {
document.getElementById('flush').innerHTML = JSON.stringify(record)
}
</script>
</body>
</html>