diff --git a/.istanbul.yml b/.istanbul.yml new file mode 100644 index 00000000..942110f1 --- /dev/null +++ b/.istanbul.yml @@ -0,0 +1,2 @@ +reporting: + dir: ./coverage/server diff --git a/.travis.yml b/.travis.yml index bc327d12..53579899 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,12 @@ language: node_js node_js: - "node" +before_install: + - export CHROME_BIN=chromium-browser + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start after_success: - istanbul cover ./node_modules/mocha/bin/_mocha - - cat ./coverage/lcov.info | ./node_modules/.bin/coveralls + - karma start + - lcov-result-merger 'coverage/**/lcov.info' 'coverage/fullCoverage.info' + - cat ./coverage/fullCoverage.info | ./node_modules/.bin/coveralls diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 00000000..c4175a16 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,67 @@ +// Karma configuration + +module.exports = function(config) { + var configuration = { + basePath: '', + frameworks: ['mocha'], + files: [ + 'teddy.js', + 'test/models/*.js', + 'node_modules/chai/chai.js', + 'node_modules/chai-string/chai-string.js', + 'test/templates/**/*', + 'test/*.js', + 'test/client.html' + ], + reporters: ['spec', 'coverage'], + port: 8000, + proxies: { + '/templates/': '/base/test/templates/', + }, + preprocessors: { + 'teddy.js': ['coverage'], + 'test/templates/**/*': ['html2js'] + }, + html2JsPreprocessor: { + stripPrefix: 'test/templates/' + }, + specReporter: { + maxLogLines: 5, + suppressErrorSummary: false, + suppressFailed: false, + suppressPassed: false, + suppressSkipped: false, + showSpecTiming: true + }, + coverageReporter: { + type: 'lcov', + dir: 'coverage/', + subdir: function(browser) { + return browser.toLowerCase().split(/[ /-]/)[0]; + } + }, + client: { + mocha: { + reporter: 'html' + } + }, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: false, + singleRun: true, + browsers: ['Chrome'], + customLaunchers: { + Chrome_travis_ci: { + base: 'Chrome', + flags: ['--no-sandbox'] + } + }, + concurrency: 1 + }; + + if (process.env.TRAVIS) { + configuration.browsers = ['Chrome_travis_ci']; + } + + config.set(configuration); +}; diff --git a/package.json b/package.json index 229dc282..d9e29c0d 100755 --- a/package.json +++ b/package.json @@ -14,14 +14,23 @@ "dependencies": { }, "devDependencies": { - "eslint": "3.13.1", + "eslint": "3.19.0", "mocha": "3.2.0", "chai": "3.5.0", "chai-string": "1.3.0", "istanbul": "0.4.5", "mocha-lcov-reporter": "1.3.0", - "coveralls": "2.12.0", - "cross-env": "4.0.0" + "coveralls": "2.13.0", + "cross-env": "4.0.0", + "karma": "1.6.0", + "karma-cli": "1.0.1", + "karma-mocha": "1.3.0", + "karma-coverage": "1.1.1", + "karma-chrome-launcher": "2.0.0", + "karma-coverage-allsources": "0.0.4", + "lcov-result-merger": "^1.2.0", + "karma-html2js-preprocessor": "1.1.0", + "karma-spec-reporter": "0.0.31" }, "eslintConfig": { "env": { @@ -54,9 +63,12 @@ } }, "scripts": { - "test": "cross-env NODE_ENV=test mocha --recursive test", + "test": "cross-env NODE_ENV=test npm run test-server && npm run test-client", + "test-server": "cross-env NODE_ENV=test mocha --recursive test", + "test-client": "karma start", "eslint": "eslint .", - "cover": "cross-env NODE_ENV=cover istanbul cover _mocha --recursive test" + "cover": "cross-env NODE_ENV=cover istanbul cover _mocha --recursive test", + "coverage": "npm run cover" }, "pre-commit": [ "test", diff --git a/teddy.js b/teddy.js index 0169abec..82930043 100644 --- a/teddy.js +++ b/teddy.js @@ -79,18 +79,7 @@ */ // default values for parameters sent to teddy - params: { - verbosity: 1, - templateRoot: './', - cacheRenders: false, - defaultCaches: 1, - templateMaxCaches: {}, - cacheWhitelist: false, - cacheBlacklist: [], - compileAtEveryRender: false, - minify: false, - maxPasses: 25000 - }, + params: {}, // compiled templates are stored as object collections, e.g. { "myTemplate.html": "

