diff --git a/.gitignore b/.gitignore index 54ac29a..5d5649f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .sass-cache/ node_modules/ +coverage/ .project _site/ diff --git a/Gruntfile.js b/Gruntfile.js index 855728c..ff7381c 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -3,6 +3,11 @@ module.exports = function(grunt) { // Project configuration. grunt.initConfig({ pkg : grunt.file.readJSON('package.json'), + karma: { + unit: { + configFile: 'karma.conf.js' + } + }, uglify : { options : { banner : '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' @@ -61,7 +66,9 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-requirejs'); + grunt.loadNpmTasks('grunt-karma'); // Default task(s). grunt.registerTask('default', ['jshint', 'requirejs', 'uglify']); + grunt.registerTask('test', ['karma']); -}; \ No newline at end of file +}; diff --git a/README.md b/README.md index 46de94a..f95bfbe 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,21 @@ Quagga.decodeSingle({ }); ``` +## Tests + +Unit Tests can be run with [Karma][karmaUrl] and written using [Mocha][mochaUrl], [Chai][chaiUrl] and [SinonJS][sinonUrl]. Coverage reports are automatically generated in the coverage/ folder. + +```console +> npm install +> grunt test +``` + + [zxing_github]: https://github.com/zxing/zxing [teaser_left]: https://github.com/serratus/quaggaJS/blob/master/doc/img/mobile-located.png [teaser_right]: https://github.com/serratus/quaggaJS/blob/master/doc/img/mobile-detected.png -[caniuse_getusermedia]: http://caniuse.com/#feat=stream \ No newline at end of file +[caniuse_getusermedia]: http://caniuse.com/#feat=stream +[sinonUrl]: http://sinonjs.org/ +[chaiUrl]: http://chaijs.com/ +[mochaUrl]: https://github.com/mochajs/mocha +[karmaUrl]: http://karma-runner.github.io/ diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..012a59a --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,29 @@ +module.exports = function(config) { + config.set({ + basePath: '', + frameworks: ['mocha', 'requirejs', 'chai', 'sinon', 'sinon-chai'], + files: [ + 'test-main.js', + 'src/vendor/glMatrix.js', + 'src/typedefs.js', + {pattern: 'src/*.js', included: false}, + {pattern: 'spec/**/*.js', included: false}, + ], + exclude: [ + ], + preprocessors: { + 'src/*.js': ['coverage'] + }, + reporters: ['progress', 'coverage'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['PhantomJS'], + singleRun: false, + coverageReporter: { + type : 'html', + dir : 'coverage/' + } + }); +}; diff --git a/package.json b/package.json index 20f2c20..bf685dc 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,23 @@ "grunt-contrib-jshint": "~0.10.0", "grunt-contrib-nodeunit": "~0.4.1", "grunt-contrib-uglify": "~0.5.0", - "grunt-requirejs": "^0.4.2" + "grunt-karma": "^0.9.0", + "grunt-requirejs": "^0.4.2", + "karma": "latest", + "karma-chai": "latest", + "karma-coverage": "^0.2.7", + "karma-mocha": "latest", + "karma-phantomjs-launcher": "^0.1.4", + "karma-requirejs": "^0.2.2", + "karma-sinon": "^1.0.4", + "karma-sinon-chai": "^0.2.0", + "sinon": "^1.12.1" }, "directories": { "doc": "doc" }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "karma start" }, "author": "", "license": "ISC" diff --git a/spec/array_helper.spec.js b/spec/array_helper.spec.js new file mode 100644 index 0000000..8e10764 --- /dev/null +++ b/spec/array_helper.spec.js @@ -0,0 +1,53 @@ +define(['array_helper'], function(ArrayHelper){ + describe('init', function() { + it('initializes an array with the given value', function() { + var input = [0, 0, 0]; + ArrayHelper.init(input, 5); + expect(input).to.deep.equal([5, 5, 5]); + }); + }); + + describe('shuffle', function() { + before(function() { + sinon.stub(Math, 'random').returns(0.5); + }); + + after(function() { + sinon.restore(Math); + }); + it('shuffles the content of an array', function() { + var input = [1, 2, 3]; + expect(ArrayHelper.shuffle(input)).to.deep.equal([3, 1, 2]); + }); + }); + + describe('toPointList', function() { + it('converts an Array to a List of poitns', function() { + var input = [[1, 2], [2, 2], [3, 2]]; + expect(ArrayHelper.toPointList(input)).to.equal("[[1,2],\r\n[2,2],\r\n[3,2]]"); + }); + }); + + describe('threshold', function() { + it('returns all elements above the given threshold', function() { + var input = [1, 2, 3]; + expect(ArrayHelper.threshold(input, 2, function(score) { + return score * 1.5; + })).to.deep.equal([2, 3]); + }); + }); + + describe('maxIndex', function() { + it('gets the index of the biggest element in the array', function() { + var input = [1, 2, 3]; + expect(ArrayHelper.maxIndex(input)).to.equal(2); + }); + }); + + describe('max', function() { + it('gets the biggest element in the array', function() { + var input = [1, 3, 2]; + expect(ArrayHelper.max(input)).to.equal(3); + }); + }); +}); diff --git a/spec/cv_utils.spec.js b/spec/cv_utils.spec.js new file mode 100644 index 0000000..2282b01 --- /dev/null +++ b/spec/cv_utils.spec.js @@ -0,0 +1,11 @@ + +define(['cv_utils'], function(CVUtils){ + describe('imageRef', function() { + it('gets the image Reference for a coordinate', function() { + var res = CVUtils.imageRef(1, 2); + expect(res.x).to.equal(1); + expect(res.y).to.equal(2); + expect(res.toVec2()[0]).to.equal(1); + }); + }); +}); diff --git a/test-main.js b/test-main.js new file mode 100644 index 0000000..560ac37 --- /dev/null +++ b/test-main.js @@ -0,0 +1,26 @@ +var allTestFiles = []; +var TEST_REGEXP = /(spec|test)\.js$/i; + +var pathToModule = function(path) { + return path.replace(/^\/base\//, '').replace(/\.js$/, ''); +}; + +Object.keys(window.__karma__.files).forEach(function(file) { + if (TEST_REGEXP.test(file)) { + allTestFiles.push(pathToModule(file)); + } +}); + +require.config({ + baseUrl: '/base', + + paths: { + 'array_helper': 'src/array_helper', + 'cv_utils': 'src/cv_utils', + 'typedefs': 'src/typedefs', + 'glMatrixAddon': 'src/glMatrixAddon', + 'cluster': 'src/cluster' + }, + deps: allTestFiles, + callback: window.__karma__.start +});