/* jshint mocha: true */ /** * Module dependencies. */ var ejs = require('..') , fs = require('fs') , read = fs.readFileSync , assert = require('assert') , path = require('path'); try { fs.mkdirSync(__dirname + '/tmp'); } catch (ex) { if (ex.code !== 'EEXIST') { throw ex; } } // From https://gist.github.com/pguillory/729616 function hook_stdio(stream, callback) { var old_write = stream.write; stream.write = (function() { return function(string, encoding, fd) { callback(string, encoding, fd); }; })(stream.write); return function() { stream.write = old_write; }; } /** * Load fixture `name`. */ function fixture(name) { return read('test/fixtures/' + name, 'utf8').replace(/\r/g, '').trim(); } /** * User fixtures. */ var users = []; users.push({name: 'geddy'}); users.push({name: 'neil'}); users.push({name: 'alex'}); suite('ejs.compile(str, options)', function () { test('compile to a function', function () { var fn = ejs.compile('

yay

'); assert.equal(fn(), '

yay

'); }); test('empty input works', function () { var fn = ejs.compile(''); assert.equal(fn(), ''); }); test('throw if there are syntax errors', function () { try { ejs.compile(fixture('fail.ejs')); } catch (err) { assert.ok(err.message.indexOf('compiling ejs') > -1); try { ejs.compile(fixture('fail.ejs'), {filename: 'fail.ejs'}); } catch (err) { assert.ok(err.message.indexOf('fail.ejs') > -1); return; } } throw new Error('no error reported when there should be'); }); test('allow customizing delimiter local var', function () { var fn; fn = ejs.compile('

', {delimiter: '?'}); assert.equal(fn({name: 'geddy'}), '

geddy

'); fn = ejs.compile('

<:= name :>

', {delimiter: ':'}); assert.equal(fn({name: 'geddy'}), '

geddy

'); fn = ejs.compile('

<$= name $>

', {delimiter: '$'}); assert.equal(fn({name: 'geddy'}), '

geddy

'); }); test('default to using ejs.delimiter', function () { var fn; ejs.delimiter = '&'; fn = ejs.compile('

<&= name &>

'); assert.equal(fn({name: 'geddy'}), '

geddy

'); fn = ejs.compile('

<|= name |>

', {delimiter: '|'}); assert.equal(fn({name: 'geddy'}), '

geddy

'); delete ejs.delimiter; }); test('have a working client option', function () { var fn , str , preFn; fn = ejs.compile('

<%= foo %>

', {client: true}); str = fn.toString(); if (!process.env.running_under_istanbul) { eval('var preFn = ' + str); assert.equal(preFn({foo: 'bar'}), '

bar

'); } }); test('support client mode without locals', function () { var fn , str , preFn; fn = ejs.compile('

<%= "foo" %>

', {client: true}); str = fn.toString(); if (!process.env.running_under_istanbul) { eval('var preFn = ' + str); assert.equal(preFn(), '

foo

'); } }); }); suite('ejs.render(str, data)', function () { test('render the template', function () { assert.equal(ejs.render('

yay

'), '

yay

'); }); test('empty input works', function () { assert.equal(ejs.render(''), ''); }); test('undefined renders nothing escaped', function () { assert.equal(ejs.render('<%= undefined %>'), ''); }); test('undefined renders nothing raw', function () { assert.equal(ejs.render('<%- undefined %>'), ''); }); test('null renders nothing escaped', function () { assert.equal(ejs.render('<%= null %>'), ''); }); test('null renders nothing raw', function () { assert.equal(ejs.render('<%- null %>'), ''); }); test('zero-value data item renders something escaped', function () { assert.equal(ejs.render('<%= 0 %>'), '0'); }); test('zero-value data object renders something raw', function () { assert.equal(ejs.render('<%- 0 %>'), '0'); }); test('accept locals', function () { assert.equal(ejs.render('

<%= name %>

', {name: 'geddy'}), '

geddy

'); }); test('accept locals without using with() {}', function () { assert.equal(ejs.render('

<%= locals.name %>

', {name: 'geddy'}, {_with: false}), '

geddy

'); assert.throws(function() { ejs.render('

<%= name %>

