1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | var ejs = require('..');
|
9 | var fs = require('fs');
|
10 | var read = fs.readFileSync;
|
11 | var assert = require('assert');
|
12 | var path = require('path');
|
13 | var LRU = require('lru-cache');
|
14 |
|
15 | try {
|
16 | fs.mkdirSync(__dirname + '/tmp');
|
17 | } catch (ex) {
|
18 | if (ex.code !== 'EEXIST') {
|
19 | throw ex;
|
20 | }
|
21 | }
|
22 |
|
23 |
|
24 | function hook_stdio(stream, callback) {
|
25 | var old_write = stream.write;
|
26 |
|
27 | stream.write = (function() {
|
28 | return function(string, encoding, fd) {
|
29 | callback(string, encoding, fd);
|
30 | };
|
31 | })(stream.write);
|
32 |
|
33 | return function() {
|
34 | stream.write = old_write;
|
35 | };
|
36 | }
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 | function fixture(name) {
|
43 | return read('test/fixtures/' + name, 'utf8');
|
44 | }
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 | var users = [];
|
51 | users.push({name: 'geddy'});
|
52 | users.push({name: 'neil'});
|
53 | users.push({name: 'alex'});
|
54 |
|
55 | suite('ejs.compile(str, options)', function () {
|
56 | test('compile to a function', function () {
|
57 | var fn = ejs.compile('<p>yay</p>');
|
58 | assert.equal(fn(), '<p>yay</p>');
|
59 | });
|
60 |
|
61 | test('empty input works', function () {
|
62 | var fn = ejs.compile('');
|
63 | assert.equal(fn(), '');
|
64 | });
|
65 |
|
66 | test('throw if there are syntax errors', function () {
|
67 | try {
|
68 | ejs.compile(fixture('fail.ejs'));
|
69 | }
|
70 | catch (err) {
|
71 | assert.ok(err.message.indexOf('compiling ejs') > -1);
|
72 |
|
73 | try {
|
74 | ejs.compile(fixture('fail.ejs'), {filename: 'fail.ejs'});
|
75 | }
|
76 | catch (err) {
|
77 | assert.ok(err.message.indexOf('fail.ejs') > -1);
|
78 | return;
|
79 | }
|
80 | }
|
81 | throw new Error('no error reported when there should be');
|
82 | });
|
83 |
|
84 | test('allow customizing delimiter local var', function () {
|
85 | var fn;
|
86 | fn = ejs.compile('<p><?= name ?></p>', {delimiter: '?'});
|
87 | assert.equal(fn({name: 'geddy'}), '<p>geddy</p>');
|
88 |
|
89 | fn = ejs.compile('<p><:= name :></p>', {delimiter: ':'});
|
90 | assert.equal(fn({name: 'geddy'}), '<p>geddy</p>');
|
91 |
|
92 | fn = ejs.compile('<p><$= name $></p>', {delimiter: '$'});
|
93 | assert.equal(fn({name: 'geddy'}), '<p>geddy</p>');
|
94 | });
|
95 |
|
96 | test('default to using ejs.delimiter', function () {
|
97 | var fn;
|
98 | ejs.delimiter = '&';
|
99 | fn = ejs.compile('<p><&= name &></p>');
|
100 | assert.equal(fn({name: 'geddy'}), '<p>geddy</p>');
|
101 |
|
102 | fn = ejs.compile('<p><|= name |></p>', {delimiter: '|'});
|
103 | assert.equal(fn({name: 'geddy'}), '<p>geddy</p>');
|
104 | delete ejs.delimiter;
|
105 | });
|
106 |
|
107 | test('have a working client option', function () {
|
108 | var fn;
|
109 | var str;
|
110 | var preFn;
|
111 | fn = ejs.compile('<p><%= foo %></p>', {client: true});
|
112 | str = fn.toString();
|
113 | if (!process.env.running_under_istanbul) {
|
114 | eval('var preFn = ' + str);
|
115 | assert.equal(preFn({foo: 'bar'}), '<p>bar</p>');
|
116 | }
|
117 | });
|
118 |
|
119 | test('support client mode without locals', function () {
|
120 | var fn;
|
121 | var str;
|
122 | var preFn;
|
123 | fn = ejs.compile('<p><%= "foo" %></p>', {client: true});
|
124 | str = fn.toString();
|
125 | if (!process.env.running_under_istanbul) {
|
126 | eval('var preFn = ' + str);
|
127 | assert.equal(preFn(), '<p>foo</p>');
|
128 | }
|
129 | });
|
130 |
|
131 | test('not include rethrow() in client mode if compileDebug is false', function () {
|
132 | var fn = ejs.compile('<p><%= "foo" %></p>', {
|
133 | client: true,
|
134 | compileDebug: false
|
135 | });
|
136 |
|
137 | assert((fn.toString().match(/rethrow/g) || []).length <= 1);
|
138 | });
|
139 |
|
140 | test('support custom escape function', function () {
|
141 | var customEscape;
|
142 | var fn;
|
143 | customEscape = function customEscape(str) {
|
144 | return !str ? '' : str.toUpperCase();
|
145 | };
|
146 | fn = ejs.compile('HELLO <%= name %>', {escape: customEscape});
|
147 | assert.equal(fn({name: 'world'}), 'HELLO WORLD');
|
148 | });
|
149 |
|
150 | test('support custom escape function in client mode', function () {
|
151 | var customEscape;
|
152 | var fn;
|
153 | var str;
|
154 | customEscape = function customEscape(str) {
|
155 | return !str ? '' : str.toUpperCase();
|
156 | };
|
157 | fn = ejs.compile('HELLO <%= name %>', {escape: customEscape, client: true});
|
158 | str = fn.toString();
|
159 | if (!process.env.running_under_istanbul) {
|
160 | eval('var preFn = ' + str);
|
161 | assert.equal(preFn({name: 'world'}), 'HELLO WORLD');
|
162 | }
|
163 | });
|
164 |
|
165 | test('strict mode works', function () {
|
166 | assert.equal(ejs.render(fixture('strict.ejs'), {}, {strict: true}), 'true');
|
167 | });
|
168 |
|
169 | });
|
170 |
|
171 | suite('ejs.render(str, data, opts)', function () {
|
172 | test('render the template', function () {
|
173 | assert.equal(ejs.render('<p>yay</p>'), '<p>yay</p>');
|
174 | });
|
175 |
|
176 | test('empty input works', function () {
|
177 | assert.equal(ejs.render(''), '');
|
178 | });
|
179 |
|
180 | test('undefined renders nothing escaped', function () {
|
181 | assert.equal(ejs.render('<%= undefined %>'), '');
|
182 | });
|
183 |
|
184 | test('undefined renders nothing raw', function () {
|
185 | assert.equal(ejs.render('<%- undefined %>'), '');
|
186 | });
|
187 |
|
188 | test('null renders nothing escaped', function () {
|
189 | assert.equal(ejs.render('<%= null %>'), '');
|
190 | });
|
191 |
|
192 | test('null renders nothing raw', function () {
|
193 | assert.equal(ejs.render('<%- null %>'), '');
|
194 | });
|
195 |
|
196 | test('zero-value data item renders something escaped', function () {
|
197 | assert.equal(ejs.render('<%= 0 %>'), '0');
|
198 | });
|
199 |
|
200 | test('zero-value data object renders something raw', function () {
|
201 | assert.equal(ejs.render('<%- 0 %>'), '0');
|
202 | });
|
203 |
|
204 | test('accept locals', function () {
|
205 | assert.equal(ejs.render('<p><%= name %></p>', {name: 'geddy'}),
|
206 | '<p>geddy</p>');
|
207 | });
|
208 |
|
209 | test('accept locals without using with() {}', function () {
|
210 | assert.equal(ejs.render('<p><%= locals.name %></p>', {name: 'geddy'},
|
211 | {_with: false}),
|
212 | '<p>geddy</p>');
|
213 | assert.throws(function() {
|
214 | ejs.render('<p><%= name %></p>', {name: 'geddy'},
|
215 | {_with: false});
|
216 | }, /name is not defined/);
|
217 | });
|
218 |
|
219 | test('accept custom name for locals', function () {
|
220 | ejs.localsName = 'it';
|
221 | assert.equal(ejs.render('<p><%= it.name %></p>', {name: 'geddy'},
|
222 | {_with: false}),
|
223 | '<p>geddy</p>');
|
224 | assert.throws(function() {
|
225 | ejs.render('<p><%= name %></p>', {name: 'geddy'},
|
226 | {_with: false});
|
227 | }, /name is not defined/);
|
228 | ejs.localsName = 'locals';
|
229 | });
|
230 |
|
231 | test('support caching', function () {
|
232 | var file = __dirname + '/tmp/render.ejs';
|
233 | var options = {cache: true, filename: file};
|
234 | var out = ejs.render('<p>Old</p>', {}, options);
|
235 | var expected = '<p>Old</p>';
|
236 | assert.equal(out, expected);
|
237 |
|
238 | out = ejs.render('<p>New</p>', {}, options);
|
239 | assert.equal(out, expected);
|
240 | });
|
241 |
|
242 | test('support LRU caching', function () {
|
243 | var oldCache = ejs.cache;
|
244 | var file = __dirname + '/tmp/render.ejs';
|
245 | var options = {cache: true, filename: file};
|
246 | var out;
|
247 | var expected = '<p>Old</p>';
|
248 |
|
249 |
|
250 | ejs.cache = LRU();
|
251 |
|
252 | out = ejs.render('<p>Old</p>', {}, options);
|
253 | assert.equal(out, expected);
|
254 |
|
255 | out = ejs.render('<p>New</p>', {}, options);
|
256 | assert.equal(out, expected);
|
257 |
|
258 |
|
259 | ejs.cache = oldCache;
|
260 | });
|
261 |
|
262 | test('opts.context', function () {
|
263 | var ctxt = {foo: 'FOO'};
|
264 | var out = ejs.render('<%= this.foo %>', {}, {context: ctxt});
|
265 | assert.equal(out, ctxt.foo);
|
266 | });
|
267 | });
|
268 |
|
269 | suite('ejs.renderFile(path, [data], [options], fn)', function () {
|
270 | test('render a file', function(done) {
|
271 | ejs.renderFile('test/fixtures/para.ejs', function(err, html) {
|
272 | if (err) {
|
273 | return done(err);
|
274 | }
|
275 | assert.equal(html, '<p>hey</p>\n');
|
276 | done();
|
277 | });
|
278 | });
|
279 |
|
280 | test('accept locals', function(done) {
|
281 | var data = {name: 'fonebone'};
|
282 | var options = {delimiter: '$'};
|
283 | ejs.renderFile('test/fixtures/user.ejs', data, options, function(err, html) {
|
284 | if (err) {
|
285 | return done(err);
|
286 | }
|
287 | assert.equal(html, '<h1>fonebone</h1>\n');
|
288 | done();
|
289 | });
|
290 | });
|
291 |
|
292 | test('accept locals without using with() {}', function(done) {
|
293 | var data = {name: 'fonebone'};
|
294 | var options = {delimiter: '$', _with: false};
|
295 | var doneCount = 0;
|
296 | ejs.renderFile('test/fixtures/user-no-with.ejs', data, options, function(err, html) {
|
297 | if (err) {
|
298 | if (doneCount === 2) {
|
299 | return;
|
300 | }
|
301 | doneCount = 2;
|
302 | return done(err);
|
303 | }
|
304 | assert.equal(html, '<h1>fonebone</h1>\n');
|
305 | doneCount++;
|
306 | if (doneCount === 2) {
|
307 | done();
|
308 | }
|
309 | });
|
310 | ejs.renderFile('test/fixtures/user.ejs', data, options, function(err) {
|
311 | if (!err) {
|
312 | if (doneCount === 2) {
|
313 | return;
|
314 | }
|
315 | doneCount = 2;
|
316 | return done(new Error('error not thrown'));
|
317 | }
|
318 | doneCount++;
|
319 | if (doneCount === 2) {
|
320 | done();
|
321 | }
|
322 | });
|
323 | });
|
324 |
|
325 | test('not catch err thrown by callback', function(done) {
|
326 | var data = {name: 'fonebone'};
|
327 | var options = {delimiter: '$'};
|
328 | var counter = 0;
|
329 |
|
330 | var d = require('domain').create();
|
331 | d.on('error', function (err) {
|
332 | assert.equal(counter, 1);
|
333 | assert.equal(err.message, 'Exception in callback');
|
334 | done();
|
335 | });
|
336 | d.run(function () {
|
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 | process.nextTick(function () {
|
343 | ejs.renderFile('test/fixtures/user.ejs', data, options, function(err) {
|
344 | counter++;
|
345 | if (err) {
|
346 | assert.notEqual(err.message, 'Exception in callback');
|
347 | return done(err);
|
348 | }
|
349 | throw new Error('Exception in callback');
|
350 | });
|
351 | });
|
352 | });
|
353 | });
|
354 |
|
355 | test('support caching', function (done) {
|
356 | var expected = '<p>Old</p>';
|
357 | var file = __dirname + '/tmp/renderFile.ejs';
|
358 | var options = {cache: true};
|
359 | fs.writeFileSync(file, '<p>Old</p>');
|
360 |
|
361 | ejs.renderFile(file, {}, options, function (err, out) {
|
362 | if (err) {
|
363 | done(err);
|
364 | }
|
365 | fs.writeFileSync(file, '<p>New</p>');
|
366 | assert.equal(out, expected);
|
367 |
|
368 | ejs.renderFile(file, {}, options, function (err, out) {
|
369 | if (err) {
|
370 | done(err);
|
371 | }
|
372 |
|
373 | assert.equal(out, expected);
|
374 | done();
|
375 | });
|
376 | });
|
377 | });
|
378 |
|
379 | test('opts.context', function (done) {
|
380 | var ctxt = {foo: 'FOO'};
|
381 | ejs.renderFile('test/fixtures/with-context.ejs', {}, {context: ctxt}, function(err, html) {
|
382 | if (err) {
|
383 | return done(err);
|
384 | }
|
385 | assert.equal(html, ctxt.foo + '\n');
|
386 | done();
|
387 | });
|
388 |
|
389 | });
|
390 | });
|
391 |
|
392 | suite('cache specific', function () {
|
393 | test('`clearCache` work properly', function () {
|
394 | var expected = '<p>Old</p>';
|
395 | var file = __dirname + '/tmp/clearCache.ejs';
|
396 | var options = {cache: true, filename: file};
|
397 | var out = ejs.render('<p>Old</p>', {}, options);
|
398 | assert.equal(out, expected);
|
399 |
|
400 | ejs.clearCache();
|
401 |
|
402 | expected = '<p>New</p>';
|
403 | out = ejs.render('<p>New</p>', {}, options);
|
404 | assert.equal(out, expected);
|
405 | });
|
406 |
|
407 | test('`clearCache` work properly, LRU', function () {
|
408 | var expected = '<p>Old</p>';
|
409 | var oldCache = ejs.cache;
|
410 | var file = __dirname + '/tmp/clearCache.ejs';
|
411 | var options = {cache: true, filename: file};
|
412 | var out;
|
413 |
|
414 | ejs.cache = LRU();
|
415 |
|
416 | out = ejs.render('<p>Old</p>', {}, options);
|
417 | assert.equal(out, expected);
|
418 | ejs.clearCache();
|
419 | expected = '<p>New</p>';
|
420 | out = ejs.render('<p>New</p>', {}, options);
|
421 | assert.equal(out, expected);
|
422 |
|
423 | ejs.cache = oldCache;
|
424 | });
|
425 |
|
426 | test('LRU with cache-size 1', function () {
|
427 | var oldCache = ejs.cache;
|
428 | var options;
|
429 | var out;
|
430 | var expected;
|
431 | var file;
|
432 |
|
433 | ejs.cache = LRU(1);
|
434 |
|
435 | file = __dirname + '/tmp/render1.ejs';
|
436 | options = {cache: true, filename: file};
|
437 | out = ejs.render('<p>File1</p>', {}, options);
|
438 | expected = '<p>File1</p>';
|
439 | assert.equal(out, expected);
|
440 |
|
441 |
|
442 |
|
443 | file = __dirname + '/tmp/render1.ejs';
|
444 | options = {cache: true, filename: file};
|
445 | out = ejs.render('<p>ChangedFile1</p>', {}, options);
|
446 | expected = '<p>File1</p>';
|
447 | assert.equal(out, expected);
|
448 |
|
449 |
|
450 |
|
451 | file = __dirname + '/tmp/render2.ejs';
|
452 | options = {cache: true, filename: file};
|
453 | out = ejs.render('<p>File2</p>', {}, options);
|
454 | expected = '<p>File2</p>';
|
455 | assert.equal(out, expected);
|
456 |
|
457 |
|
458 |
|
459 | file = __dirname + '/tmp/render1.ejs';
|
460 | options = {cache: true, filename: file};
|
461 | out = ejs.render('<p>ChangedFile1</p>', {}, options);
|
462 | expected = '<p>ChangedFile1</p>';
|
463 | assert.equal(out, expected);
|
464 |
|
465 | ejs.cache = oldCache;
|
466 | });
|
467 | });
|
468 |
|
469 | suite('<%', function () {
|
470 | test('without semicolons', function () {
|
471 | assert.equal(ejs.render(fixture('no.semicolons.ejs')),
|
472 | fixture('no.semicolons.html'));
|
473 | });
|
474 | });
|
475 |
|
476 | suite('<%=', function () {
|
477 | test('escape &<script>', function () {
|
478 | assert.equal(ejs.render('<%= name %>', {name: ' <script>'}),
|
479 | '&nbsp;<script>');
|
480 | });
|
481 |
|
482 | test('should escape \'', function () {
|
483 | assert.equal(ejs.render('<%= name %>', {name: 'The Jones\'s'}),
|
484 | 'The Jones's');
|
485 | });
|
486 |
|
487 | test('should escape &foo_bar;', function () {
|
488 | assert.equal(ejs.render('<%= name %>', {name: '&foo_bar;'}),
|
489 | '&foo_bar;');
|
490 | });
|
491 |
|
492 | test('should accept custom function', function() {
|
493 |
|
494 | var customEscape = function customEscape(str) {
|
495 | return !str ? '' : str.toUpperCase();
|
496 | };
|
497 |
|
498 | assert.equal(
|
499 | ejs.render('<%= name %>', {name: 'The Jones\'s'}, {escape: customEscape}),
|
500 | 'THE JONES\'S'
|
501 | );
|
502 | });
|
503 | });
|
504 |
|
505 | suite('<%-', function () {
|
506 | test('not escape', function () {
|
507 | assert.equal(ejs.render('<%- name %>', {name: '<script>'}),
|
508 | '<script>');
|
509 | });
|
510 |
|
511 | test('terminate gracefully if no close tag is found', function () {
|
512 | try {
|
513 | ejs.compile('<h1>oops</h1><%- name ->');
|
514 | throw new Error('Expected parse failure');
|
515 | }
|
516 | catch (err) {
|
517 | assert.ok(err.message.indexOf('Could not find matching close tag for') > -1);
|
518 | }
|
519 | });
|
520 | });
|
521 |
|
522 | suite('%>', function () {
|
523 | test('produce newlines', function () {
|
524 | assert.equal(ejs.render(fixture('newlines.ejs'), {users: users}),
|
525 | fixture('newlines.html'));
|
526 | });
|
527 | test('works with `-%>` interspersed', function () {
|
528 | assert.equal(ejs.render(fixture('newlines.mixed.ejs'), {users: users}),
|
529 | fixture('newlines.mixed.html'));
|
530 | });
|
531 | test('consecutive tags work', function () {
|
532 | assert.equal(ejs.render(fixture('consecutive-tags.ejs')),
|
533 | fixture('consecutive-tags.html'));
|
534 | });
|
535 | });
|
536 |
|
537 | suite('-%>', function () {
|
538 | test('not produce newlines', function () {
|
539 | assert.equal(ejs.render(fixture('no.newlines.ejs'), {users: users}),
|
540 | fixture('no.newlines.html'));
|
541 | });
|
542 | test('stack traces work', function () {
|
543 | try {
|
544 | ejs.render(fixture('no.newlines.error.ejs'));
|
545 | }
|
546 | catch (e) {
|
547 | if (e.message.indexOf('>> 4| <%= qdata %>') > -1) {
|
548 | return;
|
549 | }
|
550 | throw e;
|
551 | }
|
552 | throw new Error('Expected ReferenceError');
|
553 | });
|
554 |
|
555 | test('works with unix style', function () {
|
556 | var content = '<ul><% -%>\n'
|
557 | + '<% users.forEach(function(user){ -%>\n'
|
558 | + '<li><%= user.name -%></li>\n'
|
559 | + '<% }) -%>\n'
|
560 | + '</ul><% -%>\n';
|
561 |
|
562 | var expectedResult = '<ul><li>geddy</li>\n<li>neil</li>\n<li>alex</li>\n</ul>';
|
563 | var fn;
|
564 | fn = ejs.compile(content);
|
565 | assert.equal(fn({users: users}),
|
566 | expectedResult);
|
567 | });
|
568 |
|
569 | test('works with windows style', function () {
|
570 | var content = '<ul><% -%>\r\n'
|
571 | + '<% users.forEach(function(user){ -%>\r\n'
|
572 | + '<li><%= user.name -%></li>\r\n'
|
573 | + '<% }) -%>\r\n'
|
574 | + '</ul><% -%>\r\n';
|
575 |
|
576 | var expectedResult = '<ul><li>geddy</li>\r\n<li>neil</li>\r\n<li>alex</li>\r\n</ul>';
|
577 | var fn;
|
578 | fn = ejs.compile(content);
|
579 | assert.equal(fn({users: users}),
|
580 | expectedResult);
|
581 | });
|
582 | });
|
583 |
|
584 | suite('<%%', function () {
|
585 | test('produce literals', function () {
|
586 | assert.equal(ejs.render('<%%- "foo" %>'),
|
587 | '<%- "foo" %>');
|
588 | });
|
589 | test('work without an end tag', function () {
|
590 | assert.equal(ejs.render('<%%'), '<%');
|
591 | assert.equal(ejs.render(fixture('literal.ejs'), {}, {delimiter: ' '}),
|
592 | fixture('literal.html'));
|
593 | });
|
594 | });
|
595 |
|
596 | suite('%%>', function () {
|
597 | test('produce literal', function () {
|
598 | assert.equal(ejs.render('%%>'),
|
599 | '%>');
|
600 | assert.equal(ejs.render(' >', {}, {delimiter: ' '}),
|
601 | ' >');
|
602 | });
|
603 | });
|
604 |
|
605 | suite('<%_ and _%>', function () {
|
606 | test('slurps spaces and tabs', function () {
|
607 | assert.equal(ejs.render(fixture('space-and-tab-slurp.ejs'), {users: users}),
|
608 | fixture('space-and-tab-slurp.html'));
|
609 | });
|
610 | });
|
611 |
|
612 | suite('single quotes', function () {
|
613 | test('not mess up the constructed function', function () {
|
614 | assert.equal(ejs.render(fixture('single-quote.ejs')),
|
615 | fixture('single-quote.html'));
|
616 | });
|
617 | });
|
618 |
|
619 | suite('double quotes', function () {
|
620 | test('not mess up the constructed function', function () {
|
621 | assert.equal(ejs.render(fixture('double-quote.ejs')),
|
622 | fixture('double-quote.html'));
|
623 | });
|
624 | });
|
625 |
|
626 | suite('backslashes', function () {
|
627 | test('escape', function () {
|
628 | assert.equal(ejs.render(fixture('backslash.ejs')),
|
629 | fixture('backslash.html'));
|
630 | });
|
631 | });
|
632 |
|
633 | suite('messed up whitespace', function () {
|
634 | test('work', function () {
|
635 | assert.equal(ejs.render(fixture('messed.ejs'), {users: users}),
|
636 | fixture('messed.html'));
|
637 | });
|
638 | });
|
639 |
|
640 | suite('exceptions', function () {
|
641 | test('produce useful stack traces', function () {
|
642 | try {
|
643 | ejs.render(fixture('error.ejs'), {}, {filename: 'error.ejs'});
|
644 | }
|
645 | catch (err) {
|
646 | assert.equal(err.path, 'error.ejs');
|
647 | assert.equal(err.stack.split('\n').slice(0, 8).join('\n'), fixture('error.out'));
|
648 | return;
|
649 | }
|
650 | throw new Error('no error reported when there should be');
|
651 | });
|
652 |
|
653 | test('not include fancy stack info if compileDebug is false', function () {
|
654 | try {
|
655 | ejs.render(fixture('error.ejs'), {}, {
|
656 | filename: 'error.ejs',
|
657 | compileDebug: false
|
658 | });
|
659 | }
|
660 | catch (err) {
|
661 | assert.ok(!err.path);
|
662 | assert.notEqual(err.stack.split('\n').slice(0, 8).join('\n'), fixture('error.out'));
|
663 | return;
|
664 | }
|
665 | throw new Error('no error reported when there should be');
|
666 | });
|
667 |
|
668 | var unhook = null;
|
669 | test('log JS source when debug is set', function (done) {
|
670 | var out = '';
|
671 | var needToExit = false;
|
672 | unhook = hook_stdio(process.stdout, function (str) {
|
673 | out += str;
|
674 | if (needToExit) {
|
675 | return;
|
676 | }
|
677 | if (out.indexOf('__output')) {
|
678 | needToExit = true;
|
679 | unhook();
|
680 | unhook = null;
|
681 | return done();
|
682 | }
|
683 | });
|
684 | ejs.render(fixture('hello-world.ejs'), {}, {debug: true});
|
685 | });
|
686 | teardown(function() {
|
687 | if (!unhook) {
|
688 | return;
|
689 | }
|
690 | unhook();
|
691 | unhook = null;
|
692 | });
|
693 | });
|
694 |
|
695 | suite('rmWhitespace', function () {
|
696 | test('works', function () {
|
697 | assert.equal(ejs.render(fixture('rmWhitespace.ejs'), {}, {rmWhitespace: true}),
|
698 | fixture('rmWhitespace.html'));
|
699 | });
|
700 | });
|
701 |
|
702 | suite('include()', function () {
|
703 | test('include ejs', function () {
|
704 | var file = 'test/fixtures/include-simple.ejs';
|
705 | assert.equal(ejs.render(fixture('include-simple.ejs'), {}, {filename: file}),
|
706 | fixture('include-simple.html'));
|
707 | });
|
708 |
|
709 | test('include ejs fails without `filename`', function () {
|
710 | try {
|
711 | ejs.render(fixture('include-simple.ejs'));
|
712 | }
|
713 | catch (err) {
|
714 | assert.ok(err.message.indexOf('requires the \'filename\' option') > -1);
|
715 | return;
|
716 | }
|
717 | throw new Error('expected inclusion error');
|
718 | });
|
719 |
|
720 | test('strips BOM', function () {
|
721 | assert.equal(
|
722 | ejs.render('<%- include("fixtures/includes/bom.ejs") %>',
|
723 | {}, {filename: path.join(__dirname, 'f.ejs')}),
|
724 | '<p>This is a file with BOM.</p>\n');
|
725 | });
|
726 |
|
727 | test('include ejs with locals', function () {
|
728 | var file = 'test/fixtures/include.ejs';
|
729 | assert.equal(ejs.render(fixture('include.ejs'), {pets: users}, {filename: file, delimiter: '@'}),
|
730 | fixture('include.html'));
|
731 | });
|
732 |
|
733 | test('include ejs with absolute path and locals', function () {
|
734 | var file = 'test/fixtures/include-abspath.ejs';
|
735 | assert.equal(ejs.render(fixture('include-abspath.ejs'),
|
736 | {dir: path.join(__dirname, 'fixtures'), pets: users, path: path},
|
737 | {filename: file, delimiter: '@'}),
|
738 | fixture('include.html'));
|
739 | });
|
740 |
|
741 | test('include ejs with set root path', function () {
|
742 | var file = 'test/fixtures/include-root.ejs';
|
743 | var viewsPath = path.join(__dirname, 'fixtures');
|
744 | assert.equal(ejs.render(fixture('include-root.ejs'), {pets: users}, {filename: file, delimiter: '@',root:viewsPath}),
|
745 | fixture('include.html'));
|
746 |
|
747 | });
|
748 |
|
749 | test('work when nested', function () {
|
750 | var file = 'test/fixtures/menu.ejs';
|
751 | assert.equal(ejs.render(fixture('menu.ejs'), {pets: users}, {filename: file}),
|
752 | fixture('menu.html'));
|
753 | });
|
754 |
|
755 | test('work with a variable path', function () {
|
756 | var file = 'test/fixtures/menu_var.ejs';
|
757 | var includePath = 'includes/menu-item';
|
758 | assert.equal(ejs.render(fixture('menu.ejs'), {pets: users, varPath: includePath}, {filename: file}),
|
759 | fixture('menu.html'));
|
760 | });
|
761 |
|
762 | test('include arbitrary files as-is', function () {
|
763 | var file = 'test/fixtures/include.css.ejs';
|
764 | assert.equal(ejs.render(fixture('include.css.ejs'), {pets: users}, {filename: file}),
|
765 | fixture('include.css.html'));
|
766 | });
|
767 |
|
768 | test('pass compileDebug to include', function () {
|
769 | var file = 'test/fixtures/include.ejs';
|
770 | var fn;
|
771 | fn = ejs.compile(fixture('include.ejs'), {
|
772 | filename: file,
|
773 | delimiter: '@',
|
774 | compileDebug: false
|
775 | });
|
776 | try {
|
777 |
|
778 | fn({foo: 'asdf'});
|
779 | }
|
780 | catch(e) {
|
781 | assert.equal(e.message, 'pets is not defined');
|
782 | assert.ok(!e.path);
|
783 | return;
|
784 | }
|
785 | throw new Error('no error reported when there should be');
|
786 | });
|
787 |
|
788 | test('is dynamic', function () {
|
789 | fs.writeFileSync(__dirname + '/tmp/include.ejs', '<p>Old</p>');
|
790 | var file = 'test/fixtures/include_cache.ejs';
|
791 | var options = {filename: file};
|
792 | var out = ejs.compile(fixture('include_cache.ejs'), options);
|
793 | assert.equal(out(), '<p>Old</p>\n');
|
794 |
|
795 | fs.writeFileSync(__dirname + '/tmp/include.ejs', '<p>New</p>');
|
796 | assert.equal(out(), '<p>New</p>\n');
|
797 | });
|
798 |
|
799 | test('support caching', function () {
|
800 | fs.writeFileSync(__dirname + '/tmp/include.ejs', '<p>Old</p>');
|
801 | var file = 'test/fixtures/include_cache.ejs';
|
802 | var options = {cache: true, filename: file};
|
803 | var out = ejs.render(fixture('include_cache.ejs'), {}, options);
|
804 | var expected = fixture('include_cache.html');
|
805 | assert.equal(out, expected);
|
806 | out = ejs.render(fixture('include_cache.ejs'), {}, options);
|
807 |
|
808 | assert.equal(out, expected);
|
809 | fs.writeFileSync(__dirname + '/tmp/include.ejs', '<p>New</p>');
|
810 | out = ejs.render(fixture('include_cache.ejs'), {}, options);
|
811 | assert.equal(out, expected);
|
812 | });
|
813 |
|
814 | });
|
815 |
|
816 | suite('preprocessor include', function () {
|
817 | test('work', function () {
|
818 | var file = 'test/fixtures/include_preprocessor.ejs';
|
819 | assert.equal(ejs.render(fixture('include_preprocessor.ejs'), {pets: users}, {filename: file, delimiter: '@'}),
|
820 | fixture('include_preprocessor.html'));
|
821 | });
|
822 |
|
823 | test('no false positives', function () {
|
824 | assert.equal(ejs.render('<% %> include foo <% %>'), ' include foo ');
|
825 | });
|
826 |
|
827 | test('fails without `filename`', function () {
|
828 | try {
|
829 | ejs.render(fixture('include_preprocessor.ejs'), {pets: users}, {delimiter: '@'});
|
830 | }
|
831 | catch (err) {
|
832 | assert.ok(err.message.indexOf('requires the \'filename\' option') > -1);
|
833 | return;
|
834 | }
|
835 | throw new Error('expected inclusion error');
|
836 | });
|
837 |
|
838 | test('strips BOM', function () {
|
839 | assert.equal(
|
840 | ejs.render('<% include fixtures/includes/bom.ejs %>',
|
841 | {}, {filename: path.join(__dirname, 'f.ejs')}),
|
842 | '<p>This is a file with BOM.</p>\n');
|
843 | });
|
844 |
|
845 | test('work when nested', function () {
|
846 | var file = 'test/fixtures/menu_preprocessor.ejs';
|
847 | assert.equal(ejs.render(fixture('menu_preprocessor.ejs'), {pets: users}, {filename: file}),
|
848 | fixture('menu_preprocessor.html'));
|
849 | });
|
850 |
|
851 | test('tracks dependency correctly', function () {
|
852 | var file = 'test/fixtures/menu_preprocessor.ejs';
|
853 | var fn = ejs.compile(fixture('menu_preprocessor.ejs'), {filename: file});
|
854 | assert(fn.dependencies.length);
|
855 | });
|
856 |
|
857 | test('include arbitrary files as-is', function () {
|
858 | var file = 'test/fixtures/include_preprocessor.css.ejs';
|
859 | assert.equal(ejs.render(fixture('include_preprocessor.css.ejs'), {pets: users}, {filename: file}),
|
860 | fixture('include_preprocessor.css.html'));
|
861 | });
|
862 |
|
863 | test('pass compileDebug to include', function () {
|
864 | var file = 'test/fixtures/include_preprocessor.ejs';
|
865 | var fn;
|
866 | fn = ejs.compile(fixture('include_preprocessor.ejs'), {
|
867 | filename: file,
|
868 | delimiter: '@',
|
869 | compileDebug: false
|
870 | });
|
871 | try {
|
872 |
|
873 | fn({foo: 'asdf'});
|
874 | }
|
875 | catch(e) {
|
876 | assert.equal(e.message, 'pets is not defined');
|
877 | assert.ok(!e.path);
|
878 | return;
|
879 | }
|
880 | throw new Error('no error reported when there should be');
|
881 | });
|
882 |
|
883 | test('is static', function () {
|
884 | fs.writeFileSync(__dirname + '/tmp/include_preprocessor.ejs', '<p>Old</p>');
|
885 | var file = 'test/fixtures/include_preprocessor_cache.ejs';
|
886 | var options = {filename: file};
|
887 | var out = ejs.compile(fixture('include_preprocessor_cache.ejs'), options);
|
888 | assert.equal(out(), '<p>Old</p>\n');
|
889 |
|
890 | fs.writeFileSync(__dirname + '/tmp/include_preprocessor.ejs', '<p>New</p>');
|
891 | assert.equal(out(), '<p>Old</p>\n');
|
892 | });
|
893 |
|
894 | test('support caching', function () {
|
895 | fs.writeFileSync(__dirname + '/tmp/include_preprocessor.ejs', '<p>Old</p>');
|
896 | var file = 'test/fixtures/include_preprocessor_cache.ejs';
|
897 | var options = {cache: true, filename: file};
|
898 | var out = ejs.render(fixture('include_preprocessor_cache.ejs'), {}, options);
|
899 | var expected = fixture('include_preprocessor_cache.html');
|
900 | assert.equal(out, expected);
|
901 | fs.writeFileSync(__dirname + '/tmp/include_preprocessor.ejs', '<p>New</p>');
|
902 | out = ejs.render(fixture('include_preprocessor_cache.ejs'), {}, options);
|
903 | assert.equal(out, expected);
|
904 | });
|
905 |
|
906 | test('whitespace slurp and rmWhitespace work', function() {
|
907 | var file = 'test/fixtures/include_preprocessor_line_slurp.ejs';
|
908 | var template = fixture('include_preprocessor_line_slurp.ejs');
|
909 | var expected = fixture('include_preprocessor_line_slurp.html');
|
910 | var options = {rmWhitespace: true, filename: file};
|
911 | assert.equal(ejs.render(template, options),
|
912 | expected);
|
913 | });
|
914 |
|
915 | });
|
916 |
|
917 | suite('comments', function () {
|
918 | test('fully render with comments removed', function () {
|
919 | assert.equal(ejs.render(fixture('comments.ejs')),
|
920 | fixture('comments.html'));
|
921 | });
|
922 | });
|
923 |
|
924 | suite('require', function () {
|
925 |
|
926 |
|
927 | test('allow ejs templates to be required as node modules', function () {
|
928 | var file = 'test/fixtures/include_preprocessor.ejs';
|
929 | var template = require(__dirname + '/fixtures/menu_preprocessor.ejs');
|
930 | if (!process.env.running_under_istanbul) {
|
931 | assert.equal(template({filename: file, pets: users}),
|
932 | fixture('menu_preprocessor.html'));
|
933 | }
|
934 | });
|
935 | });
|
936 |
|
937 | suite('examples', function () {
|
938 | function noop () {}
|
939 | fs.readdirSync('examples').forEach(function (f) {
|
940 | if (!/\.js$/.test(f)) {
|
941 | return;
|
942 | }
|
943 | suite(f, function () {
|
944 | test('doesn\'t throw any errors', function () {
|
945 | var stderr = hook_stdio(process.stderr, noop);
|
946 | var stdout = hook_stdio(process.stdout, noop);
|
947 | try {
|
948 | require('../examples/' + f);
|
949 | }
|
950 | catch (ex) {
|
951 | stdout();
|
952 | stderr();
|
953 | throw ex;
|
954 | }
|
955 | stdout();
|
956 | stderr();
|
957 | });
|
958 | });
|
959 | });
|
960 | });
|