Skip to content

Commit 77825f8

Browse files
authoredMay 4, 2020
refator: In spec tests, use expectTemplate over equals and shouldThrow (#1683)
1 parent 3789a30 commit 77825f8

17 files changed

+3350
-4124
lines changed
 

‎spec/basic.js

+389-401
Large diffs are not rendered by default.

‎spec/blocks.js

+288-337
Large diffs are not rendered by default.

‎spec/builtins.js

+447-443
Large diffs are not rendered by default.

‎spec/data.js

+158-244
Large diffs are not rendered by default.

‎spec/env/common.js

+40-7
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ function HandlebarsTestBench(templateAsString) {
129129
this.templateAsString = templateAsString;
130130
this.helpers = {};
131131
this.partials = {};
132+
this.decorators = {};
132133
this.input = {};
133134
this.message =
134135
'Template' + templateAsString + ' does not evaluate to expected output';
@@ -146,11 +147,43 @@ HandlebarsTestBench.prototype.withHelper = function(name, helperFunction) {
146147
return this;
147148
};
148149

150+
HandlebarsTestBench.prototype.withHelpers = function(helperFunctions) {
151+
var self = this;
152+
Object.keys(helperFunctions).forEach(function(name) {
153+
self.withHelper(name, helperFunctions[name]);
154+
});
155+
return this;
156+
};
157+
149158
HandlebarsTestBench.prototype.withPartial = function(name, partialAsString) {
150159
this.partials[name] = partialAsString;
151160
return this;
152161
};
153162

163+
HandlebarsTestBench.prototype.withPartials = function(partials) {
164+
var self = this;
165+
Object.keys(partials).forEach(function(name) {
166+
self.withPartial(name, partials[name]);
167+
});
168+
return this;
169+
};
170+
171+
HandlebarsTestBench.prototype.withDecorator = function(
172+
name,
173+
decoratorFunction
174+
) {
175+
this.decorators[name] = decoratorFunction;
176+
return this;
177+
};
178+
179+
HandlebarsTestBench.prototype.withDecorators = function(decorators) {
180+
var self = this;
181+
Object.keys(decorators).forEach(function(name) {
182+
self.withDecorator(name, decorators[name]);
183+
});
184+
return this;
185+
};
186+
154187
HandlebarsTestBench.prototype.withCompileOptions = function(compileOptions) {
155188
this.compileOptions = compileOptions;
156189
return this;
@@ -167,19 +200,18 @@ HandlebarsTestBench.prototype.withMessage = function(message) {
167200
};
168201

169202
HandlebarsTestBench.prototype.toCompileTo = function(expectedOutputAsString) {
170-
expect(this._compileAndExecute()).to.equal(expectedOutputAsString);
203+
expect(this._compileAndExecute()).to.equal(
204+
expectedOutputAsString,
205+
this.message
206+
);
171207
};
172208

173209
// see chai "to.throw" (https://www.chaijs.com/api/bdd/#method_throw)
174-
HandlebarsTestBench.prototype.toThrow = function(
175-
errorLike,
176-
errMsgMatcher,
177-
msg
178-
) {
210+
HandlebarsTestBench.prototype.toThrow = function(errorLike, errMsgMatcher) {
179211
var self = this;
180212
expect(function() {
181213
self._compileAndExecute();
182-
}).to.throw(errorLike, errMsgMatcher, msg);
214+
}).to.throw(errorLike, errMsgMatcher, this.message);
183215
};
184216

185217
HandlebarsTestBench.prototype._compileAndExecute = function() {
@@ -202,5 +234,6 @@ HandlebarsTestBench.prototype._combineRuntimeOptions = function() {
202234
});
203235
combinedRuntimeOptions.helpers = this.helpers;
204236
combinedRuntimeOptions.partials = this.partials;
237+
combinedRuntimeOptions.decorators = this.decorators;
205238
return combinedRuntimeOptions;
206239
};

‎spec/helpers.js

+520-815
Large diffs are not rendered by default.

‎spec/javascript-compiler.js

+15-5
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,18 @@ describe('javascript-compiler api', function() {
2020
return parent + '.bar_' + name;
2121
};
2222
/* eslint-disable camelcase */
23-
shouldCompileTo('{{foo}}', { bar_foo: 'food' }, 'food');
23+
expectTemplate('{{foo}}')
24+
.withInput({ bar_foo: 'food' })
25+
.toCompileTo('food');
2426
/* eslint-enable camelcase */
2527
});
2628

2729
// Tests nameLookup dot vs. bracket behavior. Bracket is required in certain cases
2830
// to avoid errors in older browsers.
2931
it('should handle reserved words', function() {
30-
shouldCompileTo('{{foo}} {{~null~}}', { foo: 'food' }, 'food');
32+
expectTemplate('{{foo}} {{~null~}}')
33+
.withInput({ foo: 'food' })
34+
.toCompileTo('food');
3135
});
3236
});
3337
describe('#compilerInfo', function() {
@@ -49,7 +53,9 @@ describe('javascript-compiler api', function() {
4953
throw new Error("It didn't work");
5054
}
5155
};
52-
shouldCompileTo('{{foo}} ', { foo: 'food' }, 'food ');
56+
expectTemplate('{{foo}} ')
57+
.withInput({ foo: 'food' })
58+
.toCompileTo('food ');
5359
});
5460
});
5561
describe('buffer', function() {
@@ -70,15 +76,19 @@ describe('javascript-compiler api', function() {
7076
handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer = function() {
7177
return this.quotedString('foo_');
7278
};
73-
shouldCompileTo('{{foo}} ', { foo: 'food' }, 'foo_food ');
79+
expectTemplate('{{foo}} ')
80+
.withInput({ foo: 'food' })
81+
.toCompileTo('foo_food ');
7482
});
7583
it('should allow append buffer override', function() {
7684
handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = function(
7785
string
7886
) {
7987
return $superAppend.call(this, [string, ' + "_foo"']);
8088
};
81-
shouldCompileTo('{{foo}}', { foo: 'food' }, 'food_foo');
89+
expectTemplate('{{foo}}')
90+
.withInput({ foo: 'food' })
91+
.toCompileTo('food_foo');
8292
});
8393
});
8494

