diff --git a/Gruntfile.js b/Gruntfile.js index ef6670166..4472ca784 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -120,11 +120,13 @@ module.exports = function (grunt) { browser: true, globals: { define: true - } + }, + jasmine: true }, all: [ "Gruntfile", - "togetherjs/*.js" + "togetherjs/*.js", + "togetherjs/tests/jasmine/*.js" ] }, @@ -154,7 +156,7 @@ module.exports = function (grunt) { // forget. Then between git action the build will be over-run, // but that's harmless. minimal: { - files: ["togetherjs/**/*.less", "togetherjs/togetherjs.js", "togetherjs/templates-localized.js", + files: ["togetherjs/**/*.less", "togetherjs/togetherjs.js", "togetherjs/templates-localized.js", "togetherjs/**/*.html", "togetherjs/**/*.js", "!**/*_flymake*", "togetherjs/locales/**/*.json"], tasks: ["build"] } @@ -181,7 +183,7 @@ module.exports = function (grunt) { grunt.loadNpmTasks("grunt-contrib-less"); grunt.loadNpmTasks("grunt-contrib-csslint"); - grunt.loadNpmTasks("grunt-contrib-jshint"); + grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks("grunt-contrib-requirejs"); grunt.loadNpmTasks("grunt-contrib-watch"); grunt.loadNpmTasks('grunt-contrib-copy'); @@ -271,7 +273,7 @@ module.exports = function (grunt) { var gitCommit = process.env.GIT_COMMIT || ""; var subs = { __interface_html__: grunt.file.read("togetherjs/interface.html"), - __help_txt__: grunt.file.read("togetherjs/help.txt"), + __help_txt__: grunt.file.read("togetherjs/help.txt"), __walkthrough_html__: grunt.file.read("togetherjs/walkthrough.html"), __baseUrl__: baseUrl, __hubUrl__: hubUrl, @@ -324,13 +326,13 @@ module.exports = function (grunt) { var lang = path.basename(langFilename).replace(/\.json/, ""); var translation = JSON.parse(grunt.file.read(langFilename)); var dest = path.join(grunt.option("dest"), "togetherjs/templates-" + lang + ".js"); - + var translatedInterface = translateFile("togetherjs/interface.html", translation); var translatedHelp = translateFile("togetherjs/help.txt", translation); var translatedWalkthrough = translateFile("togetherjs/walkthrough.html", translation); var vars = subs; - + subs.__interface_html__ = translatedInterface; subs.__help_txt__ = translatedHelp; subs.__walkthrough_html__ = translatedWalkthrough; @@ -345,7 +347,7 @@ module.exports = function (grunt) { } ); - + function translateFile(source, translation) { var env = new nunjucks.Environment(new nunjucks.FileSystemLoader("./")); var tmpl = env.getTemplate(source); diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 000000000..00f346a1c --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,69 @@ +// Karma configuration +// Generated on Wed Jun 17 2015 10:28:03 GMT+0100 (BST) + +module.exports = function(config) { + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine', 'requirejs'], + + + // list of files / patterns to load in the browser + files: [ + {pattern: 'togetherjs/tests/jasmine/mocks/*.mock.js', included: true}, + {pattern: 'togetherjs/tests/jasmine/**/*.spec.js', included: false}, + {pattern: 'togetherjs/*.js', included: false}, + {pattern: 'togetherjs/libs/**/*.js', included: false}, + 'test-main.js' + ], + + + // list of files to exclude + exclude: [ + ], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + }, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['PhantomJS'], + + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false + }); +}; diff --git a/package.json b/package.json index 6de95d71c..7693784aa 100644 --- a/package.json +++ b/package.json @@ -25,21 +25,28 @@ "optimist": "~0.6.0" }, "devDependencies": { - "grunt-contrib-less": "~0.5.1", + "docco": "~0.6.2", + "freeport": "~1.0.3", + "grunt": "~0.4.1", + "grunt-contrib-copy": "~0.4.1", "grunt-contrib-csslint": "~0.1.2", - "grunt-contrib-jshint": "~0.4.3", + "grunt-contrib-jshint": "^0.11.2", + "grunt-contrib-less": "~0.5.1", "grunt-contrib-requirejs": "~0.4.1", "grunt-contrib-watch": "~0.4.3", - "grunt": "~0.4.1", - "grunt-contrib-copy": "~0.4.1", "grunt-http-server": "~0.0.5", - "nunjucks": "~0.1.8a", - "marked": "~0.2.9", - "docco": "~0.6.2", + "grunt-lib-phantomjs": "~0.6.0", "highlight.js": "~7.3.0", + "jasmine-core": "^2.3.4", + "karma": "^0.12.36", + "karma-jasmine": "^0.2.2", + "karma-phantomjs-launcher": "^0.2.0", + "karma-requirejs": "^0.2.2", + "marked": "~0.2.9", + "nunjucks": "~0.1.8a", "optimist": "~0.6.0", - "freeport": "~1.0.3", - "grunt-lib-phantomjs": "~0.6.0" + "phantomjs": "^1.9.17", + "requirejs": "^2.1.18" }, "engines": { "node": "~0.8", diff --git a/test-main.js b/test-main.js new file mode 100644 index 000000000..f718bb25c --- /dev/null +++ b/test-main.js @@ -0,0 +1,29 @@ +var allTestFiles = []; +var TEST_REGEXP = /(spec|test)\.js$/i; + +Object.keys(window.__karma__.files).forEach(function(file) { + if (TEST_REGEXP.test(file)) { + // Normalize paths to RequireJS module names. + allTestFiles.push(file); + } +}); + +require.config({ + // Karma serves files under /base, which is the basePath from your config file + baseUrl: '/base/togetherjs', + + // dynamically load all test files + deps: allTestFiles, + + // paths to dependencies + paths: { + 'jquery': 'libs/jquery-1.11.1.min', + 'almond': 'libs/almond', + 'tinycolor': 'libs/tinycolor', + 'mersenne': 'libs/whrandom/mersenne', + 'random': 'libs/whrandom/random' + }, + + // we have to kickoff jasmine, as it is asynchronous + callback: window.__karma__.start +}); diff --git a/togetherjs/tests/jasmine/mocks/togetherjs.mock.js b/togetherjs/tests/jasmine/mocks/togetherjs.mock.js new file mode 100644 index 000000000..e95f5891d --- /dev/null +++ b/togetherjs/tests/jasmine/mocks/togetherjs.mock.js @@ -0,0 +1,8 @@ +/** + * This file contains a global variable to mock bits of the TogetherJS to allow testing using Jasmine. + * A useful refactor would be to remove the dependency on a global TJS object and instead inject it where it's + * required in other files. + */ +var TogetherJS = {}; + + diff --git a/togetherjs/tests/jasmine/util.spec.js b/togetherjs/tests/jasmine/util.spec.js new file mode 100644 index 000000000..71f948cb1 --- /dev/null +++ b/togetherjs/tests/jasmine/util.spec.js @@ -0,0 +1,31 @@ +define(['util'], function(util) { + 'use strict'; + describe('Util', function() { + describe('util.trim', function() { + var testString; + + beforeEach(function(){ + testString = 'test'; + }); + + it('should trim whitespace from the start of a string', function() { + expect(util.trim(' ' + testString)).toEqual(testString); + }); + + it('should trim whitespace from the end of a string', function() { + expect(util.trim(testString + ' ')).toEqual(testString); + }); + + it('should trim whitespace from both ends of a string', function() { + expect(util.trim(' ' + testString + ' ')).toEqual(testString); + }); + + it('should not change a string with whitespace in the middle', function() { + var longTestString = testString + ' ' + testString; + + expect(util.trim(longTestString)).toEqual(longTestString); + }); + }); + }); +}); + diff --git a/togetherjs/util.js b/togetherjs/util.js index d0ec1f29b..c180ab689 100644 --- a/togetherjs/util.js +++ b/togetherjs/util.js @@ -84,7 +84,7 @@ define(["jquery", "jqueryPlugins"], function ($) { }; util.AssertionError = function (message) { - if (! this instanceof util.AssertionError) { + if (! (this instanceof util.AssertionError)) { return new util.AssertionError(message); } this.message = message;