Passed
Push — master ( beba88...91d9d9 )
by Björn
02:26
created

test/test.02.handlebars.js (2 issues)

1
import Patternlibrary from '..';
2
3
import equal from 'assert-dir-equal';
4
import rimraf from 'rimraf';
5
import mkdirp from 'mkdirp';
6
7
var expect = require('chai').expect;
8
var $handlebars = require('../lib/vendor/handlebars');
9
var stripHtml = require('striptags');
10
11
/**
12
 * Compares the output of a $handlebars template to an expected string. Data can also be passed to the template function.
13
 * @param {string} input - String to compile into a $handlebars template.
14
 * @param {string} expected - Expected output of the template.
15
 * @param {object} data - Data to pass to the $handlebars context.
16
 * @throws {AssertionError} Throws an error if the $handlebars output and expected output are not equal.
17
 */
18
function compare(input, expected, data) {
19
  var template = $handlebars.compile(input);
20
  expect(template(data || {})).to.equal(expected);
21
}
22
23
// A note about assertions: most of these tests use the `compare()` function 
24
// above. However, in cases where the output needs to be modified in some way 
25
// before it's compared, or in cases where a substring is being searched for, 
26
// a $handlebars template is created manually inside of the test.
27
28
describe('Patternlibrary built-in Handlebars helpers', () => {
29
30
	const FIXTURES = 'test/fixtures.staticpages/';
31
32
	const CLEAN_UP = !true;
33
34
	var patternlibraryOptions = {
35
	    verbose: false,
36
	    dest : FIXTURES + 'build',
37
	    root    : FIXTURES + 'pages/',
38
	    layouts : FIXTURES + 'layouts',
39
	    partials: FIXTURES + 'partials'
40
	}
41
	
42
	describe('Structural', () => {
43
44
		describe('{{#repeat}}{{/repeat}}', () => {
45
		    it('prints content multiple times', function (done) {
46
		    
47
		        patternlibraryOptions = {
48
		            verbose : false,
49
		            dest    : FIXTURES + 'helper-repeat/build',
50
		            root    : FIXTURES + 'helper-repeat/pages/',
51
		            layouts : FIXTURES + 'helper-repeat/layouts/',
52
		            partials: FIXTURES + 'helper-repeat/partials/',
53
		            nogui   : true,
54
		            testing : true
55
		        };
56
		        rimraf.sync(FIXTURES + 'helper-repeat/build'); mkdirp(FIXTURES + 'helper-repeat/build');
57
		        var p = new Patternlibrary.Patternlibrary(patternlibraryOptions);
58
		    
59
		        p.run();
60
		    
61
		        setTimeout( function () {
62
		            equal(FIXTURES + 'helper-repeat/expected/index.html', FIXTURES + 'helper-repeat/build/index.html');
63
		            if (CLEAN_UP) rimraf.sync(FIXTURES + 'helper-repeat/build');
64
		            done();
65
		        }, 250);
66
		    
67
		    });
68
	    });
69
70
	    describe('{{#ifEqual}}{{/ifEqual}}', () => {
71
		    it('compares two values', function (done) {
72
		    
73
		        patternlibraryOptions = {
74
		            verbose : false,
75
		            dest    : FIXTURES + 'helper-ifequal/build',
76
		            root    : FIXTURES + 'helper-ifequal/pages/',
77
		            layouts : FIXTURES + 'helper-ifequal/layouts/',
78
		            partials: FIXTURES + 'helper-ifequal/partials/',
79
		            nogui   : true,
80
		            testing : true
81
		        };
82
		        rimraf.sync(FIXTURES + 'helper-ifequal/build'); mkdirp(FIXTURES + 'helper-ifequal/build');
83
		        var p = new Patternlibrary.Patternlibrary(patternlibraryOptions);
84
		    
85
		        p.run();
86
		    
87
		        setTimeout( function () {
88
		            equal(FIXTURES + 'helper-ifequal/expected/index.html', FIXTURES + 'helper-ifequal/build/index.html');
89
		            if (CLEAN_UP) rimraf.sync(FIXTURES + 'helper-ifequal/build');
90
		            done();
91
		        }, 250);
92
		    
93
		    });
94
	    });
95
96 View Code Duplication
	    describe('{{#ifpage}}{{/ifpage}}', () => {
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
97
		    it('checks the current page', function (done) {
98
		    
99
		        patternlibraryOptions = {
100
		            verbose : false,
101
		            dest    : FIXTURES + 'helper-ifpage/build',
102
		            root    : FIXTURES + 'helper-ifpage/pages/',
103
		            layouts : FIXTURES + 'helper-ifpage/layouts/',
104
		            partials: FIXTURES + 'helper-ifpage/partials/',
105
		            nogui   : true,
106
		            testing : true
107
		        };
108
		        rimraf.sync(FIXTURES + 'helper-ifpage/build'); mkdirp(FIXTURES + 'helper-ifpage/build');
109
		        var p = new Patternlibrary.Patternlibrary(patternlibraryOptions);
110
		    
111
		        p.run();
112
		    
113
		        setTimeout( function () {
114
		            equal(FIXTURES + 'helper-ifpage/expected/index.html', FIXTURES + 'helper-ifpage/build/index.html');
115
		            equal(FIXTURES + 'helper-ifpage/expected/about.html', FIXTURES + 'helper-ifpage/build/about.html');
116
		            if (CLEAN_UP) rimraf.sync(FIXTURES + 'helper-ifpage/build');
117
		            done();
118
		        }, 250);
119
		    
120
		    });
121
	    });
122
123 View Code Duplication
	    describe('{{#unlesspage}}{{/unlesspage}}', () => {
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
124
		    it('checks the current page (negation of ifpage)', function (done) {
125
		    
126
		        patternlibraryOptions = {
127
		            verbose : false,
128
		            dest    : FIXTURES + 'helper-unlesspage/build',
129
		            root    : FIXTURES + 'helper-unlesspage/pages/',
130
		            layouts : FIXTURES + 'helper-unlesspage/layouts/',
131
		            partials: FIXTURES + 'helper-unlesspage/partials/',
132
		            nogui   : true,
133
		            testing : true
134
		        };
135
		        rimraf.sync(FIXTURES + 'helper-unlesspage/build'); mkdirp(FIXTURES + 'helper-unlesspage/build');
136
		        var p = new Patternlibrary.Patternlibrary(patternlibraryOptions);
137
		    
138
		        p.run();
139
		    
140
		        setTimeout( function () {
141
		            equal(FIXTURES + 'helper-unlesspage/expected/index.html', FIXTURES + 'helper-unlesspage/build/index.html');
142
		            equal(FIXTURES + 'helper-unlesspage/expected/about.html', FIXTURES + 'helper-unlesspage/build/about.html');
143
		            if (CLEAN_UP) rimraf.sync(FIXTURES + 'helper-unlesspage/build');
144
		            done();
145
		        }, 250);
146
		    
147
		    });
148
	    });
149
		
150
	});
151
152
	describe('Formatting', () => {
153
154
		describe('{{#code}}{{/code}}', () => {
155
		    it('renders code blocks', function (done) {
156
		    
157
		        patternlibraryOptions = {
158
		            verbose : false,
159
		            dest    : FIXTURES + 'helper-code/build',
160
		            root    : FIXTURES + 'helper-code/pages/',
161
		            layouts : FIXTURES + 'helper-code/layouts/',
162
		            partials: FIXTURES + 'helper-code/partials/',
163
		            nogui   : true,
164
		            testing : true
165
		        };
166
		        rimraf.sync(FIXTURES + 'helper-code/build'); mkdirp(FIXTURES + 'helper-code/build');
167
		        var p = new Patternlibrary.Patternlibrary(patternlibraryOptions);
168
		    
169
		        p.run();
170
		    
171
		        setTimeout( function () {
172
		            equal(FIXTURES + 'helper-code/expected/index.html', FIXTURES + 'helper-code/build/index.html');
173
		            if (CLEAN_UP) rimraf.sync(FIXTURES + 'helper-code/build');
174
		            done();
175
		        }, 250);
176
		    
177
		    });
178
        });
179
180
	    describe('{{#markdown}}{{/markdown}}', () => {
181
		    it('converts Markdown to HTML (block-helper)', function (done) {
182
		    
183
		        patternlibraryOptions = {
184
		            verbose : false,
185
		            dest    : FIXTURES + 'helper-markdown/build',
186
		            root    : FIXTURES + 'helper-markdown/pages/',
187
		            layouts : FIXTURES + 'helper-markdown/layouts/',
188
		            partials: FIXTURES + 'helper-markdown/partials/',
189
		            nogui   : true,
190
		            testing : true
191
		        };
192
		        rimraf.sync(FIXTURES + 'helper-markdown/build'); mkdirp(FIXTURES + 'helper-markdown/build');
193
		        var p = new Patternlibrary.Patternlibrary(patternlibraryOptions);
194
		    
195
		        p.run();
196
		    
197
		        setTimeout( function () {
198
		            equal(FIXTURES + 'helper-markdown/expected/index.html', FIXTURES + 'helper-markdown/build/index.html');
199
		            if (CLEAN_UP) rimraf.sync(FIXTURES + 'helper-markdown/build');
200
		            done();
201
		        }, 250);
202
		    
203
		    });
204
        });
205
	    
206
        describe('{{md}}', () => {
207
            it('converts Markdown to HTML', () => {
208
                compare('{{md "**Bold**"}}', '<p><strong>Bold</strong></p>\n');
209
            });
210
        });
211
    
212
        describe('{{#heading}}{{/heading}}', () => {
213
            it('creates a heading of a specific level', () => {
214
                var expected = '<h1 id="title" class="docs-heading">Title<a class="docs-heading-icon" href="#title"></a></h1>';
215
        
216
                compare('{{#heading 1}}Title{{/heading}}', expected);
217
            });
218
    
219
            it('creates a heading with a custom ID', () => {
220
                var expected = '<h1 id="custom" class="docs-heading">Title<a class="docs-heading-icon" href="#custom"></a></h1>';
221
        
222
                compare('{{#heading 1 "custom"}}Title{{/heading}}', expected);
223
            });
224
        });
225
    
226
        describe('{{escape}}', () => {
227
            it('escapes text for use in a URL hash', () => {
228
                compare('{{escape "this text"}}', 'this-text');
229
            });
230
        });
231
    
232
        describe('{{toUpper}}', () => {
233
            it('capitalizes the first letter of a string', () => {
234
                compare('{{toUpper "kittens"}}', 'Kittens');
235
            });
236
        });
237
    
238
        describe('{{toLower}}', () => {
239
            it('converts a string to lowercase', () => {
240
                compare('{{toLower "SHOUT"}}', 'shout')
241
            });
242
        });
243
    
244
        describe('{{raw}}{{/raw}}', () => {
245
            it('ignores $handlebars', () => {
246
                compare('{{{{raw}}}}{{ignore}}{{{{/raw}}}}', '{{ignore}}');
247
            });
248
        });
249
    
250
        describe('{{#filter}}{{/filter}}', () => {
251
            it('filters private SassDoc and JSDoc objects', () => {
252
                var data = {
253
                    item: { access: 'private' }
254
                };
255
        
256
                compare('{{#filter item}}Private{{/filter}}', '', data);
257
            });
258
    
259
            it('displays public SassDoc and JSDoc objects', () => {
260
                var data = {
261
                    item: { access: 'public' }
262
                };
263
        
264
                compare('{{#filter item}}Public{{/filter}}', 'Public', data);
265
            });
266
    
267
            it('filters SassDoc aliases', () => {
268
                var data = {
269
                    item: { alias: true }
270
                };
271
        
272
                compare('{{#filter item}}Alias{{/filter}}', '', data);
273
            });
274
        });
275
    });
276
277
    describe('JavaScript', () => {
278
        describe('{{writeJsConstructor}}', () => {
279
            it('prints formatted JavaScript code to initialize a Patternlibrary/Siteapp plugin', () => {
280
                var template = $handlebars.compile('{{writeJsConstructor "Plugin"}}');
281
                var output = template();
282
        
283
                expect(output, 'Should be formatted by Highlight.js').to.contain('hljs');
284
                expect(stripHtml(output), 'Should include Patternlibrary/Siteapp code').to.equal('var elem = new YourApp.Plugin(element, options);');
285
            });
286
        });
287
    
288
        describe('{{writeJsFunction}}', () => {
289
            it('prints a JavaScript function with no parameters', () => {
290
                var data = {
291
                    method: {
292
                        name: 'petKitty',
293
                        params: []
294
                    }
295
                };
296
        
297
                var template = $handlebars.compile('{{writeJsFunction method}}');
298
                var output = template(data);
299
        
300
                expect(stripHtml(output)).to.equal(`$('#element').your_app('petKitty');`);
301
            });
302
    
303
            it('prints a JavaScript function with parameters', () => {
304
                var data = {
305
                    method: {
306
                        name: 'petKitty',
307
                        params: [
308
                            { name: 'param1' },
309
                            { name: 'param2' }
310
                        ]
311
                    }
312
                };
313
        
314
                var template = $handlebars.compile('{{writeJsFunction method}}');
315
                var output = template(data);
316
        
317
                expect(stripHtml(output)).to.equal(`$('#element').your_app('petKitty', param1, param2);`);
318
            });
319
        });
320
    
321
        describe('{{formatJsModule}}', () => {
322
            it('converts a JSDoc module definition to a filename', () => {
323
                compare('{{formatJsModule "module:foundation.toggler"}}', 'foundation.toggler.js');
324
            });
325
        });
326
    
327
        describe('{{formatJsOptionName}}', () => {
328
            it('converts a plugin option name to an HTML data attribute', () => {
329
                compare('{{formatJsOptionName "optionName"}}', 'data-option-name');
330
            });
331
        });
332
    
333
        describe('{{formatJsOptionValue}}', () => {
334
            it('prints non-String values as-is', () => {
335
                var data = {
336
                    value: '0'
337
                };
338
        
339
                compare('{{formatJsOptionValue value}}', '0', data);
340
            });
341
    
342
            it('prints String values without the quotes on either side', () => {
343
                var data = {
344
                    singleQuotes: "'value'",
345
                    multiQuotes: '"value"'
346
                };
347
        
348
                compare(`{{formatJsOptionValue singleQuotes}}`, 'value', data);
349
                compare(`{{formatJsOptionValue multiQuotes}}`, 'value', data);
350
            });
351
    
352
            it('returns an empty string if an option is missing a value', () => {
353
                compare('{{formatJsOptionValue undef}}', '');
354
            });
355
        });
356
    
357
        describe('{{formatJsEventName}}', () => {
358
            it('formats a JSDoc event to look like "YourApp"-namespaced events', () => {
359
                var data = {
360
                    name: 'event',
361
                    title: 'Plugin'
362
                };
363
        
364
                compare('{{formatJsEventName name title}}', 'event.zf.plugin', data);
365
            });
366
    
367
            it('handles plugin names that are intercapped', () => {
368
                var data = {
369
                    name: 'event',
370
                    title: 'PluginName'
371
                };
372
        
373
                compare('{{formatJsEventName name title}}', 'event.zf.pluginName', data);
374
            });
375
        });
376
    });
377
378
    describe('Links', () => {
379
        describe('{{editLink}}', () => {
380
            it('generates a GitHub edit link point to a repository, branch, and file', () => {
381
                compare('{{editLink "foundation-sites" "master" "docs/pages/index.html"}}', 'https://github.com/zurb/foundation-sites/edit/master/docs/pages/index.md');
382
            });
383
        });
384
    
385
        describe('{{issueLink}}', () => {
386
            it('generates a GitHub link to open a new issue, with a preset title', () => {
387
                var template = $handlebars.compile('{{issueLink "foundation-sites" "Plugin"}}');
388
                var output = template();
389
        
390
                expect(output, 'links to GitHub issue tracker').to.contain('https://github.com/zurb/foundation-sites/issues/new?title');
391
                expect(output, 'includes tag in preset title').to.contain('Plugin');
392
                expect(output, 'includes super loud title that you should replace').to.contain('ISSUE%20NAME%20HERE');
393
            });
394
        });
395
    });
396
397
    describe('Sass', () => {
398
        describe('{{writeSassMixin}}', () => {
399
            it('formats a Sass mixin with no parameters', () => {
400
            var data = {
401
                mixin: {
402
                context: { name: 'name' }
403
                }
404
            };
405
    
406
            var template = $handlebars.compile('{{writeSassMixin mixin}}');
407
            var output = stripHtml(template(data));
408
    
409
            expect(output).to.equal('@include name;');
410
            });
411
    
412
            it('formats a Sass mixin with parameters', () => {
413
                var data = {
414
                    mixin: {
415
                        context: { name: 'name' },
416
                        parameter: [
417
                            { name: 'param1' },
418
                            { name: 'param2' }
419
                        ]
420
                    }
421
                };
422
        
423
                var template = $handlebars.compile('{{writeSassMixin mixin}}');
424
                var output = stripHtml(template(data));
425
        
426
                expect(output).to.equal('@include name($param1, $param2);');
427
            });
428
    
429
            it('formats a Sass mixin with a @content directive', () => {
430
                var data = {
431
                    mixin: {
432
                        context: { name: 'name' },
433
                        content: 'Content'
434
                    }
435
                };
436
        
437
                var template = $handlebars.compile('{{writeSassMixin mixin}}');
438
                var output = stripHtml(template(data));
439
        
440
                expect(output).to.equal('@include name { }');
441
            });
442
        });
443
    
444
        describe('{{writeSassFunction}}', () => {
445
            it('formats a Sass function with no parameters', () => {
446
                var data = {
447
                    func: {
448
                    context: { name: 'name' }
449
                    }
450
                };
451
        
452
                var template = $handlebars.compile('{{writeSassFunction func}}');
453
                var output = stripHtml(template(data));
454
        
455
                expect(output).to.equal('name()');
456
            });
457
    
458
            it('formats a Sass function with parameters', () => {
459
                var data = {
460
                    func: {
461
                    context: { name: 'name' },
462
                        parameter: [
463
                            { name: 'param1' },
464
                            { name: 'param2' }
465
                        ]
466
                    }
467
                };
468
        
469
                var template = $handlebars.compile('{{writeSassFunction func}}');
470
                var output = stripHtml(template(data));
471
        
472
                expect(output).to.equal('name($param1, $param2)');
473
            });
474
        });
475
    
476
        describe('{{writeSassVariable}}', () => {
477
            it('formats a Sass variable', () => {
478
                var data = {
479
                    variable: {
480
                    context: {
481
                        name: 'name',
482
                        value: 'value'
483
                    }
484
                    }
485
                };
486
        
487
                var template = $handlebars.compile('{{writeSassVariable variable}}');
488
                var output = stripHtml(template(data));
489
        
490
                expect(output).to.equal('$name: value;');
491
            });
492
        });
493
    
494
        describe('{{formatSassTypes}}', () => {
495
            it('formats a SassDoc @type annotation with one value', () => {
496
                compare('{{formatSassTypes "String"}}', 'String');
497
            });
498
    
499
            it('formats a SassDoc @type annotation with multiple values', () => {
500
                compare('{{formatSassTypes "String|List"}}', 'String or List');
501
            });
502
    
503
            it('prints an empty string if no value is defined', () => {
504
                compare('{{formatSassTypes undef}}', '');
505
            });
506
        });
507
    
508
        describe('{{formatSassValue}}', () => {
509
            it('formats basic values as-is', () => {
510
                compare('{{formatSassValue "value"}}', 'value');
511
            });
512
    
513
            it('formats maps with each value on a separate line', () => {
514
                var template = $handlebars.compile(`{{formatSassValue '(one: one,two: two)'}}`);
515
                var output = template();
516
        
517
                expect(output).to.equal('one: one&lt;br&gt;two: two');
518
            });
519
    
520
            it('returns the word "None" for undefined values', () => {
521
                var template = $handlebars.compile('{{formatSassValue undef}}');
522
                var output = template();
523
        
524
                expect(output).to.contain('None');
525
            });
526
        });
527
    
528
        describe('{{writeSassLink}}', () => {
529
            it('formats a SassDoc @link annotation', () => {
530
                var data = {
531
                    link: [{
532
                    url: '#',
533
                    caption: 'Caption'
534
                    }]
535
                };
536
        
537
                compare('{{writeSassLink link}}', '<p><strong>Learn more:</strong> <a href="#">Caption</a></p>', data);
538
            });
539
    
540
            it('prints an empty string for an undefined link', () => {
541
                compare('{{writeSassLink undef}}', '');
542
            });
543
        });
544
    });
545
});
546