summaryrefslogtreecommitdiffstats
path: root/spec/builtins.js
blob: bbe494e087941add72f90691f67a2e2025fbf5e1 (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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/*global CompilerContext, shouldCompileTo, compileWithPartials, handlebarsEnv */
describe('builtin helpers', function() {
  describe('#if', function() {
    it("if", function() {
      var string   = "{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!";
      shouldCompileTo(string, {goodbye: true, world: "world"}, "GOODBYE cruel world!",
                      "if with boolean argument shows the contents when true");
      shouldCompileTo(string, {goodbye: "dummy", world: "world"}, "GOODBYE cruel world!",
                      "if with string argument shows the contents");
      shouldCompileTo(string, {goodbye: false, world: "world"}, "cruel world!",
                      "if with boolean argument does not show the contents when false");
      shouldCompileTo(string, {world: "world"}, "cruel world!",
                      "if with undefined does not show the contents");
      shouldCompileTo(string, {goodbye: ['foo'], world: "world"}, "GOODBYE cruel world!",
                      "if with non-empty array shows the contents");
      shouldCompileTo(string, {goodbye: [], world: "world"}, "cruel world!",
                      "if with empty array does not show the contents");
      shouldCompileTo(string, {goodbye: 0, world: "world"}, "cruel world!",
                      "if with zero does not show the contents");
      shouldCompileTo("{{#if goodbye includeZero=true}}GOODBYE {{/if}}cruel {{world}}!",
                      {goodbye: 0, world: "world"}, "GOODBYE cruel world!",
                      "if with zero does not show the contents");
    });

    it("if with function argument", function() {
      var string   = "{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!";
      shouldCompileTo(string, {goodbye: function() {return true;}, world: "world"}, "GOODBYE cruel world!",
                      "if with function shows the contents when function returns true");
      shouldCompileTo(string, {goodbye: function() {return this.world;}, world: "world"}, "GOODBYE cruel world!",
                      "if with function shows the contents when function returns string");
      shouldCompileTo(string, {goodbye: function() {return false;}, world: "world"}, "cruel world!",
                      "if with function does not show the contents when returns false");
      shouldCompileTo(string, {goodbye: function() {return this.foo;}, world: "world"}, "cruel world!",
                      "if with function does not show the contents when returns undefined");
    });
  });

  describe('#with', function() {
    it("with", function() {
      var string = "{{#with person}}{{first}} {{last}}{{/with}}";
      shouldCompileTo(string, {person: {first: "Alan", last: "Johnson"}}, "Alan Johnson");
    });
    it("with with function argument", function() {
      var string = "{{#with person}}{{first}} {{last}}{{/with}}";
      shouldCompileTo(string, {person: function() { return {first: "Alan", last: "Johnson"};}}, "Alan Johnson");
    });
  });

  describe('#each', function() {
    beforeEach(function() {
      handlebarsEnv.registerHelper('detectDataInsideEach', function(options) {
        return options.data && options.data.exclaim;
      });
    });

    it("each", function() {
      var string   = "{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!";
      var hash     = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
      shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!",
                      "each with array argument iterates over the contents when not empty");
      shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
                      "each with array argument ignores the contents when empty");
    });

    it("each with an object and @key", function() {
      var string   = "{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!";
      var hash     = {goodbyes: {"<b>#1</b>": {text: "goodbye"}, 2: {text: "GOODBYE"}}, world: "world"};

      // Object property iteration order is undefined according to ECMA spec,
      // so we need to check both possible orders
      // @see http://stackoverflow.com/questions/280713/elements-order-in-a-for-in-loop
      var actual = compileWithPartials(string, hash);
      var expected1 = "&lt;b&gt;#1&lt;/b&gt;. goodbye! 2. GOODBYE! cruel world!";
      var expected2 = "2. GOODBYE! &lt;b&gt;#1&lt;/b&gt;. goodbye! cruel world!";

      equals(actual === expected1 || actual === expected2, true, "each with object argument iterates over the contents when not empty");
      shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
                      "each with object argument ignores the contents when empty");
    });

    it("each with @index", function() {
      var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}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("each with nested @index", function() {
      var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}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! 0 1 2 After 0 1. Goodbye! 0 1 2 After 1 2. GOODBYE! 0 1 2 After 2 cruel world!", "The @index variable is used");
    });

    it("each object with @index", function() {
      var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!";
      var hash   = {goodbyes: {'a': {text: "goodbye"}, b: {text: "Goodbye"}, c: {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("each with @first", function() {
      var string = "{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!";
      var hash   = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};

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

      equal(result, "goodbye! cruel world!", "The @first variable is used");
    });

    it("each with nested @first", function() {
      var string = "{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!";
      var hash   = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};

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

      equal(result, "(goodbye! goodbye! goodbye!) (goodbye!) (goodbye!) cruel world!", "The @first variable is used");
    });

    it("each object with @first", function() {
      var string = "{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!";
      var hash   = {goodbyes: {'foo': {text: "goodbye"}, bar: {text: "Goodbye"}}, world: "world"};

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

      equal(result, "goodbye! cruel world!", "The @first variable is used");
    });

    it("each with @last", function() {
      var string = "{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!";
      var hash   = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};

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

      equal(result, "GOODBYE! cruel world!", "The @last variable is used");
    });

    it("each with nested @last", function() {
      var string = "{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!";
      var hash   = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};

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

      equal(result, "(GOODBYE!) (GOODBYE!) (GOODBYE! GOODBYE! GOODBYE!) cruel world!", "The @last variable is used");
    });

    it("each with function argument", function() {
      var string = "{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!";
      var hash   = {goodbyes: function () { return [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}];}, world: "world"};
      shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!",
                "each with array function argument iterates over the contents when not empty");
      shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
                "each with array function argument ignores the contents when empty");
    });

    it("data passed to helpers", function() {
      var string = "{{#each letters}}{{this}}{{detectDataInsideEach}}{{/each}}";
      var hash = {letters: ['a', 'b', 'c']};

      var template = CompilerContext.compile(string);
      var result = template(hash, {
        data: {
          exclaim: '!'
        }
      });
      equal(result, 'a!b!c!', 'should output data');
    });

    it("each on implicit context", function() {
      var string   = "{{#each}}{{text}}! {{/each}}cruel world!";
      var hash     = [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}];
      shouldCompileTo(string, [hash], "goodbye! Goodbye! GOODBYE! cruel world!");
    });
  });

  it("#log", function() {
    var string = "{{log blah}}";
    var hash   = { blah: "whee" };

    var levelArg, logArg;
    handlebarsEnv.log = function(level, arg){
      levelArg = level;
      logArg = arg;
    };

    shouldCompileTo(string, hash, "", "log should not display");
    equals(1, levelArg, "should call log with 1");
    equals("whee", logArg, "should call log with 'whee'");
  });


  describe('#lookup', function() {
    it('should lookup arbitrary content', function() {
      var string = '{{#each goodbyes}}{{lookup ../data .}}{{/each}}',
          hash   = {goodbyes: [0, 1], data: ['foo', 'bar']};

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

      equal(result, 'foobar');
    });
    it('should not fail on undefined value', function() {
      var string = '{{#each goodbyes}}{{lookup ../bar .}}{{/each}}',
          hash   = {goodbyes: [0, 1], data: ['foo', 'bar']};

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

      equal(result, '');
    });
  });
});