some markup

"} templates: {}, @@ -102,6 +91,20 @@ * mutator methods for public member vars */ + // sets all params to their default values + setDefaultParams: function() { + teddy.params.verbosity = 1; + teddy.params.templateRoot = './'; + teddy.params.cacheRenders = false; + teddy.params.defaultCaches = 1; + teddy.params.templateMaxCaches = {}; + teddy.params.cacheWhitelist = false; + teddy.params.cacheBlacklist = []; + teddy.params.compileAtEveryRender = false; + teddy.params.minify = false; + teddy.params.maxPasses = 25000; + }, + // mutator method to set verbosity param. takes human-readable string argument and converts it to an integer for more efficient checks against the setting setVerbosity: function(v) { switch (v) { @@ -225,6 +228,12 @@ } } } + else { + if (teddy.templates[template]) { + template = teddy.templates[template]; + register = true; + } + } // remove {! comments !} and (optionally) unnecessary whitespace do { @@ -257,6 +266,15 @@ // invalidates cache of a given template and model combination // if no model is supplied, deletes all caches of the given template flushCache: function(template, model) { + + // ensure template is a string + if (typeof template !== 'string') { + if (teddy.params.verbosity > 1) { + teddy.console.warn('teddy.flushCache attempted to invalidate cache of template that is not a string'); + } + return ''; + } + // append extension if not present if (template.slice(-5) !== '.html') { template += '.html'; @@ -1174,6 +1192,9 @@ } }; + // set params to default values + teddy.setDefaultParams(); + /** * private utility methods */ diff --git a/test/client.html b/test/client.html index 9d85d4c8..9df4646c 100644 --- a/test/client.html +++ b/test/client.html @@ -6,26 +6,18 @@ Teddy Templating Engine unit tests -
-

Teddy Templating Engine unit tests

+

Teddy Templating Engine unit tests

-
-

Warning: these tests can only be run from a web server.

-

Due to the same origin policy applying to files loaded directly from the local filesystem, these unit tests can only be executed from a real HTTP server.

-

To start a simple web server to run these tests with, open your terminal and run this command from the "teddy" directory:

-
python -m SimpleHTTPServer
-

(For python 2.x.)

-

If that command doesn't work, try the python 3.x version instead:

-
python -m http.server

(For python 3.x.)

-

Then simply visit http://localhost:8000/test/client.html

-

If you can't run the command, then you'll need to install Python or use some other web server.

-
- - -
- - +
@@ -328,134 +296,23 @@

Warning: these tests can only be run from a web server.

