diff --git a/.gitignore b/.gitignore index 40feb52..4d481c3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ node_modules .idea *.komodo* help -image_creator \ No newline at end of file +image_creator +tmp diff --git a/Gruntfile.js b/Gruntfile.js index b5d3138..20d3c0a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -32,6 +32,10 @@ module.exports = function(grunt) { "src/end.js" ], dest: 'dist/<%= pkg.name %>.v<%= pkg.version %>.js' + }, + test: { + src: '<%= concat.dist.src %>', + dest: 'tmp/<%= pkg.name %>.js' } }, uglify: { @@ -49,17 +53,6 @@ module.exports = function(grunt) { } } }, - qunit: { - all: { - options: { - urls: [ - 'http://localhost:3001/test/methods/_getOrderedList.html', - 'http://localhost:3001/test/methods/_rollUp.html', - 'http://localhost:3001/test/methods/newSvg.html' - ] - } - } - }, jslint: { files: [ 'Gruntfile.js', @@ -89,6 +82,43 @@ module.exports = function(grunt) { "\n" + "\n" } + }, + karma: { + options: { + basepath: '', + frameworks: ['jasmine'], + files: [ + 'lib/d3.v3.min.js', + 'tmp/*.js', + 'test/**/*.spec.js', + 'test/*.spec.js' + ], + reporters: ['progress'], + port: 9876, + colors: true, + browsers: ['PhantomJS'] + }, + unit: { + singleRun: true + }, + continuous: { + background: true + } + }, + watch: { + src: { + files: [ + '<%= concat.test.src %>' + ], + tasks: ['concat:test', 'karma:continuous:run'] + }, + test: { + files: [ + 'test/**/*.spec.js', + 'test/*.spec.js' + ], + tasks: ['karma:continuous:run'] + } } }); @@ -98,6 +128,8 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-connect'); grunt.loadNpmTasks('grunt-contrib-qunit'); grunt.loadNpmTasks('grunt-jslint'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-karma'); // Propogate version into relevant files grunt.registerMultiTask('prop', 'Propagate Versions.', function() { @@ -130,6 +162,8 @@ module.exports = function(grunt) { }); // Default tasks - grunt.registerTask('default', ['concat', 'jslint', 'uglify', 'connect', 'qunit', 'prop']); + grunt.registerTask('default', ['concat', 'jslint', 'uglify', 'connect', 'prop']); + grunt.registerTask('test:unit', ['concat:test', 'karma:unit']); + grunt.registerTask('test', ['karma:continuous:start', 'watch']); }; \ No newline at end of file diff --git a/package.json b/package.json index 75000c8..72f337a 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,22 @@ "express": "3.x", "grunt": "~0.4.1", "grunt-jslint": "~0.2.6", - "grunt-contrib-nodeunit": "~0.1.2", "grunt-contrib-concat": "~0.2.0", "grunt-contrib-uglify": "~0.2.0", - "grunt-contrib-connect": "~0.3.0", - "grunt-contrib-qunit": "~0.2.2" + "grunt-contrib-connect": "~0.3.0" + }, + "devDependencies": { + "karma-script-launcher": "~0.1.0", + "karma-chrome-launcher": "~0.1.2", + "karma-firefox-launcher": "~0.1.3", + "karma-html2js-preprocessor": "~0.1.0", + "karma-jasmine": "~0.1.5", + "karma-coffee-preprocessor": "~0.1.2", + "requirejs": "~2.1.10", + "karma-requirejs": "~0.2.1", + "karma-phantomjs-launcher": "~0.1.1", + "karma": "~0.10.9", + "grunt-contrib-watch": "~0.5.3", + "grunt-karma": "~0.6.2" } } diff --git a/test/methods/_getOrderList.spec.js b/test/methods/_getOrderList.spec.js new file mode 100644 index 0000000..4d71d57 --- /dev/null +++ b/test/methods/_getOrderList.spec.js @@ -0,0 +1,77 @@ +describe("_getOrderedList", function() { + var data; + var getResults + + beforeEach(function() { + data = [ + { "Int": 1, "Float":234, "Text":"XFBGR", "Date":"12/5/99", "Group":"A"}, + { "Int": 2, "Float":54.35, "Text":"YTREB", "Date":"1/1/00", "Group":"A"}, + { "Int": 3, "Float":-453, "Text":"XGFDY", "Date":"2 February 2007", "Group":"B"}, + { "Int": 4, "Float":5436546, "Text":"XGFDE", "Date":"2000-03-01", "Group":"B"}, + { "Int": 5, "Float":4323, "Text":"YTREB", "Date":"10/10/2000", "Group":"C"}, + { "Int": 6, "Float":0, "Text":"GFDHN", "Date":"11/10/2000", "Group":"C"}, + { "Int": 7, "Float":-453, "Text":"TRET", "Date":"10/9/2000", "Group":"D"}, + { "Int": 1, "Float":5436546, "Text":"GFDGFDHG", "Date":"10/10/2000", "Group":"E"} + ]; + + getResults = function(data, field, levelDefinitions) { + var ordered = dimple._getOrderedList(data, field, levelDefinitions); + var retString = ""; + ordered.forEach(function (d, i) { + retString += (i > 0 ? ", " : "") + d; + }); + return retString; + } + }); + + it("Implicit Single Dimension Ordering", function() { + expect(getResults(data, "Int")).toEqual( "1, 2, 3, 4, 5, 6, 7"); + expect(getResults(data, "Float")).toEqual( "-453, 0, 54.35, 234, 4323, 5436546"); + expect(getResults(data, "Text")).toEqual( "GFDGFDHG, GFDHN, TRET, XFBGR, XGFDE, XGFDY, YTREB"); + expect(getResults(data, "Date")).toEqual( "12/5/99, 1/1/00, 2000-03-01, 10/9/2000, 10/10/2000, 11/10/2000, 2 February 2007"); + }); + + it("Explicit Single Dimension Ordering", function() { + expect(getResults(data, "Int", { ordering : "Int" })).toEqual( "1, 2, 3, 4, 5, 6, 7"); + expect(getResults(data, "Float", { ordering : "Float" })).toEqual( "-453, 0, 54.35, 234, 4323, 5436546"); + expect(getResults(data, "Text", { ordering : "Text" })).toEqual( "GFDGFDHG, GFDHN, TRET, XFBGR, XGFDE, XGFDY, YTREB"); + expect(getResults(data, "Date", { ordering : "Date" })).toEqual( "12/5/99, 1/1/00, 2000-03-01, 10/9/2000, 10/10/2000, 11/10/2000, 2 February 2007"); + }); + + it("Descending Single Dimension Ordering", function() { + expect(getResults(data, "Int", { ordering : "Int", desc : true })).toEqual( "7, 6, 5, 4, 3, 2, 1"); + expect(getResults(data, "Float", { ordering : "Float", desc : true })).toEqual( "5436546, 4323, 234, 54.35, 0, -453"); + expect(getResults(data, "Text", { ordering : "Text", desc : true })).toEqual( "YTREB, XGFDY, XGFDE, XFBGR, TRET, GFDHN, GFDGFDHG"); + expect(getResults(data, "Date", { ordering : "Date", desc : true })).toEqual( "2 February 2007, 11/10/2000, 10/10/2000, 10/9/2000, 2000-03-01, 1/1/00, 12/5/99"); + }); + + it("List Ordering", function() { + expect(getResults(data, "Int", { ordering : [3, 7, 4, 5, 2, 1, 6] })).toEqual( "3, 7, 4, 5, 2, 1, 6"); + expect(getResults(data, "Int", { ordering : [3, 7, 4, 5, 2, 1, 6], desc : true })).toEqual( "6, 1, 2, 5, 4, 7, 3"); + expect(getResults(data, "Int", { ordering : [3, 7, 4] })).toEqual( "3, 7, 4, 1, 2, 5, 6"); + expect(getResults(data, "Int", { ordering : [3, 7, 4], desc : true })).toEqual( "4, 7, 3, 1, 2, 5, 6"); + expect(getResults(data, "Int", { ordering : ["3", "7", "4", "5", "2", "1", "6"] })).toEqual( "3, 7, 4, 5, 2, 1, 6"); + expect(getResults(data, "Int", { ordering : ["3", "7", "4", "5", "2", "1", "6"], desc : true })).toEqual( "6, 1, 2, 5, 4, 7, 3"); + expect(getResults(data, "Int", { ordering : ["3", "7", "4"] })).toEqual( "3, 7, 4, 1, 2, 5, 6"); + expect(getResults(data, "Int", { ordering : ["3", "7", "4"], desc : true })).toEqual( "4, 7, 3, 1, 2, 5, 6"); + }); + + it("Functional Ordering", function() { + expect(getResults(data, "Text", { ordering : function (a, b) { return a.Text.length - b.Text.length; } })).toEqual( "TRET, GFDHN, XFBGR, XGFDE, XGFDY, YTREB, GFDGFDHG"); + expect(getResults(data, "Text", { ordering : function (a, b) { return a.Text.length - b.Text.length; }, desc : true })).toEqual( "GFDGFDHG, GFDHN, XFBGR, XGFDE, XGFDY, YTREB, TRET"); + }); + + it("Secondary Category Ordering", function() { + expect(getResults(data, "Int", { ordering : "Text" })).toEqual( "6, 7, 1, 4, 3, 2, 5"); + expect(getResults(data, "Int", { ordering : "Text", desc : true } )).toEqual( "2, 5, 3, 4, 1, 7, 6"); + expect(getResults(data, "Group", { ordering : "Float" } )).toEqual( "D, A, C, B, E"); + expect(getResults(data, "Group", { ordering : "Float", desc : true } )).toEqual( "E, B, C, A, D"); + }); + + it("Tertiary Category Ordering", function() { + expect(getResults(data, "Int", [{ ordering : "Group" }, { ordering : "Float" }])).toEqual( "2, 1, 3, 4, 6, 5, 7"); + expect(getResults(data, "Int", [{ ordering : "Group", desc : true}, { ordering : "Float" }])).toEqual( "7, 6, 5, 3, 4, 2, 1"); + expect(getResults(data, "Int", [{ ordering : "Group"}, { ordering : "Float", desc : true }])).toEqual( "1, 2, 4, 3, 5, 6, 7"); + expect(getResults(data, "Int", [{ ordering : "Group", desc : true}, { ordering : "Float", desc : true }])).toEqual( "7, 5, 6, 4, 3, 1, 2"); + }); +}); diff --git a/test/methods/_getOrderedList.html b/test/methods/_getOrderedList.html deleted file mode 100644 index 4712a62..0000000 --- a/test/methods/_getOrderedList.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - Test dimple.js - - - -
-
- - - - - - \ No newline at end of file diff --git a/test/methods/_rollUp.html b/test/methods/_rollUp.html deleted file mode 100644 index 3141a92..0000000 --- a/test/methods/_rollUp.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - - Test dimple.js - - - -
-
- - - - - - \ No newline at end of file diff --git a/test/methods/_rollUp.spec.js b/test/methods/_rollUp.spec.js new file mode 100644 index 0000000..36364c8 --- /dev/null +++ b/test/methods/_rollUp.spec.js @@ -0,0 +1,125 @@ +describe("_rollUp", function() { + var data; + var getResults + + beforeEach(function() { + data = [ + { "Field 1":"a", "Field 2":"x", "Field 3":"s", "Field 4":13 }, + { "Field 1":"a", "Field 2":"y", "Field 3":"s", "Field 4":14 }, + { "Field 1":"a", "Field 2":"z", "Field 3":"t", "Field 4":15 } + ]; + + // Flatten the ordered resultset for easy comparison + getResults = function(data, fields) { + var rolledUp = dimple._rollUp(data, fields, ["Field 1", "Field 2", "Field 3", "Field 4"]), + retString = ""; + rolledUp.forEach(function (d, i) { + var addField = function (field) { + retString += "'" + field + "':" + if (d[field] instanceof Array) { + retString += "['" + d[field].join("','") + "']" + } else { + retString += "'" + d[field] + "'"; + } + }; + retString += (i > 0 ? "," : "") + "{"; + addField("Field 1"); + retString += ","; + addField("Field 2"); + retString += ","; + addField("Field 3"); + retString += ","; + addField("Field 4"); + retString += "}" + }); + return retString; + } + + }); + it("Single Dimension Squash", function() { + expect(getResults(data, "Field 1")).toEqual( + "{'Field 1':'a','Field 2':['x','y','z'],'Field 3':['s','s','t'],'Field 4':['13','14','15']}" + ); + expect(getResults(data, "Field 2")).toEqual( + "{'Field 1':['a'],'Field 2':'x','Field 3':['s'],'Field 4':['13']}," + + "{'Field 1':['a'],'Field 2':'y','Field 3':['s'],'Field 4':['14']}," + + "{'Field 1':['a'],'Field 2':'z','Field 3':['t'],'Field 4':['15']}" + ); + expect(getResults(data, "Field 3")).toEqual( + "{'Field 1':['a','a'],'Field 2':['x','y'],'Field 3':'s','Field 4':['13','14']}," + + "{'Field 1':['a'],'Field 2':['z'],'Field 3':'t','Field 4':['15']}" + ); + expect(getResults(data, "Field 4" + )).toEqual( + "{'Field 1':['a'],'Field 2':['x'],'Field 3':['s'],'Field 4':'13'}," + + "{'Field 1':['a'],'Field 2':['y'],'Field 3':['s'],'Field 4':'14'}," + + "{'Field 1':['a'],'Field 2':['z'],'Field 3':['t'],'Field 4':'15'}" + ); + }); + + it("Double Dimension Squash", function() { + expect(getResults(data, ["Field 1", "Field 2"])).toEqual( + "{'Field 1':'a','Field 2':'x','Field 3':['s'],'Field 4':['13']}," + + "{'Field 1':'a','Field 2':'y','Field 3':['s'],'Field 4':['14']}," + + "{'Field 1':'a','Field 2':'z','Field 3':['t'],'Field 4':['15']}" + ); + expect(getResults(data, ["Field 1", "Field 3"])).toEqual( + "{'Field 1':'a','Field 2':['x','y'],'Field 3':'s','Field 4':['13','14']}," + + "{'Field 1':'a','Field 2':['z'],'Field 3':'t','Field 4':['15']}" + ); + expect(getResults(data, ["Field 1", "Field 4"])).toEqual( + "{'Field 1':'a','Field 2':['x'],'Field 3':['s'],'Field 4':'13'}," + + "{'Field 1':'a','Field 2':['y'],'Field 3':['s'],'Field 4':'14'}," + + "{'Field 1':'a','Field 2':['z'],'Field 3':['t'],'Field 4':'15'}" + ); + expect(getResults(data, ["Field 2", "Field 3"])).toEqual( + "{'Field 1':['a'],'Field 2':'x','Field 3':'s','Field 4':['13']}," + + "{'Field 1':['a'],'Field 2':'y','Field 3':'s','Field 4':['14']}," + + "{'Field 1':['a'],'Field 2':'z','Field 3':'t','Field 4':['15']}" + ); + expect(getResults(data, ["Field 2", "Field 4"])).toEqual( + "{'Field 1':['a'],'Field 2':'x','Field 3':['s'],'Field 4':'13'}," + + "{'Field 1':['a'],'Field 2':'y','Field 3':['s'],'Field 4':'14'}," + + "{'Field 1':['a'],'Field 2':'z','Field 3':['t'],'Field 4':'15'}" + ); + expect(getResults(data, ["Field 3", "Field 4"])).toEqual( + "{'Field 1':['a'],'Field 2':['x'],'Field 3':'s','Field 4':'13'}," + + "{'Field 1':['a'],'Field 2':['y'],'Field 3':'s','Field 4':'14'}," + + "{'Field 1':['a'],'Field 2':['z'],'Field 3':'t','Field 4':'15'}" + ); + }); + + it("Triple Dimension Squash", function() { + expect(getResults(data, ["Field 1", "Field 2", "Field 3"])).toEqual( + "{'Field 1':'a','Field 2':'x','Field 3':'s','Field 4':['13']}," + + "{'Field 1':'a','Field 2':'y','Field 3':'s','Field 4':['14']}," + + "{'Field 1':'a','Field 2':'z','Field 3':'t','Field 4':['15']}" + ); + expect(getResults(data, ["Field 1", "Field 2", "Field 4"])).toEqual( + "{'Field 1':'a','Field 2':'x','Field 3':['s'],'Field 4':'13'}," + + "{'Field 1':'a','Field 2':'y','Field 3':['s'],'Field 4':'14'}," + + "{'Field 1':'a','Field 2':'z','Field 3':['t'],'Field 4':'15'}" + ); + expect(getResults(data, ["Field 1", "Field 3", "Field 4"])).toEqual( + "{'Field 1':'a','Field 2':['x'],'Field 3':'s','Field 4':'13'}," + + "{'Field 1':'a','Field 2':['y'],'Field 3':'s','Field 4':'14'}," + + "{'Field 1':'a','Field 2':['z'],'Field 3':'t','Field 4':'15'}" + ); + expect(getResults(data, ["Field 2", "Field 3", "Field 4"])).toEqual( + "{'Field 1':['a'],'Field 2':'x','Field 3':'s','Field 4':'13'}," + + "{'Field 1':['a'],'Field 2':'y','Field 3':'s','Field 4':'14'}," + + "{'Field 1':['a'],'Field 2':'z','Field 3':'t','Field 4':'15'}" + ); + }); + + it("Full Dimension Squash", function() { + expect(getResults(data, ["Field 1", "Field 2", "Field 3", "Field 4"])).toEqual( + "{'Field 1':'a','Field 2':'x','Field 3':'s','Field 4':'13'}," + + "{'Field 1':'a','Field 2':'y','Field 3':'s','Field 4':'14'}," + + "{'Field 1':'a','Field 2':'z','Field 3':'t','Field 4':'15'}" + ); + }); +}); +/* + + */ diff --git a/test/methods/newSvg.html b/test/methods/newSvg.html deleted file mode 100644 index 65d99a3..0000000 --- a/test/methods/newSvg.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - Test dimple.js - - - -
-
-
- - - - - - \ No newline at end of file diff --git a/test/methods/newSvg.spec.js b/test/methods/newSvg.spec.js new file mode 100644 index 0000000..f0d08d7 --- /dev/null +++ b/test/methods/newSvg.spec.js @@ -0,0 +1,61 @@ +describe("newSvg", function() { + var getResults; + + beforeEach(function() { + getResults = function(selector, width, height) { + var retString = ""; + return retString; + }; + + d3.select("body").append("div").attr("id", "itDiv"); + }); + + it("should add by tag", function() { + var svg; + dimple.newSvg("body", 200, 100); + svg = document.getElementsByTagName("svg"); + expect(svg.length).toEqual(1); + expect(document.getElementsByTagName("svg")[0].parentNode.tagName).toEqual("BODY"); + expect(d3.select(svg[0]).attr("width")).toEqual("200"); + expect(d3.select(svg[0]).attr("height")).toEqual("100"); + d3.select(svg[0]).remove(); + expect(svg.length).toEqual(0); + }); + + it("should add by id", function() { + var svg; + dimple.newSvg("#itDiv", 200, 100); + svg = document.getElementsByTagName("svg"); + expect(svg.length).toEqual(1); + expect(document.getElementsByTagName("svg")[0].parentNode.tagName).toEqual("DIV"); + expect(d3.select(svg[0]).attr("width")).toEqual("200"); + expect(d3.select(svg[0]).attr("height")).toEqual("100"); + d3.select(svg[0]).remove(); + }); + + it("should add by default parameter", function() { + var svg; + dimple.newSvg(null, 200, 100); + svg = document.getElementsByTagName("svg"); + expect(svg.length).toEqual(1); + expect(document.getElementsByTagName("svg")[0].parentNode.tagName).toEqual("BODY"); + expect(d3.select(svg[0]).attr("width")).toEqual("200"); + expect(d3.select(svg[0]).attr("height")).toEqual("100"); + d3.select(svg[0]).remove(); + }); + + it("should check selection exceptions", function() { + var svg; + var random = function() { + dimple.newSvg("random string", 200, 100); + }; + expect(random).toThrow("The 'random string' selector did not match any elements. Please prefix with '#' to select by id or '.' to select by class"); + svg = document.getElementsByTagName("svg"); + expect(svg.length).toEqual(0); + }); +}); +/* + + + + */