', {name: 'geddy'}, {_with: false}); }, /name is not defined/); }); test('accept custom name for locals', function () { ejs.localsName = 'it'; assert.equal(ejs.render('

<%= it.name %>

', {name: 'geddy'}, {_with: false}), '

geddy

'); assert.throws(function() { ejs.render('

<%= name %>

', {name: 'geddy'}, {_with: false}); }, /name is not defined/); ejs.localsName = 'locals'; }); test('support caching (pass 1)', function () { var file = __dirname + '/tmp/render.ejs' , options = {cache: true, filename: file} , out = ejs.render('

Old

', {}, options) , expected = '

Old

'; assert.equal(out, expected); }); test('support caching (pass 2)', function () { var file = __dirname + '/tmp/render.ejs' , options = {cache: true, filename: file} , out = ejs.render('

New

', {}, options) , expected = '

Old

'; assert.equal(out, expected); }); }); suite('ejs.renderFile(path, [data], [options], fn)', function () { test('render a file', function(done) { ejs.renderFile('test/fixtures/para.ejs', function(err, html) { if (err) { return done(err); } assert.equal(html, '

hey

'); done(); }); }); test('callback is async', function(done) { var async = false; ejs.renderFile('test/fixtures/para.ejs', function(err, html) { if (async) { return done(); } throw new Error('not async'); }); async = true; }); test('accept locals', function(done) { var data = {name: 'fonebone'} , options = {delimiter: '$'}; ejs.renderFile('test/fixtures/user.ejs', data, options, function(err, html) { if (err) { return done(err); } assert.equal(html, '

fonebone

'); done(); }); }); test('accept locals without using with() {}', function(done) { var data = {name: 'fonebone'} , options = {delimiter: '$', _with: false} , doneCount = 0; ejs.renderFile('test/fixtures/user-no-with.ejs', data, options, function(err, html) { if (err) { if (doneCount === 2) { return; } doneCount = 2; return done(err); } assert.equal(html, '

fonebone

'); doneCount++; if (doneCount === 2) { done(); } }); ejs.renderFile('test/fixtures/user.ejs', data, options, function(err) { if (!err) { if (doneCount === 2) { return; } doneCount = 2; return done(new Error('error not thrown')); } doneCount++; if (doneCount === 2) { done(); } }); }); test('not catch err thrown by callback', function(done) { var data = {name: 'fonebone'} , options = {delimiter: '$'} , counter = 0; var d = require('domain').create(); d.on('error', function (err) { assert.equal(counter, 1); assert.equal(err.message, 'Exception in callback'); done(); }); d.run(function () { // process.nextTick() needed to work around mochajs/mocha#513 // // tl;dr: mocha doesn't support synchronous exception throwing in // domains. Have to make it async. Ticket closed because: "domains are // deprecated :D" process.nextTick(function () { ejs.renderFile('test/fixtures/user.ejs', data, options, function(err) { counter++; if (err) { assert.notEqual(err.message, 'Exception in callback'); return done(err); } throw new Error('Exception in callback'); }); }); }); }); test('support caching (pass 1)', function (done) { var expected = '

Old

' , file = __dirname + '/tmp/renderFile.ejs' , options = {cache: true}; fs.writeFileSync(file, '

Old

'); ejs.renderFile(file, {}, options, function (err, out) { if (err) { done(err); } assert.equal(out, expected); done(); }); }); test('support caching (pass 2)', function (done) { var expected = '

Old

' , file = __dirname + '/tmp/renderFile.ejs' , options = {cache: true}; fs.writeFileSync(file, '

New

'); ejs.renderFile(file, {}, options, function (err, out) { if (err) { done(err); } assert.equal(out, expected); done(); }); }); }); suite('ejs.clearCache()', function () { test('work properly', function () { var expected = '

Old

' , file = __dirname + '/tmp/clearCache.ejs' , options = {cache: true, filename: file} , out = ejs.render('

Old

', {}, options); assert.equal(out, expected); ejs.clearCache(); expected = '

New

'; out = ejs.render('

New

', {}, options); assert.equal(out, expected); }); }); suite('<%', function () { test('without semicolons', function () { assert.equal(ejs.render(fixture('no.semicolons.ejs')), fixture('no.semicolons.html')); }); }); suite('<%=', function () { test('escape &