+ + - - - - - + diff --git a/test/conditionals.js b/test/conditionals.js index 77562e4d..5a9292dc 100644 --- a/test/conditionals.js +++ b/test/conditionals.js @@ -1,30 +1,4 @@ -if (typeof module !== 'undefined') { - var chai = require('chai'), - chaiString = require('chai-string'), - assert = chai.assert, - model, - makeModel = require('./models/model'), - teddy = require('../teddy'); - chai.use(chaiString); -} - describe('Conditionals', function() { - before(function() { - teddy.setTemplateRoot('test/templates'); - model = makeModel(); - if (typeof process !== 'undefined') { - if (process.env.NODE_ENV === 'test') { - teddy.setVerbosity(0); - } - else if (process.env.NODE_ENV === 'cover') { - teddy.setVerbosity(3); - } - } - else { - teddy.setVerbosity(0); - } - }); - it('should evaluate as true (conditionals/if.html)', function(done) { assert.equalIgnoreSpaces(teddy.render('conditionals/if.html', model), '

The variable \'something\' is present

'); done(); diff --git a/test/global.js b/test/global.js new file mode 100644 index 00000000..83c95983 --- /dev/null +++ b/test/global.js @@ -0,0 +1,22 @@ +if (typeof process === 'object') { + global.chai = require('chai'); + global.chaiString = require('chai-string'); + global.assert = chai.assert; + global.makeModel = require('./models/model'); + global.teddy = require('../teddy'); + global.model = makeModel(); +} + +before(function() { + teddy.setTemplateRoot('test/templates'); + model = makeModel(); + if (typeof process === 'object') { + chai.use(chaiString); + if (process.env.NODE_ENV === 'test') { + teddy.setVerbosity(0); + } + else if (process.env.NODE_ENV === 'cover') { + teddy.setVerbosity(3); + } + } +}); diff --git a/test/includes.js b/test/includes.js index 586e1fff..7e94d7aa 100644 --- a/test/includes.js +++ b/test/includes.js @@ -1,30 +1,4 @@ -if (typeof module !== 'undefined') { - var chai = require('chai'), - chaiString = require('chai-string'), - assert = chai.assert, - model, - makeModel = require('./models/model'), - teddy = require('../teddy'); - chai.use(chaiString); -} - describe('Includes', function() { - before(function() { - teddy.setTemplateRoot('test/templates'); - model = makeModel(); - if (typeof process !== 'undefined') { - if (process.env.NODE_ENV === 'test') { - teddy.setVerbosity(0); - } - else if (process.env.NODE_ENV === 'cover') { - teddy.setVerbosity(3); - } - } - else { - teddy.setVerbosity(0); - } - }); - it('should a template (includes/include.html)', function(done) { assert.equalIgnoreSpaces(teddy.render('includes/include.html', model), '

Some content

'); done(); diff --git a/test/looping.js b/test/looping.js index 8423b485..55ccf077 100644 --- a/test/looping.js +++ b/test/looping.js @@ -1,30 +1,16 @@ -if (typeof module !== 'undefined') { - var chai = require('chai'), - chaiString = require('chai-string'), - assert = chai.assert, - model, - makeModel = require('./models/model'), - teddy = require('../teddy'); - chai.use(chaiString); +var loopMs; + +if (typeof process === 'object') { + loopMs = 50; + if (process.env.NODE_ENV === 'cover') { + loopMs = 500; + } +} +else { + loopMs = 500; } describe('Looping', function() { - before(function() { - teddy.setTemplateRoot('test/templates'); - model = makeModel(); - if (typeof process !== 'undefined') { - if (process.env.NODE_ENV === 'test') { - teddy.setVerbosity(0); - } - else if (process.env.NODE_ENV === 'cover') { - teddy.setVerbosity(3); - } - } - else { - teddy.setVerbosity(0); - } - }); - it('should loop through {letters} correctly (looping/loopVal.html)', function(done) { assert.equalIgnoreSpaces(teddy.render('looping/loopVal.html', model), '

a

b

c

'); done(); @@ -70,7 +56,7 @@ describe('Looping', function() { done(); }); - it('should loop through same array of 5000 elements in < 50ms during second attempt due to caching (looping/largeDataSet.html)', function(done) { + it('should loop through same array of 5000 elements in < ' + loopMs + 'ms during second attempt due to caching (looping/largeDataSet.html)', function(done) { var start, end, time; start = new Date().getTime(); @@ -79,7 +65,7 @@ describe('Looping', function() { end = new Date().getTime(); time = end - start; - assert.isAtMost(time, 50); + assert.isAtMost(time, loopMs); done(); }); @@ -97,7 +83,7 @@ describe('Looping', function() { done(); }); - it('should loop through same array of 5000 elements in < 50ms during second attempt due to caching (looping/largeDataSet.html)', function(done) { + it('should loop through same array of 5000 elements in < ' + loopMs + 'ms during second attempt due to caching (looping/largeDataSet.html)', function(done) { var start, end, time; start = new Date().getTime(); @@ -106,7 +92,7 @@ describe('Looping', function() { end = new Date().getTime(); time = end - start; - assert.isAtMost(time, 50); + assert.isAtMost(time, loopMs); done(); }); @@ -124,7 +110,7 @@ describe('Looping', function() { done(); }); - it('should loop through same array of 5000 elements in < 50ms during second attempt due to caching (looping/largeDataSet.html)', function(done) { + it('should loop through same array of 5000 elements in < ' + loopMs + 'ms during second attempt due to caching (looping/largeDataSet.html)', function(done) { var start, end, time; start = new Date().getTime(); @@ -134,7 +120,7 @@ describe('Looping', function() { time = end - start; teddy.cacheRenders(false); - assert.isAtMost(time, 50); + assert.isAtMost(time, loopMs); done(); }); diff --git a/test/misc.js b/test/misc.js index be84b4ef..334d0c37 100644 --- a/test/misc.js +++ b/test/misc.js @@ -1,31 +1,4 @@ -if (typeof module !== 'undefined') { - var chai = require('chai'), - chaiString = require('chai-string'), - assert = chai.assert, - model, - makeModel = require('./models/model'), - verbosity = '', - teddy = require('../teddy'); - chai.use(chaiString); -} - describe('Misc', function() { - before(function() { - teddy.setTemplateRoot('test/templates'); - model = makeModel(); - if (typeof process !== 'undefined') { - if (process.env.NODE_ENV === 'test') { - teddy.setVerbosity(0); - } - else if (process.env.NODE_ENV === 'cover') { - teddy.setVerbosity(3); - } - } - else { - teddy.setVerbosity(0); - } - }); - it('should render {variables} (misc/variable.html)', function(done) { assert.equalIgnoreSpaces(teddy.render('misc/variable.html', model), '

Some content

'); done(); @@ -161,8 +134,8 @@ describe('Misc', function() { done(); }); - // broken client-side ಠ_ಠ @Autre31415 - it.skip('should set each verbosity level', function(done) { + it('should set each verbosity level', function(done) { + verbosity = ''; teddy.setVerbosity(); verbosity += teddy.params.verbosity + ', '; teddy.setVerbosity('none'); @@ -179,20 +152,32 @@ describe('Misc', function() { verbosity += teddy.params.verbosity; assert.equal(verbosity, '1, 0, 0, 2, 2, 3, 3'); - if (process.env.NODE_ENV === 'test') { - teddy.setVerbosity(0); + verbosity = ''; + if (typeof process === 'object') { + if (process.env.NODE_ENV === 'test') { + teddy.setVerbosity(0); + } + else if (process.env.NODE_ENV === 'cover') { + teddy.setVerbosity(3); + } } - else if (process.env.NODE_ENV === 'cover') { - teddy.setVerbosity(3); + else { + teddy.setVerbosity(0); } done(); }); - // broken client-side ಠ_ಠ @Autre31415 - it.skip('should minify template with internal minifier (misc/plainHTML.html)', function(done) { + it('should minify template with internal minifier (misc/templateToMinify.html)', function(done) { + teddy.compileAtEveryRender(true); teddy.minify(true); - assert.equal(teddy.compile('misc/plainHTML.html', model), ' Plain HTML

This template contains no teddy tags. Just HTML.

'); + assert.equal(teddy.render('misc/templateToMinify.html', model), ' Plain HTML

This template contains no teddy tags. Just HTML.

'); teddy.minify(false); + teddy.compileAtEveryRender(false); + done(); + }); + + it('should avoid flushing cache of non strings', function(done) { + assert.equalIgnoreSpaces(teddy.flushCache(5), ''); done(); }); }); diff --git a/test/templates/misc/templateToMinify.html b/test/templates/misc/templateToMinify.html new file mode 100644 index 00000000..c159ecf2 --- /dev/null +++ b/test/templates/misc/templateToMinify.html @@ -0,0 +1,14 @@ + + + + + + + Plain HTML + + +
+

This template contains no teddy tags. Just HTML.

+
+ +