Comparing version 0.1.1 to 0.2.0
{ | ||
"base": "http://www.businessinsider.com", | ||
"base": "http://businessinsider.com", | ||
"storage": "mongodb://localhost/test", | ||
"queries": { | ||
"page.hour": { | ||
"collection": "analytics.page.hour", | ||
"query": {"name": "<%= relative %>", "date": "<%= hour %>"}, | ||
"field": "n", | ||
"sort": {"date": -1} | ||
} | ||
}, | ||
"sets": { | ||
"google": [ | ||
"http://www.google-analytics.com/__utm.gif" | ||
], | ||
"internal": [ | ||
"track.gif" | ||
] | ||
@@ -10,5 +22,22 @@ }, | ||
{ | ||
"uri": "/the-7-awesome-types-of-slideshows-2010-11", | ||
"actions": [ | ||
{"click": "a.sl-start"} | ||
], | ||
"sets": { | ||
"google": 2, | ||
"internal": 2 | ||
}, | ||
"queries": { | ||
"page.hour": 1 | ||
} | ||
}, | ||
{ | ||
"uri": "/tausche-vs-kopecki-2013-8", | ||
"sets": { | ||
"google": 1 | ||
"google": 1, | ||
"internal": 1 | ||
}, | ||
"queries": { | ||
"page.hour": 1 | ||
} | ||
@@ -15,0 +44,0 @@ } |
var Haunted = require('../lib/haunted'), | ||
util = require('util') | ||
util = require('util'), | ||
should = require('should') | ||
@@ -4,0 +5,0 @@ var definition = require('./definition.json'); |
@@ -16,3 +16,3 @@ var Spooky = require('spooky'), | ||
this.MongoHouse = require('./datastores/mongo'); | ||
_.each(definition.pages, function(page) { | ||
@@ -40,3 +40,3 @@ self.buildPage(page, describer, tester); | ||
} | ||
_.each(self.pages, function(page) { | ||
@@ -43,0 +43,0 @@ page.run(); |
@@ -36,9 +36,23 @@ var Spooky = require('spooky'), | ||
relative: self.relative, | ||
hour: '<%= hour %>' | ||
time: '<%= time %>', | ||
hour: '<%= hour %>', | ||
day: '<%= day %>', | ||
month: '<%= day %>', | ||
fiveMin: '<%= fiveMin %>' | ||
} | ||
var now = new Date; | ||
var nowHour = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours()); | ||
var nowDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()); | ||
var nowMonth = new Date(now.getFullYear(), now.getMonth(), now.getDate()); | ||
var roundFive = 1000 * 60 * 5; // round to five minutes | ||
var nowFive = new Date(Math.floor(now.getTime() / roundFive) * roundFive); | ||
var objReplacements = { | ||
'<%= time %>': now, | ||
'<%= hour %>': nowHour | ||
'<%= hour %>': nowHour, | ||
'<%= day %>': nowDay, | ||
'<%= month %>': nowMonth, | ||
'<%= fiveMin %>': nowFive | ||
} | ||
@@ -91,3 +105,14 @@ | ||
} | ||
// build the tests list | ||
_.each(self.expectations, function(expectation) { | ||
expectation.test = { | ||
'page': self, | ||
'name': expectation.uri, | ||
'expected': expectation.expected, | ||
'occurred': expectation.occurred | ||
} | ||
self.tests[expectation.uri] = expectation.test; | ||
}); | ||
// time out on loading the page | ||
@@ -99,21 +124,9 @@ if (self.definition.timeout != undefined) { | ||
} | ||
self.describer(self, function(done) { | ||
self.describer(self, function(done) { | ||
// disable timeouts. if possible | ||
if (typeof this.timeout == 'function') { | ||
this.timeout(0); | ||
} | ||
// build the tests list | ||
_.each(self.expectations, function(expectation) { | ||
expectation.test = { | ||
'page': self, | ||
'name': expectation.uri, | ||
'expected': expectation.expected, | ||
'occurred': expectation.occurred | ||
} | ||
self.tests[expectation.uri] = expectation.test; | ||
}); | ||
} | ||
// if we have storage, we need to start it | ||
@@ -175,3 +188,2 @@ if (self.haunted.storage != undefined) { | ||
expect.occurred++; | ||
console.log(resource.url, expect); | ||
@@ -186,3 +198,3 @@ } | ||
var self = this; | ||
_.each(this.tests, function(test) { | ||
@@ -243,3 +255,3 @@ self.tester(test); | ||
self.spooky.on('console', function(line) { | ||
console.log(line); | ||
// console.log(line); | ||
}); | ||
@@ -249,3 +261,3 @@ | ||
if (log.space === 'remote') { | ||
console.log(log.message.replace(/ \- .*/, '')); | ||
// console.log(log.message.replace(/ \- .*/, '')); | ||
} | ||
@@ -252,0 +264,0 @@ }); |
{ | ||
"name": "haunted", | ||
"description": "A node module for validating site analytics", | ||
"version": "0.1.1", | ||
"version": "0.2.0", | ||
"keywords": [ | ||
@@ -6,0 +6,0 @@ "node", |
156
README.md
@@ -28,7 +28,43 @@ # Haunted | ||
Examples | ||
-------- | ||
Two examples are included, a simple one using console.log and an example using the [Mocha test framework](http://visionmedia.github.io/mocha/). To use the Mocha example, you must install the mocha npm module. | ||
### definition | ||
The definition argument should be an object configuring your analytics definition, see [configuration](#configuration). | ||
### describer(page, setup, suite) | ||
The describer argument should be a function which, when called, creates a test suite for a particular page. It is passed 3 arguments: | ||
* ```page```: an object representing the page currently being tested | ||
* ```setup(done)```: a function which, when called, sets up the test suite (by loading the page in a headless browser); it's argument is a function to be called when the setup is done | ||
* ```suite(this)```: a function which, when called, executes the test suite; it's argument should be the test context. | ||
For example, this is a simple describer function: | ||
``` javascript | ||
function(page, setup, suite) { | ||
setup(function() { | ||
suite(this); | ||
}); | ||
} | ||
``` | ||
### tester(expectation) | ||
The tester argument should be a function which, when called, actually tests an expectation. It's one argument is an object with three properties: | ||
* ```expectation.name```: the name of the expectation (ex. the URL of a resource which was expected) | ||
* ```expectation.occurred```: the number of instances which actually occurred | ||
* ```expectation.expected```: the number of instances which was expected | ||
For example, here is a simple tester which outputs to the console: | ||
``` javascript | ||
function(expectation) { | ||
if (expectation.occurred != expectation.expected) { | ||
console.log(util.format('%s expected %d, received %d on %s', expectation.name, expectation.expected, expectation.occurred, expectation.page.url)); | ||
} else { | ||
console.log(util.format('passed %s on %s', expectation.name, expectation.page.url)); | ||
} | ||
} | ||
``` | ||
## Examples | ||
Two examples are included, a simple one using console.log and an example using the [Mocha test framework](http://visionmedia.github.io/mocha/). To run the simple example, just execute this command: ```node examples/simple.js``` | ||
To use the Mocha example, you must install the mocha npm module. | ||
``` | ||
npm install -g mocha | ||
@@ -38,2 +74,114 @@ npm install should | ||
To run the Mocha example, just use this command: ```mocha --reporter spec --ui bdd -r should example/mocha.js``` | ||
To run the Mocha example, just use this command: ```mocha --reporter spec --ui bdd -r should example/mocha.js``` | ||
## Configuration | ||
The definition used for validating your site is stored in a simple JavaScript object, which is passed as the first parameter for a new haunted object. This object can be easily loaded from a JSON file, and contains a number of properties. A sample definition is included in the examples directory. | ||
``` javascript | ||
var definition = require('./definition.json'); | ||
``` | ||
### base (required) | ||
The base URL of your site. Ex. ```"http://google.com"``` | ||
### authentication (optional) | ||
If your site is behind basic HTTP authentication, you can pass a username and password in your definition file to enable authentication. | ||
``` javascript | ||
"authentication": { | ||
"username": "YOURUSERNAMEHERE", | ||
"password": "YOURPASSWORDHERE" | ||
} | ||
``` | ||
### storage (optional) | ||
This contains configuration information which is passed to the [datastore](#datastores). | ||
### queries (optional) | ||
An object of all queries which your pages would like to check. The key is the query name and the value is an object containing query properties which are passed along to the datastore. | ||
``` javascript | ||
"queries": { | ||
"page.hour": { | ||
"collection": "analytics.page.hour", | ||
"query": {"name": "<%= relative %>", "date": "<%= hour %>"}, | ||
"field": "n", | ||
"sort": {"date": -1} | ||
} | ||
} | ||
``` | ||
#### collection (required) | ||
The collection this query should reference. | ||
#### query (required) | ||
The actual query parameters to be passed. This format will often depend on the driver. Note that in field names certain properties will be replaced: | ||
* ```<%= relative %>``` becomes the relative URL of the current page. | ||
* ```<%= time %>``` becomes the current time, as a JavaScript date | ||
* ```<%= hour %>``` becomes the current hour, rounded down, as a JavaScript date | ||
* ```<%= day %>``` becomes the current day, rounded down, as a JavaScript date | ||
* ```<%= month %>``` becomes the current month, rounded down, as a JavaScript date | ||
* ```<%= fiveMin %>``` becomes the current five minute period, rounded down, as a JavaScript date | ||
#### field (required) | ||
The name of the field, in the fetched document, where the changing value can be found. | ||
#### sort (optional) | ||
An object parameter to pass for sorting the collection query, useful in the MongoDB datastore. | ||
### sets (required) | ||
In Haunted, a set is an array of URLs which are expected. You can define multiple sets (each of which has multiple URLs), and each page can reference multiple sets. Note that URLs will be naively partially matched, such that if a requested resource contains one of these URLs as a substring, it will be considered a match. For example: | ||
``` javascript | ||
"sets": { | ||
"google": [ | ||
"http://www.google-analytics.com/__utm.gif" | ||
], | ||
"internal": [ | ||
"track.gif" | ||
] | ||
} | ||
``` | ||
### pages (required) | ||
The pages property contains an array of pages to be checked, each of which has a number of properties. Ex. | ||
``` javascript | ||
"pages": [ | ||
{ | ||
"uri": "/the-7-awesome-types-of-slideshows-2010-11", | ||
"sets": { | ||
"google": 1, | ||
"internal": 2 | ||
}, | ||
"actions": [ | ||
{"click": "a.sl-start"} | ||
], | ||
"queries": { | ||
"page.hour": 1 | ||
} | ||
} | ||
] | ||
``` | ||
#### uri (required) | ||
The location of the page, relative to [the base url](#base-required). Ex. ```"/blog"``` | ||
#### sets (required) | ||
An object containing the [sets](#sets-required), as defined elsewhere in your definition, which this page should load. The key is the set and the value is the number of times it should be referenced. The above example will expect each URL in ```google``` set to be called once and each URL in the ```internal``` set twice: | ||
#### actions (optional) | ||
An array containing any actions to take on the page. Each action is represented as an object with the key being the event/action and the value being the target. Currently only the ```click``` ation is supported. | ||
#### queries (optional) | ||
An object containing the [queries](#queries-optional), as defined elsewhere in your definition, which this page should check. The key is the query and the value is the amount we expect that query to be updated by. | ||
## Datastores | ||
Haunted supports tracking that values are properly incremented in your datastore for analytics calls. To use a datastore, you must define [storage](#storage-optional) and [queries](#queries-optional) in your configuration, and activate the datastore. Currently only a MongoDB datastore driver is included with Haunted, which can be activated thusly: | ||
``` javascript | ||
haunted = new Haunted(definition, describer, tester); | ||
// use the mongo datastore | ||
haunted.setStorage(haunted.MongoHouse); | ||
``` | ||
As the datastore is a simple class, you can easily write drivers for other datastores by following the conventions of the mongo datastore. If you do so, please submit a pull request so we can include it! |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
23776
11
472
185