‎spec/partials.js

+442-606
Large diffs are not rendered by default.

‎spec/regressions.js

+217-244
Large diffs are not rendered by default.

‎spec/security.js

+22-44
Original file line numberDiff line numberDiff line change
@@ -20,36 +20,19 @@ describe('security issues', function() {
2020
});
2121

2222
it('should allow the "constructor" property to be accessed if it is an "ownProperty"', function() {
23-
shouldCompileTo(
24-
'{{constructor.name}}',
25-
{
26-
constructor: {
27-
name: 'here we go'
28-
}
29-
},
30-
'here we go'
31-
);
32-
shouldCompileTo(
33-
'{{lookup (lookup this "constructor") "name"}}',
34-
{
35-
constructor: {
36-
name: 'here we go'
37-
}
38-
},
39-
'here we go'
40-
);
23+
expectTemplate('{{constructor.name}}')
24+
.withInput({ constructor: { name: 'here we go' } })
25+
.toCompileTo('here we go');
26+
27+
expectTemplate('{{lookup (lookup this "constructor") "name"}}')
28+
.withInput({ constructor: { name: 'here we go' } })
29+
.toCompileTo('here we go');
4130
});
4231

4332
it('should allow the "constructor" property to be accessed if it is an "own property"', function() {
44-
shouldCompileTo(
45-
'{{lookup (lookup this "constructor") "name"}}',
46-
{
47-
constructor: {
48-
name: 'here we go'
49-
}
50-
},
51-
'here we go'
52-
);
33+
expectTemplate('{{lookup (lookup this "constructor") "name"}}')
34+
.withInput({ constructor: { name: 'here we go' } })
35+
.toCompileTo('here we go');
5336
});
5437
});
5538

