Skip to content

Commit

Permalink
Merge pull request #14 from KrisSiegel/0.3.0-development
Browse files Browse the repository at this point in the history
0.3.0 development
  • Loading branch information
KrisSiegel committed Sep 14, 2014
2 parents 0e458ef + 5e394e5 commit 3240c7e
Show file tree
Hide file tree
Showing 35 changed files with 1,375 additions and 720 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ node_js:
- "0.11"
- "0.10"
before_install: npm install -g grunt-cli mocha-phantomjs phantomjs
before_script: grunt build
68 changes: 58 additions & 10 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ module.exports = (function (grunt) {
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-mocha-phantomjs');
grunt.loadNpmTasks('grunt-available-tasks');

// Get rid of the header output nonsense
grunt.log.header = function () {};

var paths = [
"src/main.js",
Expand All @@ -12,7 +16,10 @@ module.exports = (function (grunt) {
"src/routers/*.js",
"src/binders/*.js",
"src/api/*.js",
"src/module.exports.js"
"src/module.exports.js",
"!**/*.aspec.js",
"!**/*.cspec.js",
"!**/*.nspec.js"
];

grunt.initConfig({
Expand Down Expand Up @@ -42,16 +49,26 @@ module.exports = (function (grunt) {
reporter: "spec"
},
src: [
"./test/*.any.spec.js",
"./test/*.node.spec.js"
"**/*.aspec.js",
"**/*.nspec.js"
]
}
},
mocha_phantomjs: {
all: ["specRunner.html"]
},
availabletasks: {
tasks: {
options: {
filter: "include",
tasks: ["build", "test"]
}
}
}
});

grunt.registerTask("default", ["availabletasks"]);

grunt.registerTask("verisionify", "Verisionifying msngr.js", function () {
var fs = require("fs");
var pkg = grunt.file.readJSON('package.json');
Expand All @@ -66,7 +83,7 @@ module.exports = (function (grunt) {
fs.writeFileSync("src/main.js", ified, { encoding: "utf8" });
});

grunt.registerTask("stress", "Stress test", function () {
grunt.registerTask("stresser", "Stress testing", function () {
var fs = require("fs");
var path = require("path");
var items = fs.readdirSync("./stress");
Expand All @@ -85,20 +102,48 @@ module.exports = (function (grunt) {
done();
});

grunt.registerTask("header:building", function () {
grunt.log.subhead("Building msngr.js");
});

grunt.registerTask("header:stressing", function () {
grunt.log.subhead("Running stress tests with node.js");
});

grunt.registerTask("header:nodeTesting", function () {
grunt.log.subhead("Unit testing with node.js");
});

grunt.registerTask("header:clientTesting", function () {
grunt.log.subhead("Client-side unit testing with phantom.js");
});

grunt.registerTask("setRunner", "Set the client side spec runner", function () {
var makeScript = function (path) {
return "<script type='text/javascript' src='" + path + "'></script>";
};
var fs = require("fs");
var path = require("path");
var tests = fs.readdirSync("./test");
var scriptHtml = "";
var tests = [];
var dirs = fs.readdirSync("./src/");

for (var i = 0; i < dirs.length; ++i) {
if (fs.statSync("./src/" + dirs[i]).isDirectory()) {
var files = fs.readdirSync("./src/" + dirs[i]);
for (var j = 0; j < files.length; ++j) {
tests.push(path.join("./", "./src/", dirs[i], files[j]));
}
} else {
tests.push(path.join("./", "./src/", dirs[i]));
}
}

var scriptHtml = "";
if (tests !== undefined && tests.length > 0) {
var file = tests.shift();
while (tests.length > 0) {
if (file.indexOf(".client.spec.js") !== -1 || file.indexOf(".any.spec.js") !== -1) {
scriptHtml += makeScript(("test/" + file)) + "\n";
if (file.indexOf(".cspec.js") !== -1 || file.indexOf(".aspec.js") !== -1) {
scriptHtml += makeScript(file) + "\n";
}
file = tests.shift();
}
Expand All @@ -116,6 +161,9 @@ module.exports = (function (grunt) {
fs.writeFileSync("./specRunner.html", newHtml, { encoding: "utf8" });
});

grunt.registerTask("build", ["clean", "verisionify", "concat", "uglify:minify", "setRunner"]);
grunt.registerTask("test", ["mochaTest", "mocha_phantomjs"]);
grunt.registerTask("build", "Cleans, sets the version and builds msngr.js", ["header:building", "clean", "verisionify", "concat", "uglify:minify", "setRunner"]);

grunt.registerTask("test", "Runs mocha unit tests through node.js and phantom.js", ["build", "header:nodeTesting", "mochaTest", "header:clientTesting", "mocha_phantomjs"]);

//grunt.registerTask("stress", "Stress testing msngr.js", ["build", "header:stressing", "stresser"]);
});
53 changes: 12 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,49 +74,21 @@ Building requires that the development dependencies from npm to be installed (ru

Simply run ```grunt build``` to build msngr.js.

###Testing msngr.js
Testing is conducted directly using node and phantomjs for client related tests. First let's explain the way tests are named; in the ```./test/``` directory you will notice there are 2 types of unit test names. ```*.any.spec.js``` and ```*.client.spec.js```. The unit tests with ```any``` in the name indicates it can be run via node.js or within a browser context. The unit tests with ```client``` in the name indicates it can only be run within a browser context.

Simply running ```npm test``` will run through all of the tests that are specified as ```any``` with mocha and node.js then proceed to use phantomjs to run the ```client``` and ```any``` unit tests within a browser context. The building step updates the ```specRunner.html``` file to have all of the correct spec files included and run upon loading the page.

###Stress testing msngr.js
Stress testing is important especially when the library is in charge of all local and possibly even remote communications between components. Stress testing is somewhat similar to how unit testing works; stress tests exist in the ```./stress/``` directory and are named using the ```*.stress.js``` convention.

Stress tests are run using [benchmark.js](http://benchmarkjs.com/) in a custom context. Unlike mocha testing, stress tests are simply scripts that run via node. There is a familiar interface to running async mocha unit tests in that some data is passed into the stress test and at the end ```done()``` should be called. The best example is looking at how the indexer stress tests were created which is in the ```./stress/msngr.utils.indexer.stress.js``` file.

A basic example of a stress test is as follows [which would simply do into a ```*.stress.js``` file in the ```./stress/``` directory]:

```
module.exports = (function (done) {
var benchmark = require("benchmark");
var stress = (function (description, msngr, uniqueKey) {
var suite = new benchmark.Suite;
suite.add("test", function () {
var answer = 5 * 5;
});
Note: running 'grunt' by itself will produce an available set of commands and their descriptions.

suite.on("cycle", function (event) {
console.log(String(event.target));
});
suite.run({ "async": false });
done();
});
stress("A stress example", require("../msngr.js"), Math.floor(Math.random() * 1000));
});
###Testing msngr.js
Testing is conducted directly using node and phantomjs for client related tests. Unlike many JavaScript projects I decided to use the GO model of testing meaning each unit test sits directly next to the file it is testing (so there is no test or spec directory). There are also 3 different naming conventions for spec files.

```
- *.aspec.js - A spec file that can be run directly within node.js or a web browser.
- *.cspec.js - A spec file that can ONLY be run inside of a web browser.
- *.nspec.js - A spec file that can ONLY be run inside of node.js.

To run the stress tests simply run ```grunt stress```.
The reasoning for the different conventions is simple: msngr.js is meant to work in as many environments as possible however some features (such a DOM binding) are only available in very specific environments all of which need automated unit testing.

###Routers versus Binders
There are two ways to extend how msngr handles sending, receiving and binding. Routers are used for standard messages across the system whereas binders are used for binding directly to a component (typically part of the interface). Routers are more general and can be used in all aspects but binders provide an easy way to hook HTML elements and their events directly into msngr's messaging.
There are two ways to extend how msngr handles sending, receiving and binding. Routers are used for standard messages across the system whereas binders are used for binding directly to a component (typically part of the user interface). Routers are more general and can be used in all environments but binders provide an easy way to hook HTML elements and their events directly into msngr's messaging.

A router must be a JavaScript object and must implement the following interface:
A router must be a JavaScript object and must implement the following interface (a domain can be 'local' or 'localAndRemote' depending on if it's working within the local environment or doing both local and remote):
```
{
emit: function (message) { },
Expand All @@ -126,7 +98,7 @@ A router must be a JavaScript object and must implement the following interface:
}
```

A binder must be a JavaScript object and must implement the following interface:
A binder must be a JavaScript object and must implement the following interface (domain should always be 'local' for binders):
```
{
bind: function (element, event, message) { },
Expand Down Expand Up @@ -188,9 +160,6 @@ Removes a specific item from the index by its unique key as specified when initi
###msngr.utils.arrayContains(arr, values);
Checks whether the ```arr``` array contains the values in the ```values``` array.

###msngr.utils.verifyInterface(object, interface);
Verifies whether a specific ```object``` implements an interface. Essentially checks that the methods and properties of the ```interface``` are contained within the ```object```.

###msngr.utils.getType(obj);
Returns the type's name in the full JavaScript format of ```[object Object]```.

Expand Down Expand Up @@ -238,3 +207,5 @@ Returns whether the message contains wildcard characters or not.

###msngr.utils.getPropertiesWithWildcards(message);
Returns all properties associated with the ```message``` object where they contain wildcard characters.

Copyright (c) 2014 Kris Siegel
Loading

0 comments on commit 3240c7e

Please sign in to comment.