summaryrefslogtreecommitdiffstats
path: root/spec/blocks.js
blob: 71c9045d2cf7ad662944c9b91fe755979fca3ac9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
describe('blocks', function() {
  it('array', function() {
    var string = '{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!';
    var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
    shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!',
                    'Arrays iterate over the contents when not empty');

    shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
                    'Arrays ignore the contents when empty');
  });

  it('array without data', function() {
    var string = '{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}';
    var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
    shouldCompileTo(string, [hash,,, false], 'goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE');
  });

  it('array with @index', function() {
    var string = '{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!';
    var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};

    var template = CompilerContext.compile(string);
    var result = template(hash);

    equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used');
  });

  it('empty block', function() {
    var string = '{{#goodbyes}}{{/goodbyes}}cruel {{world}}!';
    var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'};
    shouldCompileTo(string, hash, 'cruel world!',
                    'Arrays iterate over the contents when not empty');

    shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!',
                    'Arrays ignore the contents when empty');
  });

  it('block with complex lookup', function() {
    var string = '{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}';
    var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]};

    shouldCompileTo(string, hash, 'goodbye cruel Alan! Goodbye cruel Alan! GOODBYE cruel Alan! ',
                    'Templates can access variables in contexts up the stack with relative path syntax');
  });

  it('multiple blocks with complex lookup', function() {
    var string = '{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}';
    var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]};

    shouldCompileTo(string, hash, 'AlanAlanAlanAlanAlanAlan');
  });

  it('block with complex lookup using nested context', function() {
    var string = '{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}';

    shouldThrow(function() {
      CompilerContext.compile(string);
    }, Error);
  });

  it('block with deep nested complex lookup', function() {
    var string = '{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}';
    var hash = {omg: 'OMG!', outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }] };

    shouldCompileTo(string, hash, 'Goodbye cruel sad OMG!');
  });

  it('works with cached blocks', function() {
    var template = CompilerContext.compile('{{#each person}}{{#with .}}{{first}} {{last}}{{/with}}{{/each}}', {data: false});

    var result = template({person: [{first: 'Alan', last: 'Johnson'}, {first: 'Alan', last: 'Johnson'}]});
    equals(result, 'Alan JohnsonAlan Johnson');
  });

  describe('inverted sections', function() {
    it('inverted sections with unset value', function() {
      var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
      var hash = {};
      shouldCompileTo(string, hash, 'Right On!', "Inverted section rendered when value isn't set.");
    });

    it('inverted section with false value', function() {
      var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
      var hash = {goodbyes: false};
      shouldCompileTo(string, hash, 'Right On!', 'Inverted section rendered when value is false.');
    });

    it('inverted section with empty set', function() {
      var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}';
      var hash = {goodbyes: []};
      shouldCompileTo(string, hash, 'Right On!', 'Inverted section rendered when value is empty set.');
    });

    it('block inverted sections', function() {
      shouldCompileTo('{{#people}}{{name}}{{^}}{{none}}{{/people}}', {none: 'No people'},
        'No people');
    });
    it('chained inverted sections', function() {
      shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{/people}}', {none: 'No people'},
        'No people');
      shouldCompileTo('{{#people}}{{name}}{{else if nothere}}fail{{else unless nothere}}{{none}}{{/people}}', {none: 'No people'},
        'No people');
      shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{else}}fail{{/people}}', {none: 'No people'},
        'No people');
    });
    it('chained inverted sections with mismatch', function() {
      shouldThrow(function() {
        shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{/if}}', {none: 'No people'},
          'No people');
      }, Error);
    });

    it('block inverted sections with empty arrays', function() {
      shouldCompileTo('{{#people}}{{name}}{{^}}{{none}}{{/people}}', {none: 'No people', people: []},
        'No people');
    });
  });

  describe('standalone sections', function() {
    it('block standalone else sections', function() {
      shouldCompileTo('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n', {none: 'No people'},
        'No people\n');
      shouldCompileTo('{{#none}}\n{{.}}\n{{^}}\n{{none}}\n{{/none}}\n', {none: 'No people'},
        'No people\n');
      shouldCompileTo('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n', {none: 'No people'},
        'No people\n');
    });
    it('block standalone else sections can be disabled', function() {
      shouldCompileTo(
        '{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n',
        [{none: 'No people'}, {}, {}, {ignoreStandalone: true}],
        '\nNo people\n\n');
      shouldCompileTo(
        '{{#none}}\n{{.}}\n{{^}}\nFail\n{{/none}}\n',
        [{none: 'No people'}, {}, {}, {ignoreStandalone: true}],
        '\nNo people\n\n');
    });
    it('block standalone chained else sections', function() {
      shouldCompileTo('{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{/people}}\n', {none: 'No people'},
        'No people\n');
      shouldCompileTo('{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{^}}\n{{/people}}\n', {none: 'No people'},
        'No people\n');
    });
    it('should handle nesting', function() {
      shouldCompileTo('{{#data}}\n{{#if true}}\n{{.}}\n{{/if}}\n{{/data}}\nOK.', {data: [1, 3, 5]}, '1\n3\n5\nOK.');
    });
  });

  describe('compat mode', function() {
    it('block with deep recursive lookup lookup', function() {
      var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}';
      var hash = {omg: 'OMG!', outer: [{ inner: [{ text: 'goodbye' }] }] };

      shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel OMG!');
    });
    it('block with deep recursive pathed lookup', function() {
      var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
      var hash = {omg: {yes: 'OMG!'}, outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] };

      shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel OMG!');
    });
    it('block with missed recursive lookup', function() {
      var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}';
      var hash = {omg: {no: 'OMG!'}, outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] };

      shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel ');
    });
  });
});