@@ -60,19 +43,13 @@ describe('security issues', function() {
6043

6144
describe('without the option "allowExplicitCallOfHelperMissing"', function() {
6245
it('should throw an exception when calling "{{helperMissing}}" ', function() {
63-
shouldThrow(function() {
64-
var template = Handlebars.compile('{{helperMissing}}');
65-
template({});
66-
}, Error);
46+
expectTemplate('{{helperMissing}}').toThrow(Error);
6747
});
48+
6849
it('should throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function() {
69-
shouldThrow(function() {
70-
var template = Handlebars.compile(
71-
'{{#helperMissing}}{{/helperMissing}}'
72-
);
73-
template({});
74-
}, Error);
50+
expectTemplate('{{#helperMissing}}{{/helperMissing}}').toThrow(Error);
7551
});
52+
7653
it('should throw an exception when calling "{{blockHelperMissing "abc" .}}" ', function() {
7754
var functionCalls = [];
7855
expect(function() {
@@ -85,17 +62,15 @@ describe('security issues', function() {
8562
}).to.throw(Error);
8663
expect(functionCalls.length).to.equal(0);
8764
});
65+
8866
it('should throw an exception when calling "{{#blockHelperMissing .}}{{/blockHelperMissing}}"', function() {
89-
shouldThrow(function() {
90-
var template = Handlebars.compile(
91-
'{{#blockHelperMissing .}}{{/blockHelperMissing}}'
92-
);
93-
template({
67+
expectTemplate('{{#blockHelperMissing .}}{{/blockHelperMissing}}')
68+
.withInput({
9469
fn: function() {
9570
return 'functionInData';
9671
}
97-
});
98-
}, Error);
72+
})
73+
.toThrow(Error);
9974
});
10075
});
10176

@@ -104,12 +79,14 @@ describe('security issues', function() {
10479
var template = Handlebars.compile('{{helperMissing}}');
10580
template({}, { allowCallsToHelperMissing: true });
10681
});
82+
10783
it('should not throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function() {
10884
var template = Handlebars.compile(
10985
'{{#helperMissing}}{{/helperMissing}}'
11086
);
11187
template({}, { allowCallsToHelperMissing: true });
11288
});
89+
11390
it('should not throw an exception when calling "{{blockHelperMissing "abc" .}}" ', function() {
11491
var functionCalls = [];
11592
var template = Handlebars.compile('{{blockHelperMissing "abc" .}}');
@@ -123,6 +100,7 @@ describe('security issues', function() {
123100
);
124101
equals(functionCalls.length, 1);
125102
});
103+
126104
it('should not throw an exception when calling "{{#blockHelperMissing .}}{{/blockHelperMissing}}"', function() {
127105
var template = Handlebars.compile(
128106
'{{#blockHelperMissing true}}sdads{{/blockHelperMissing}}'

‎spec/spec.js

+6-16
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,12 @@ describe('spec', function() {
4040
/* eslint-enable no-eval */
4141
}
4242
it(name + ' - ' + test.name, function() {
43-
if (test.partials) {
44-
shouldCompileToWithPartials(
45-
test.template,
46-
[data, {}, test.partials, true],
47-
true,
48-
test.expected,
49-
test.desc + ' "' + test.template + '"'
50-
);
51-
} else {
52-
shouldCompileTo(
53-
test.template,
54-
[data, {}, {}, true],
55-
test.expected,
56-
test.desc + ' "' + test.template + '"'
57-
);
58-
}
43+
expectTemplate(test.template)
44+
.withInput(data)
45+
.withPartials(test.partials || {})
46+
.withCompileOptions({ compat: true })
47+
.withMessage(test.desc + ' "' + test.template + '"')
48+
.toCompileTo(test.expected);
5949
});
6050
});
6151
});

‎spec/strict.js

+98-164
Original file line numberDiff line numberDiff line change
@@ -3,161 +3,107 @@ var Exception = Handlebars.Exception;
33
describe('strict', function() {
44
describe('strict mode', function() {
55
it('should error on missing property lookup', function() {
6-
shouldThrow(
7-
function() {
8-
var template = CompilerContext.compile('{{hello}}', { strict: true });
9-
10-
template({});
11-
},
12-
Exception,
13-
/"hello" not defined in/
14-
);
6+
expectTemplate('{{hello}}')
7+
.withCompileOptions({ strict: true })
8+
.toThrow(Exception, /"hello" not defined in/);
159
});
10+
1611
it('should error on missing child', function() {
17-
var template = CompilerContext.compile('{{hello.bar}}', { strict: true });
18-
equals(template({ hello: { bar: 'foo' } }), 'foo');
12+
expectTemplate('{{hello.bar}}')
13+
.withCompileOptions({ strict: true })
14+
.withInput({ hello: { bar: 'foo' } })
15+
.toCompileTo('foo');
1916

20-
shouldThrow(
21-
function() {
22-
template({ hello: {} });
23-
},
24-
Exception,
25-
/"bar" not defined in/
26-
);
17+
expectTemplate('{{hello.bar}}')
18+
.withCompileOptions({ strict: true })
19+
.withInput({ hello: {} })
20+
.toThrow(Exception, /"bar" not defined in/);
2721
});
28-
it('should handle explicit undefined', function() {
29-
var template = CompilerContext.compile('{{hello.bar}}', { strict: true });
3022

31-
equals(template({ hello: { bar: undefined } }), '');
23+
it('should handle explicit undefined', function() {
24+
expectTemplate('{{hello.bar}}')
25+
.withCompileOptions({ strict: true })
26+
.withInput({ hello: { bar: undefined } })
27+
.toCompileTo('');
3228
});
29+
3330
it('should error on missing property lookup in known helpers mode', function() {
34-
shouldThrow(
35-
function() {
36-
var template = CompilerContext.compile('{{hello}}', {
37-
strict: true,
38-
knownHelpersOnly: true
39-
});
40-
41-
template({});
42-
},
43-
Exception,
44-
/"hello" not defined in/
45-
);
31+
expectTemplate('{{hello}}')
32+
.withCompileOptions({
33+
strict: true,
34+
knownHelpersOnly: true
35+
})
36+
.toThrow(Exception, /"hello" not defined in/);
4637
});
47-
it('should error on missing context', function() {
48-
shouldThrow(function() {
49-
var template = CompilerContext.compile('{{hello}}', { strict: true });
5038

51-
template();
52-
}, Error);
39+
it('should error on missing context', function() {
40+
expectTemplate('{{hello}}')
41+
.withCompileOptions({ strict: true })
42+
.toThrow(Error);
5343
});
5444

5545
it('should error on missing data lookup', function() {
56-
var template = CompilerContext.compile('{{@hello}}', { strict: true });
57-
equals(template(undefined, { data: { hello: 'foo' } }), 'foo');
46+
var xt = expectTemplate('{{@hello}}').withCompileOptions({
47+
strict: true
48+
});
5849

59-
shouldThrow(function() {
60-
template();
61-
}, Error);
50+
xt.toThrow(Error);
51+
52+
xt.withRuntimeOptions({ data: { hello: 'foo' } }).toCompileTo('foo');
6253
});
6354

6455
it('should not run helperMissing for helper calls', function() {
65-
shouldThrow(
66-
function() {
67-
var template = CompilerContext.compile('{{hello foo}}', {
68-
strict: true
69-
});
70-
71-
template({ foo: true });
72-
},
73-
Exception,
74-
/"hello" not defined in/
75-
);
76-
77-
shouldThrow(
78-
function() {
79-
var template = CompilerContext.compile('{{#hello foo}}{{/hello}}', {
80-
strict: true
81-
});
82-
83-
template({ foo: true });
84-
},
85-
Exception,
86-
/"hello" not defined in/
87-
);
56+
expectTemplate('{{hello foo}}')
57+
.withCompileOptions({ strict: true })
58+
.withInput({ foo: true })
59+
.toThrow(Exception, /"hello" not defined in/);
60+
61+
expectTemplate('{{#hello foo}}{{/hello}}')
62+
.withCompileOptions({ strict: true })
63+
.withInput({ foo: true })
64+
.toThrow(Exception, /"hello" not defined in/);
8865
});
66+
8967
it('should throw on ambiguous blocks', function() {
90-
shouldThrow(
91-
function() {
92-
var template = CompilerContext.compile('{{#hello}}{{/hello}}', {
93-
strict: true
94-
});
95-
96-
template({});
97-
},
98-
Exception,
99-
/"hello" not defined in/
100-
);
101-
102-
shouldThrow(
103-
function() {
104-
var template = CompilerContext.compile('{{^hello}}{{/hello}}', {
105-
strict: true
106-
});
107-
108-
template({});
109-
},
110-
Exception,
111-
/"hello" not defined in/
112-
);
113-
114-
shouldThrow(
115-
function() {
116-
var template = CompilerContext.compile(
117-
'{{#hello.bar}}{{/hello.bar}}',
118-
{ strict: true }
119-
);
120-
121-
template({ hello: {} });
122-
},
123-
Exception,
124-
/"bar" not defined in/
125-
);
68+
expectTemplate('{{#hello}}{{/hello}}')
69+
.withCompileOptions({ strict: true })
70+
.toThrow(Exception, /"hello" not defined in/);
71+
72+
expectTemplate('{{^hello}}{{/hello}}')
73+
.withCompileOptions({ strict: true })
74+
.toThrow(Exception, /"hello" not defined in/);
75+
76+
expectTemplate('{{#hello.bar}}{{/hello.bar}}')
77+
.withCompileOptions({ strict: true })
78+
.withInput({ hello: {} })
79+
.toThrow(Exception, /"bar" not defined in/);
12680
});
12781

12882
it('should allow undefined parameters when passed to helpers', function() {
129-
var template = CompilerContext.compile(
130-
'{{#unless foo}}success{{/unless}}',
131-
{ strict: true }
132-
);
133-
equals(template({}), 'success');
83+
expectTemplate('{{#unless foo}}success{{/unless}}')
84+
.withCompileOptions({ strict: true })
85+
.toCompileTo('success');
13486
});
13587

13688
it('should allow undefined hash when passed to helpers', function() {
137-
var template = CompilerContext.compile('{{helper value=@foo}}', {
138-
strict: true
139-
});
140-
var helpers = {
141-
helper: function(options) {
142-
equals('value' in options.hash, true);
143-
equals(options.hash.value, undefined);
144-
return 'success';
145-
}
146-
};
147-
equals(template({}, { helpers: helpers }), 'success');
89+
expectTemplate('{{helper value=@foo}}')
90+
.withCompileOptions({
91+
strict: true
92+
})
93+
.withHelpers({
94+
helper: function(options) {
95+
equals('value' in options.hash, true);
96+
equals(options.hash.value, undefined);
97+
return 'success';
98+
}
99+
})
100+
.toCompileTo('success');
148101
});
149102

150103
it('should show error location on missing property lookup', function() {
151-
shouldThrow(
152-
function() {
153-
var template = CompilerContext.compile('\n\n\n {{hello}}', {
154-
strict: true
155-
});
156-
template({});
157-
},
158-
Exception,
159-
'"hello" not defined in [object Object] - 4:5'
160-
);
104+
expectTemplate('\n\n\n {{hello}}')
105+
.withCompileOptions({ strict: true })
106+
.toThrow(Exception, '"hello" not defined in [object Object] - 4:5');
161107
});
162108

163109
it('should error contains correct location properties on missing property lookup', function() {
@@ -177,54 +123,42 @@ describe('strict', function() {
177123

178124
describe('assume objects', function() {
179125
it('should ignore missing property', function() {
180-
var template = CompilerContext.compile('{{hello}}', {
181-
assumeObjects: true
182-
});
183-
184-
equal(template({}), '');
126+
expectTemplate('{{hello}}')
127+
.withCompileOptions({ assumeObjects: true })
128+
.toCompileTo('');
185129
});
186-
it('should ignore missing child', function() {
187-
var template = CompilerContext.compile('{{hello.bar}}', {
188-
assumeObjects: true
189-
});
190130

191-
equal(template({ hello: {} }), '');
131+
it('should ignore missing child', function() {
132+
expectTemplate('{{hello.bar}}')
133+
.withCompileOptions({ assumeObjects: true })
134+
.withInput({ hello: {} })
135+
.toCompileTo('');
192136
});
193-
it('should error on missing object', function() {
194-
shouldThrow(function() {
195-
var template = CompilerContext.compile('{{hello.bar}}', {
196-
assumeObjects: true
197-
});
198137

199-
template({});
200-
}, Error);
138+
it('should error on missing object', function() {
139+
expectTemplate('{{hello.bar}}')
140+
.withCompileOptions({ assumeObjects: true })
141+
.toThrow(Error);
201142
});
202-
it('should error on missing context', function() {
203-
shouldThrow(function() {
204-
var template = CompilerContext.compile('{{hello}}', {
205-
assumeObjects: true
206-
});
207143

208-
template();
209-
}, Error);
144+
it('should error on missing context', function() {
145+
expectTemplate('{{hello}}')
146+
.withCompileOptions({ assumeObjects: true })
147+
.withInput(undefined)
148+
.toThrow(Error);
210149
});
211150

212151
it('should error on missing data lookup', function() {
213-
shouldThrow(function() {
214-
var template = CompilerContext.compile('{{@hello.bar}}', {
215-
assumeObjects: true
216-
});
217-
218-
template();
219-
}, Error);
152+
expectTemplate('{{@hello.bar}}')
153+
.withCompileOptions({ assumeObjects: true })
154+
.withInput(undefined)
155+
.toThrow(Error);
220156
});
221157

222158
it('should execute blockHelperMissing', function() {
223-
var template = CompilerContext.compile('{{^hello}}foo{{/hello}}', {
224-
assumeObjects: true
225-
});
226-
227-
equals(template({}), 'foo');
159+
expectTemplate('{{^hello}}foo{{/hello}}')
160+
.withCompileOptions({ assumeObjects: true })
161+
.toCompileTo('foo');
228162
});
229163
});
230164
});

‎spec/string-params.js

+154-193
Original file line numberDiff line numberDiff line change
@@ -1,151 +1,117 @@
11
describe('string params mode', function() {
22
it('arguments to helpers can be retrieved from options hash in string form', function() {
3-
var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {
4-
stringParams: true
5-
});
6-
7-
var helpers = {
8-
wycats: function(passiveVoice, noun) {
9-
return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun;
10-
}
11-
};
12-
13-
var result = template({}, { helpers: helpers });
14-
15-
equals(
16-
result,
17-
'HELP ME MY BOSS is.a slave.driver',
18-
'String parameters output'
19-
);
3+
expectTemplate('{{wycats is.a slave.driver}}')
4+
.withCompileOptions({
5+
stringParams: true
6+
})
7+
.withHelpers({
8+
wycats: function(passiveVoice, noun) {
9+
return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun;
10+
}
11+
})
12+
.withMessage('String parameters output')
13+
.toCompileTo('HELP ME MY BOSS is.a slave.driver');
2014
});
2115

2216
it('when using block form, arguments to helpers can be retrieved from options hash in string form', function() {
23-
var template = CompilerContext.compile(
24-
'{{#wycats is.a slave.driver}}help :({{/wycats}}',
25-
{ stringParams: true }
26-
);
27-
28-
var helpers = {
29-
wycats: function(passiveVoice, noun, options) {
30-
return (
31-
'HELP ME MY BOSS ' +
32-
passiveVoice +
33-
' ' +
34-
noun +
35-
': ' +
36-
options.fn(this)
37-
);
38-
}
39-
};
40-
41-
var result = template({}, { helpers: helpers });
42-
43-
equals(
44-
result,
45-
'HELP ME MY BOSS is.a slave.driver: help :(',
46-
'String parameters output'
47-
);
17+
expectTemplate('{{#wycats is.a slave.driver}}help :({{/wycats}}')
18+
.withCompileOptions({
19+
stringParams: true
20+
})
21+
.withHelpers({
22+
wycats: function(passiveVoice, noun, options) {
23+
return (
24+
'HELP ME MY BOSS ' +
25+
passiveVoice +
26+
' ' +
27+
noun +
28+
': ' +
29+
options.fn(this)
30+
);
31+
}
32+
})
33+
.withMessage('String parameters output')
34+
.toCompileTo('HELP ME MY BOSS is.a slave.driver: help :(');
4835
});
4936

5037
it('when inside a block in String mode, .. passes the appropriate context in the options hash', function() {
51-
var template = CompilerContext.compile(
52-
'{{#with dale}}{{tomdale ../need dad.joke}}{{/with}}',
53-
{ stringParams: true }
54-
);
55-
56-
var helpers = {
57-
tomdale: function(desire, noun, options) {
58-
return (
59-
'STOP ME FROM READING HACKER NEWS I ' +
60-
options.contexts[0][desire] +
61-
' ' +
62-
noun
63-
);
64-
},
65-
66-
with: function(context, options) {
67-
return options.fn(options.contexts[0][context]);
68-
}
69-
};
70-
71-
var result = template(
72-
{
38+
expectTemplate('{{#with dale}}{{tomdale ../need dad.joke}}{{/with}}')
39+
.withCompileOptions({
40+
stringParams: true
41+
})
42+
.withHelpers({
43+
tomdale: function(desire, noun, options) {
44+
return (
45+
'STOP ME FROM READING HACKER NEWS I ' +
46+
options.contexts[0][desire] +
47+
' ' +
48+
noun
49+
);
50+
},
51+
with: function(context, options) {
52+
return options.fn(options.contexts[0][context]);
53+
}
54+
})
55+
.withInput({
7356
dale: {},
7457

7558
need: 'need-a'
76-
},
77-
{ helpers: helpers }
78-
);
79-
80-
equals(
81-
result,
82-
'STOP ME FROM READING HACKER NEWS I need-a dad.joke',
83-
'Proper context variable output'
84-
);
59+
})
60+
.withMessage('Proper context variable output')
61+
.toCompileTo('STOP ME FROM READING HACKER NEWS I need-a dad.joke');
8562
});
8663

8764
it('information about the types is passed along', function() {
88-
var template = CompilerContext.compile(
89-
"{{tomdale 'need' dad.joke true false}}",
90-
{ stringParams: true }
91-
);
92-
93-
var helpers = {
94-
tomdale: function(desire, noun, trueBool, falseBool, options) {
95-
equal(options.types[0], 'StringLiteral', 'the string type is passed');
96-
equal(
97-
options.types[1],
98-
'PathExpression',
99-
'the expression type is passed'
100-
);
101-
equal(
102-
options.types[2],
103-
'BooleanLiteral',
104-
'the expression type is passed'
105-
);
106-
equal(desire, 'need', 'the string form is passed for strings');
107-
equal(noun, 'dad.joke', 'the string form is passed for expressions');
108-
equal(trueBool, true, 'raw booleans are passed through');
109-
equal(falseBool, false, 'raw booleans are passed through');
110-
return 'Helper called';
111-
}
112-
};
113-
114-
var result = template({}, { helpers: helpers });
115-
equal(result, 'Helper called');
65+
expectTemplate("{{tomdale 'need' dad.joke true false}}")
66+
.withCompileOptions({
67+
stringParams: true
68+
})
69+
.withHelpers({
70+
tomdale: function(desire, noun, trueBool, falseBool, options) {
71+
equal(options.types[0], 'StringLiteral', 'the string type is passed');
72+
equal(
73+
options.types[1],
74+
'PathExpression',
75+
'the expression type is passed'
76+
);
77+
equal(
78+
options.types[2],
79+
'BooleanLiteral',
80+
'the expression type is passed'
81+
);
82+
equal(desire, 'need', 'the string form is passed for strings');
83+
equal(noun, 'dad.joke', 'the string form is passed for expressions');
84+
equal(trueBool, true, 'raw booleans are passed through');
85+
equal(falseBool, false, 'raw booleans are passed through');
86+
return 'Helper called';
87+
}
88+
})
89+
.toCompileTo('Helper called');
11690
});
11791

11892
it('hash parameters get type information', function() {
119-
var template = CompilerContext.compile(
120-
"{{tomdale he.says desire='need' noun=dad.joke bool=true}}",
121-
{ stringParams: true }
122-
);
123-
124-
var helpers = {
125-
tomdale: function(exclamation, options) {
126-
equal(exclamation, 'he.says');
127-
equal(options.types[0], 'PathExpression');
128-
129-
equal(options.hashTypes.desire, 'StringLiteral');
130-
equal(options.hashTypes.noun, 'PathExpression');
131-
equal(options.hashTypes.bool, 'BooleanLiteral');
132-
equal(options.hash.desire, 'need');
133-
equal(options.hash.noun, 'dad.joke');
134-
equal(options.hash.bool, true);
135-
return 'Helper called';
136-
}
137-
};
138-
139-
var result = template({}, { helpers: helpers });
140-
equal(result, 'Helper called');
93+
expectTemplate("{{tomdale he.says desire='need' noun=dad.joke bool=true}}")
94+
.withCompileOptions({
95+
stringParams: true
96+
})
97+
.withHelpers({
98+
tomdale: function(exclamation, options) {
99+
equal(exclamation, 'he.says');
100+
equal(options.types[0], 'PathExpression');
101+
102+
equal(options.hashTypes.desire, 'StringLiteral');
103+
equal(options.hashTypes.noun, 'PathExpression');
104+
equal(options.hashTypes.bool, 'BooleanLiteral');
105+
equal(options.hash.desire, 'need');
106+
equal(options.hash.noun, 'dad.joke');
107+
equal(options.hash.bool, true);
108+
return 'Helper called';
109+
}
110+
})
111+
.toCompileTo('Helper called');
141112
});
142113

143114
it('hash parameters get context information', function() {
144-
var template = CompilerContext.compile(
145-
"{{#with dale}}{{tomdale he.says desire='need' noun=../dad/joke bool=true}}{{/with}}",
146-
{ stringParams: true }
147-
);
148-
149115
var context = { dale: {} };
150116

151117
var helpers = {
@@ -165,82 +131,77 @@ describe('string params mode', function() {
165131
}
166132
};
167133

168-
var result = template(context, { helpers: helpers });
169-
equal(result, 'Helper called');
134+
expectTemplate(
135+
"{{#with dale}}{{tomdale he.says desire='need' noun=../dad/joke bool=true}}{{/with}}"
136+
)
137+
.withCompileOptions({ stringParams: true })
138+
.withHelpers(helpers)
139+
.withInput(context)
140+
.toCompileTo('Helper called');
170141
});
171142

172143
it('when inside a block in String mode, .. passes the appropriate context in the options hash to a block helper', function() {
173-
var template = CompilerContext.compile(
174-
'{{#with dale}}{{#tomdale ../need dad.joke}}wot{{/tomdale}}{{/with}}',
175-
{ stringParams: true }
176-
);
177-
178-
var helpers = {
179-
tomdale: function(desire, noun, options) {
180-
return (
181-
'STOP ME FROM READING HACKER NEWS I ' +
182-
options.contexts[0][desire] +
183-
' ' +
184-
noun +
185-
' ' +
186-
options.fn(this)
187-
);
188-
},
189-
190-
with: function(context, options) {
191-
return options.fn(options.contexts[0][context]);
192-
}
193-
};
194-
195-
var result = template(
196-
{
144+
expectTemplate(
145+
'{{#with dale}}{{#tomdale ../need dad.joke}}wot{{/tomdale}}{{/with}}'
146+
)
147+
.withCompileOptions({
148+
stringParams: true
149+
})
150+
.withHelpers({
151+
tomdale: function(desire, noun, options) {
152+
return (
153+
'STOP ME FROM READING HACKER NEWS I ' +
154+
options.contexts[0][desire] +
155+
' ' +
156+
noun +
157+
' ' +
158+
options.fn(this)
159+
);
160+
},
161+
162+
with: function(context, options) {
163+
return options.fn(options.contexts[0][context]);
164+
}
165+
})
166+
.withInput({
197167
dale: {},
198168

199169
need: 'need-a'
200-
},
201-
{ helpers: helpers }
202-
);
203-
204-
equals(
205-
result,
206-
'STOP ME FROM READING HACKER NEWS I need-a dad.joke wot',
207-
'Proper context variable output'
208-
);
170+
})
171+
.withMessage('Proper context variable output')
172+
.toCompileTo('STOP ME FROM READING HACKER NEWS I need-a dad.joke wot');
209173
});
210174

211175
it('with nested block ambiguous', function() {
212-
var template = CompilerContext.compile(
213-
'{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}',
214-
{ stringParams: true }
215-
);
216-
217-
var helpers = {
218-
with: function() {
219-
return 'WITH';
220-
},
221-
view: function() {
222-
return 'VIEW';
223-
}
224-
};
225-
226-
var result = template({}, { helpers: helpers });
227-
equals(result, 'WITH');
176+
expectTemplate(
177+
'{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}'
178+
)
179+
.withCompileOptions({
180+
stringParams: true
181+
})
182+
.withHelpers({
183+
with: function() {
184+
return 'WITH';
185+
},
186+
view: function() {
187+
return 'VIEW';
188+
}
189+
})
190+
.toCompileTo('WITH');
228191
});
229192

230193
it('should handle DATA', function() {
231-
var template = CompilerContext.compile('{{foo @bar}}', {
232-
stringParams: true
233-
});
234-
235-
var helpers = {
236-
foo: function(bar, options) {
237-
equal(bar, '@bar');
238-
equal(options.types[0], 'PathExpression');
239-
return 'Foo!';
240-
}
241-
};
242-
243-
var result = template({}, { helpers: helpers });
244-
equal(result, 'Foo!');
194+
expectTemplate('{{foo @bar}}')
195+
.withCompileOptions({
196+
stringParams: true
197+
})
198+
.withHelpers({
199+
foo: function(bar, options) {
200+
equal(bar, '@bar');
201+
equal(options.types[0], 'PathExpression');
202+
return 'Foo!';
203+
}
204+
})
205+
.toCompileTo('Foo!');
245206
});
246207
});

‎spec/subexpressions.js

+212-226
Large diffs are not rendered by default.

‎spec/track-ids.js

+221-287
Large diffs are not rendered by default.

‎spec/utils.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,9 @@ describe('utils', function() {
1515
it('it should not escape SafeString properties', function() {
1616
var name = new Handlebars.SafeString('<em>Sean O&#x27;Malley</em>');
1717

18-
shouldCompileTo(
19-
'{{name}}',
20-
[{ name: name }],
21-
'<em>Sean O&#x27;Malley</em>'
22-
);
18+
expectTemplate('{{name}}')
19+
.withInput({ name: name })
20+
.toCompileTo('<em>Sean O&#x27;Malley</em>');
2321
});
2422
});
2523

‎spec/whitespace-control.js

+118-87
Original file line numberDiff line numberDiff line change
@@ -2,125 +2,156 @@ describe('whitespace control', function() {
22
it('should strip whitespace around mustache calls', function() {
33
var hash = { foo: 'bar<' };
44

5-
shouldCompileTo(' {{~foo~}} ', hash, 'bar&lt;');
6-
shouldCompileTo(' {{~foo}} ', hash, 'bar&lt; ');
7-
shouldCompileTo(' {{foo~}} ', hash, ' bar&lt;');
5+
expectTemplate(' {{~foo~}} ')
6+
.withInput(hash)
7+
.toCompileTo('bar&lt;');
88

9-
shouldCompileTo(' {{~&foo~}} ', hash, 'bar<');
10-
shouldCompileTo(' {{~{foo}~}} ', hash, 'bar<');
9+
expectTemplate(' {{~foo}} ')
10+
.withInput(hash)
11+
.toCompileTo('bar&lt; ');
1112

12-
shouldCompileTo('1\n{{foo~}} \n\n 23\n{{bar}}4', {}, '1\n23\n4');
13+
expectTemplate(' {{foo~}} ')
14+
.withInput(hash)
15+
.toCompileTo(' bar&lt;');
16+
17+
expectTemplate(' {{~&foo~}} ')
18+
.withInput(hash)
19+
.toCompileTo('bar<');
20+
21+
expectTemplate(' {{~{foo}~}} ')
22+
.withInput(hash)
23+
.toCompileTo('bar<');
24+
25+
expectTemplate('1\n{{foo~}} \n\n 23\n{{bar}}4').toCompileTo('1\n23\n4');
1326
});
1427

1528
describe('blocks', function() {
1629
it('should strip whitespace around simple block calls', function() {
1730
var hash = { foo: 'bar<' };
1831

19-
shouldCompileTo(' {{~#if foo~}} bar {{~/if~}} ', hash, 'bar');
20-
shouldCompileTo(' {{#if foo~}} bar {{/if~}} ', hash, ' bar ');
21-
shouldCompileTo(' {{~#if foo}} bar {{~/if}} ', hash, ' bar ');
22-
shouldCompileTo(' {{#if foo}} bar {{/if}} ', hash, ' bar ');
32+
expectTemplate(' {{~#if foo~}} bar {{~/if~}} ')
33+
.withInput(hash)
34+
.toCompileTo('bar');
2335

24-
shouldCompileTo(
25-
' \n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\n ',
26-
hash,
27-
'bar'
28-
);
29-
shouldCompileTo(
30-
' a\n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\na ',
31-
hash,
32-
' abara '
33-
);
36+
expectTemplate(' {{#if foo~}} bar {{/if~}} ')
37+
.withInput(hash)
38+
.toCompileTo(' bar ');
39+
40+
expectTemplate(' {{~#if foo}} bar {{~/if}} ')
41+
.withInput(hash)
42+
.toCompileTo(' bar ');
43+
44+
expectTemplate(' {{#if foo}} bar {{/if}} ')
45+
.withInput(hash)
46+
.toCompileTo(' bar ');
47+
48+
expectTemplate(' \n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\n ')
49+
.withInput(hash)
50+
.toCompileTo('bar');
51+
52+
expectTemplate(' a\n\n{{~#if foo~}} \n\nbar \n\n{{~/if~}}\n\na ')
53+
.withInput(hash)
54+
.toCompileTo(' abara ');
3455
});
56+
3557
it('should strip whitespace around inverse block calls', function() {
36-
var hash = {};
58+
expectTemplate(' {{~^if foo~}} bar {{~/if~}} ').toCompileTo('bar');
3759

38-
shouldCompileTo(' {{~^if foo~}} bar {{~/if~}} ', hash, 'bar');
39-
shouldCompileTo(' {{^if foo~}} bar {{/if~}} ', hash, ' bar ');
40-
shouldCompileTo(' {{~^if foo}} bar {{~/if}} ', hash, ' bar ');
41-
shouldCompileTo(' {{^if foo}} bar {{/if}} ', hash, ' bar ');
60+
expectTemplate(' {{^if foo~}} bar {{/if~}} ').toCompileTo(' bar ');
4261

43-
shouldCompileTo(
44-
' \n\n{{~^if foo~}} \n\nbar \n\n{{~/if~}}\n\n ',
45-
hash,
46-
'bar'
47-
);
62+
expectTemplate(' {{~^if foo}} bar {{~/if}} ').toCompileTo(' bar ');
63+
64+
expectTemplate(' {{^if foo}} bar {{/if}} ').toCompileTo(' bar ');
65+
66+
expectTemplate(
67+
' \n\n{{~^if foo~}} \n\nbar \n\n{{~/if~}}\n\n '
68+
).toCompileTo('bar');
4869
});
70+
4971
it('should strip whitespace around complex block calls', function() {
5072
var hash = { foo: 'bar<' };
5173

52-
shouldCompileTo('{{#if foo~}} bar {{~^~}} baz {{~/if}}', hash, 'bar');
53-
shouldCompileTo('{{#if foo~}} bar {{^~}} baz {{/if}}', hash, 'bar ');
54-
shouldCompileTo('{{#if foo}} bar {{~^~}} baz {{~/if}}', hash, ' bar');
55-
shouldCompileTo('{{#if foo}} bar {{^~}} baz {{/if}}', hash, ' bar ');
74+
expectTemplate('{{#if foo~}} bar {{~^~}} baz {{~/if}}')
75+
.withInput(hash)
76+
.toCompileTo('bar');
5677

57-
shouldCompileTo('{{#if foo~}} bar {{~else~}} baz {{~/if}}', hash, 'bar');
78+
expectTemplate('{{#if foo~}} bar {{^~}} baz {{/if}}')
79+
.withInput(hash)
80+
.toCompileTo('bar ');
5881

59-
shouldCompileTo(
60-
'\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n',
61-
hash,
62-
'bar'
63-
);
64-
shouldCompileTo(
65-
'\n\n{{~#if foo~}} \n\n{{{foo}}} \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n',
66-
hash,
67-
'bar<'
82+
expectTemplate('{{#if foo}} bar {{~^~}} baz {{~/if}}')
83+
.withInput(hash)
84+
.toCompileTo(' bar');
85+
86+
expectTemplate('{{#if foo}} bar {{^~}} baz {{/if}}')
87+
.withInput(hash)
88+
.toCompileTo(' bar ');
89+
90+
expectTemplate('{{#if foo~}} bar {{~else~}} baz {{~/if}}')
91+
.withInput(hash)
92+
.toCompileTo('bar');
93+
94+
expectTemplate(
95+
'\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n'
96+
)
97+
.withInput(hash)
98+
.toCompileTo('bar');
99+
100+
expectTemplate(
101+
'\n\n{{~#if foo~}} \n\n{{{foo}}} \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n'
102+
)
103+
.withInput(hash)
104+
.toCompileTo('bar<');
105+
106+
expectTemplate('{{#if foo~}} bar {{~^~}} baz {{~/if}}').toCompileTo(
107+
'baz'
68108
);
69109

70-
hash = {};
110+
expectTemplate('{{#if foo}} bar {{~^~}} baz {{/if}}').toCompileTo('baz ');
71111

72-
shouldCompileTo('{{#if foo~}} bar {{~^~}} baz {{~/if}}', hash, 'baz');
73-
shouldCompileTo('{{#if foo}} bar {{~^~}} baz {{/if}}', hash, 'baz ');
74-
shouldCompileTo('{{#if foo~}} bar {{~^}} baz {{~/if}}', hash, ' baz');
75-
shouldCompileTo('{{#if foo~}} bar {{~^}} baz {{/if}}', hash, ' baz ');
112+
expectTemplate('{{#if foo~}} bar {{~^}} baz {{~/if}}').toCompileTo(
113+
' baz'
114+
);
76115

77-
shouldCompileTo('{{#if foo~}} bar {{~else~}} baz {{~/if}}', hash, 'baz');
116+
expectTemplate('{{#if foo~}} bar {{~^}} baz {{/if}}').toCompileTo(
117+
' baz '
118+
);
78119

79-
shouldCompileTo(
80-
'\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n',
81-
hash,
120+
expectTemplate('{{#if foo~}} bar {{~else~}} baz {{~/if}}').toCompileTo(
82121
'baz'
83122
);
123+
124+
expectTemplate(
125+
'\n\n{{~#if foo~}} \n\nbar \n\n{{~^~}} \n\nbaz \n\n{{~/if~}}\n\n'
126+
).toCompileTo('baz');
84127
});
85128
});
86129

87130
it('should strip whitespace around partials', function() {
88-
shouldCompileToWithPartials(
89-
'foo {{~> dude~}} ',
90-
[{}, {}, { dude: 'bar' }],
91-
true,
92-
'foobar'
93-
);
94-
shouldCompileToWithPartials(
95-
'foo {{> dude~}} ',
96-
[{}, {}, { dude: 'bar' }],
97-
true,
98-
'foo bar'
99-
);
100-
shouldCompileToWithPartials(
101-
'foo {{> dude}} ',
102-
[{}, {}, { dude: 'bar' }],
103-
true,
104-
'foo bar '
105-
);
106-
107-
shouldCompileToWithPartials(
108-
'foo\n {{~> dude}} ',
109-
[{}, {}, { dude: 'bar' }],
110-
true,
111-
'foobar'
112-
);
113-
shouldCompileToWithPartials(
114-
'foo\n {{> dude}} ',
115-
[{}, {}, { dude: 'bar' }],
116-
true,
117-
'foo\n bar'
118-
);
131+
expectTemplate('foo {{~> dude~}} ')
132+
.withPartials({ dude: 'bar' })
133+
.toCompileTo('foobar');
134+
135+
expectTemplate('foo {{> dude~}} ')
136+
.withPartials({ dude: 'bar' })
137+
.toCompileTo('foo bar');
138+
139+
expectTemplate('foo {{> dude}} ')
140+
.withPartials({ dude: 'bar' })
141+
.toCompileTo('foo bar ');
142+
143+
expectTemplate('foo\n {{~> dude}} ')
144+
.withPartials({ dude: 'bar' })
145+
.toCompileTo('foobar');
146+
147+
expectTemplate('foo\n {{> dude}} ')
148+
.withPartials({ dude: 'bar' })
149+
.toCompileTo('foo\n bar');
119150
});
120151

121152
it('should only strip whitespace once', function() {
122-
var hash = { foo: 'bar' };
123-
124-
shouldCompileTo(' {{~foo~}} {{foo}} {{foo}} ', hash, 'barbar bar ');
153+
expectTemplate(' {{~foo~}} {{foo}} {{foo}} ')
154+
.withInput({ foo: 'bar' })
155+
.toCompileTo('barbar bar ');
125156
});
126157
});

0 commit comments

Comments
 (0)
Please sign in to comment.