describe("Ext.XTemplate", function() {
var tpl,
data,
arrayData,
objectData;
beforeEach(function() {
data = {
name: "Nicolas Ferrero",
title: "Developer",
company: "Sencha",
email: "nico@sencha.com",
address: "10 Rue St Ferreol",
city: "Toulouse",
country: "France",
zip: "31000",
drinks: ["Wine", "Coffee", "Corona"],
something: {
name: "root",
child : {
name: "child"
}
},
kids: [{
name: "Joshua",
age:3
},{
name: "Nina",
age:2
},{
name: "Solomon",
age:0
}],
computers: [{
cpu: "2Ghz",
hdd: "1To"
},{
cpu: "100Mhz",
hdd: "500Mo"
}]
};
arrayData = {
arrays: [
[ { name: 'Item A1' }, { name: 'Item A2' } ],
[ { name: 'Item B1' }, { name: 'Item B2' } ]
]
};
objectData = {
a: 'aValue',
b: {
x: 'xValue',
y: 'yValue'
},
c: 'cValue'
};
});
describe("instantiation", function() {
it("should extend Ext.Template", function() {
tpl = new Ext.XTemplate("");
expect(tpl.superclass).toEqual(Ext.Template.prototype);
});
it("should alias apply with applyTemplate", function() {
tpl = new Ext.XTemplate("");
spyOn(tpl, 'apply');
tpl.applyTemplate();
expect(tpl.apply).toHaveBeenCalled();
});
it("should compile on first use", function() {
tpl = new Ext.XTemplate('Hello {foo}');
expect(tpl.fn).toBe(null);
var s = tpl.apply({ foo: 42 });
expect(s).toBe('Hello 42');
expect(typeof tpl.fn).toBe('function');
});
/* begin this line with "//* to include this test or "/*" to remove it
it('should perform better', function () {
function run (name) {
var T = Ext[name],
t0 = new Date().getTime(),
K = 2000,
t, s;
for (var i = 0; i < K; ++i) {
t = new T(
'
Name: {name}
',
'Kids: ',
'',
'',
'{name}
',
'Dad: {parent.name}
',
'',
'
'
);
}
var t1 = new Date().getTime();
for (i = 0; i < K; ++i) {
s = t.apply(data);
}
var t2 = new Date().getTime();
for (i = 0; i < K; ++i) {
t = new T(
'Name: {name}
',
'Kids: ',
'',
'',
'{name}
',
'Dad: {parent.name}
',
'',
'
'
);
s = t.apply(data);
}
var t3 = new Date().getTime();
Ext.log(name + ': total=' + (t2 - t0)/K + ' ctor=' + (t1 - t0)/K +
' apply=' + (t2 - t1)/K + ' ctorApply=' + (t3 - t2)/K);
}
run('XTemplate');
run('XTemplate1');
run('XTemplate2');
});/**/
});
describe("tags", function() {
describe("if", function() {
it("should handle tpl tag with no attributes", function() {
tpl = new Ext.XTemplate(
'{name}'
);
expect(tpl.apply({name: 'Phil'})).toEqual('Phil');
});
it('should handle like ', function() {
tpl = new Ext.XTemplate(
'Kids: ',
'',
'{name}
',
'
'
);
expect(tpl.apply(data.kids)).toEqual('Kids:
');
});
it('should handle if, elif and else', function() {
tpl = new Ext.XTemplate(
'',
'',
'{name}
',
'Pops: {parent.name}
',
'',
'{name}
',
'Dad: {parent.name}
',
'',
'{name}
',
'Daddy: {parent.name}
',
'',
'!
'
);
var s = tpl.apply(data);
expect(s).toEqual('Joshua
Pops: Nicolas Ferrero
' +
'Nina
Dad: Nicolas Ferrero
' +
'Solomon
Daddy: Nicolas Ferrero
!
');
});
it('should handle verbatim block', function() {
tpl = new Ext.XTemplate(
'',
'',
'{% continue; %}',
'',
'',
' and ',
'',
'{% ++this.count %}',
'{name} is less than 3',
'!!!',
{
count: 0
}
);
var s = tpl.apply(data);
expect(s).toEqual('Nina is less than 3 and Solomon is less than 3!!!');
});
it('should handle verbatim if/else', function() {
tpl = new Ext.XTemplate(
'',
'{% if (values.age >= 3) { %}',
'{% continue; %}',
'{% }',
'if (this.count) { %}',
' and ',
'{% } %}',
'{% ++this.count %}',
'{name} is less than 3',
'!!!',
{
count: 0
}
);
var s = tpl.apply(data);
expect(s).toEqual('Nina is less than 3 and Solomon is less than 3!!!');
});
it('should handle double quotes', function() {
tpl = new Ext.XTemplate(
"",
"",
"Josh",
"",
" {name}",
"",
'!!!'
);
var s = tpl.apply(data);
expect(s).toEqual('Josh Nina Solomon!!!');
});
// From http://www.sencha.com/forum/showthread.php?142918
it('should handle single quotes', function () {
tpl = new Ext.XTemplate(
'',
'',
'
',
'',
'
',
'
',
'',
'
',
'',
'',
'{name}',
'',
'',
'
',
'',
'
',
'');
var s = tpl.apply({
menus: [
{ id: 'foo', test: 0, sample: 3, cmpName: 'cname', name: 'Name', icon: 'ico' }
]
});
expect(s).toEqual(''+
'
'+
'
'+
'
'+
'
'+
''+
'Name'+
''+
''+
'
'
);
});
});
describe("switch", function() {
it('should handle switch, case and default with numbers', function() {
tpl = new Ext.XTemplate(
'',
'',
'',
'{name} is 3...
',
'',
'{name} is 2...
',
'',
'{name} is {age}!
',
'',
'!
'
);
var s = tpl.apply(data);
expect(s).toEqual('Joshua is 3...
Nina is 2...
Solomon is 0!
!
');
});
it('should handle switch, case and default with strings', function() {
tpl = new Ext.XTemplate(
'',
'',
'',
'{name} is a boy
',
'',
'{name} is a girl!
',
'',
'!
'
);
var s = tpl.apply(data);
expect(s).toEqual('Joshua is a boy
Nina is a girl!
Solomon is a boy
!
');
});
it("should be able to switch on xindex", function() {
tpl = new Ext.XTemplate([
'',
'',
'One',
'Two',
'Three',
'Four',
'Bigger',
'',
'']);
expect(tpl.apply([1, 2, 3, 4, 5, 6])).toBe('OneTwoThreeFourBiggerBigger');
});
it("should allow spaces after the switch", function() {
tpl = new Ext.XTemplate(' bar');
expect(tpl.apply({
foo: 'bar'
})).toBe('bar');
});
});
describe("for", function () {
it('should examine the data object provided if for="." is specified (include array index test)', function() {
tpl = new Ext.XTemplate(
'Kids: ',
'',
'{#}. {name}
',
'
'
);
var s = tpl.apply(data.kids);
expect(s).toEqual('Kids:
1. Joshua
2. Nina
3. Solomon
');
});
it('should insert "between" values', function() {
tpl = new Ext.XTemplate(
'Kids: ',
'',
'{#}. {name}',
'
'
);
var s = tpl.apply(data.kids);
expect(s).toEqual('Kids: 1. Joshua,2. Nina,3. Solomon
');
});
it('should handle "." and "parent" in loop', function () {
var tpl = new Ext.XTemplate(
' {bodyCls}',
'',
' {parent.baseCls}-body-{parent.ui}-{.}',
'"',
' style="{bodyStyle}">',
'
'
);
var s = tpl.apply({
baseCls: 'x-panel-header',
componentCls: 'x-panel-header',
frame: false,
id: 'header-1026',
ui: 'default',
uiCls: ['horizontal', 'top']
});
expect(s).toEqual('');
});
it('should handle like ', function() {
tpl = new Ext.XTemplate(
'Kids: ',
'',
'{name}
',
'
'
);
expect(tpl.apply(data.kids)).toEqual('Kids:
');
});
it('should examine the data of parent object if for=".." is specified', function() {
tpl = new Ext.XTemplate(
'Computer: ',
'',
'Cpu: {cpu} Hdd: {hdd}',
'',
' User: {name}',
'',
'
',
'
'
);
var s = tpl.apply(data);
expect(s).toEqual('Computer:
Cpu: 2Ghz Hdd: 1To User: Nicolas Ferrero
Cpu: 100Mhz Hdd: 500Mo User: Nicolas Ferrero
');
});
it("should be able to access specified members of the provided data object (include array index test)", function() {
tpl = new Ext.XTemplate(
'Name: {name}
',
'Title: {title}
',
'Company: {company}
',
'Kids: ',
'',
'{#}. {name}
',
'
'
);
expect(tpl.apply(data)).toEqual('Name: Nicolas Ferrero
Title: Developer
Company: Sencha
Kids:
1. Joshua
2. Nina
3. Solomon
');
});
describe("{.}", function(){
it("should be able to auto-render flat array content with special variable {.} (include array index test)", function() {
tpl = new Ext.XTemplate(
'{name}\'s favorite beverages:
',
'',
'{#} - {.}
',
''
);
expect(tpl.apply(data)).toEqual("Nicolas Ferrero's favorite beverages:
1 - Wine
2 - Coffee
3 - Corona
");
});
it("should render numbers, strings, booleans, and dates, but not objects or arrays", function(){
tpl = new Ext.XTemplate('{.}');
var date = new Date();
expect(tpl.apply([1, true, 2.3, false, 'test', [1, 2, 3], {a:1, b:2}, 'ing', date, undefined, null])).toEqual('1true2.3falsetesting' + date);
});
});
it("should not fail if for try to handle an undefined variable.", function() {
tpl = new Ext.XTemplate(
'{name}\'s:
',
'',
'{nothing1}
',
'{badness}Foo
'
);
var s = tpl.apply(data);
expect(s).toEqual("Nicolas Ferrero's:
Foo
");
});
describe("parent", function() {
it("should be able to access parent object member via the parent object", function() {
tpl = new Ext.XTemplate(
'Name: {name}
',
'Kids: ',
'',
'',
'{name}
',
'Dad: {parent.name}
',
'',
'
'
);
var s = tpl.apply(data);
expect(s).toEqual("Name: Nicolas Ferrero
Kids:
Joshua
Dad: Nicolas Ferrero
Nina
Dad: Nicolas Ferrero
");
});
it("should set the parent to the parent array if the action is '.'", function(){
var tpl = new Ext.XTemplate(
'',
'{parent.specialProp}',
'',
'{parent.specialProp}{.}',
'',
''
);
var data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
data.specialProp = 'test';
data[0].specialProp = 'foo';
data[1].specialProp = 'bar';
data[2].specialProp = 'baz';
var s = tpl.apply(data);
expect(s).toBe('testfoo1foo2foo3testbar4bar5bar6testbaz7baz8baz9');
});
it("should work with nested parents", function(){
var tpl = new Ext.XTemplate(
'{name}',
'',
'{name}{parent.name}',
'',
'{name}{parent.name}',
'',
''
);
var s = tpl.apply({
name : 'A1',
children : [{
name : 'B1',
children : [{
name : 'C1'
}, {
name: 'C2'
}]
}, {
name: 'B2',
children : [{
name : 'C3'
}, {
name: 'C4'
}]
}]
});
expect(s).toBe('A1B1A1C1B1C2B1B2A1C3B2C4B2');
});
it("should reset the parent correctly during looping", function(){
var data = [{
id: 1,
level2: [{
id: 11,
level3: [{
id: 111
}, {
id: 112
}, {
id: 113
}]
}, {
id: 12,
level3: [{
id: 121
}, {
id: 122
}, {
id: 123
}]
}, {
id: 13,
level3: [{
id: 131
}, {
id: 132
}, {
id: 133
}]
}]
}, {
id: 2,
level2: [{
id: 21,
level3: []
}, {
id: 22,
level3: []
}]
}];
var tpl = new Ext.XTemplate(
'',
'level 1: id: {id}',
'',
'level 2: id: {id}, parent.id: {parent.id}',
'',
'level 3: id: {id}, parent.id: {parent.id}',
'',
'',
''
);
expect(tpl.apply(data)).toBe([
'level 1: id: 1',
'level 2: id: 11, parent.id: 1',
'level 3: id: 111, parent.id: 11',
'level 3: id: 112, parent.id: 11',
'level 3: id: 113, parent.id: 11',
'level 2: id: 12, parent.id: 1',
'level 3: id: 121, parent.id: 12',
'level 3: id: 122, parent.id: 12',
'level 3: id: 123, parent.id: 12',
'level 2: id: 13, parent.id: 1',
'level 3: id: 131, parent.id: 13',
'level 3: id: 132, parent.id: 13',
'level 3: id: 133, parent.id: 13',
'level 1: id: 2',
'level 2: id: 21, parent.id: 2',
'level 2: id: 22, parent.id: 2'
].join(''));
});
});
it("should be able to access child object like a tree", function() {
tpl = new Ext.XTemplate("{something.child.name}");
expect(tpl.apply(data)).toEqual("child");
});
it('should handle sequential for loops nested in for loop using arrays', function () {
// this bug one was found by Brian's calendar templates
tpl = new Ext.XTemplate(
'',
'',
'_{name}_',
'',
'',
'-{name}-',
'',
'/',
''
);
var s = tpl.apply(arrayData);
expect(s).toEqual('_Item A1__Item A2_-Item A1--Item A2-/'+
'_Item B1__Item B2_-Item B1--Item B2-/');
});
it("should set the xindex variable correctly when looping over nested arrays", function() {
var result = new Ext.XTemplate(
'',
'{% if (Ext.isArray(values)) { %}',
'',
'{#}',
'',
'{% } %}',
'{#}',
''
).apply([1,1,1,[1,1],1]);
expect(result).toBe('1231245');
});
}); // for
describe("foreach", function () {
it('should examine the data object provided if foreach="." is specified', function() {
var tpl = new Ext.XTemplate(
'',
'{% if (Ext.isObject(values)) { %}',
'',
'{[xkey]} {[values]}.',
'',
'{% } %}',
'{$} {.}.',
''
),
result = Ext.Array.sort(tpl.apply(objectData).split('.'));
expect(result[1]).toBe('a aValue');
expect(result[2]).toBe('b ');
expect(result[3]).toBe('c cValue');
expect(result[4]).toBe('x xValue');
expect(result[5]).toBe('y yValue');
});
it('should handle "." and "parent" in loop', function () {
var tpl = new Ext.XTemplate(
' {bodyCls}',
'',
' {parent.baseCls}-body-{parent.ui}-{.}',
'"',
' style="{bodyStyle}">',
'
'
),
result = tpl.apply({
baseCls: 'x-panel-header',
componentCls: 'x-panel-header',
frame: false,
id: 'header-1026',
ui: 'default',
uiCls: {
h: 'horizontal',
t: 'top'
}
});
expect(result).toEqual('');
});
it('should handle like ', function() {
var tpl = new Ext.XTemplate(
'Kids: ',
'',
'{name}
',
'
'
);
expect(tpl.apply(data.kids)).toEqual('Kids:
');
});
it('should examine the data of parent object if for=".." is specified', function() {
var tpl = new Ext.XTemplate(
'',
'{$} {.}
',
'',
'a: {a}',
'',
'',
''
);
expect(tpl.apply(objectData)).toEqual('x xValue
a: aValuey yValue
a: aValue');
});
it('should insert "between" values', function() {
var tpl = new Ext.XTemplate(
'',
'{$}: {.}',
''
);
expect(tpl.apply(objectData)).toEqual('x: xValue,y: yValue');
});
it("should be able to access the xindex using {#}", function() {
var tpl = new Ext.XTemplate(
'',
'{#}',
''
);
expect(tpl.apply(data)).toEqual('123');
});
it("should not loop if foreach is passed an undefined variable.", function() {
var tpl = new Ext.XTemplate(
'{name}\'s:
',
'',
'{#}{$}{.}{nothing1}
',
'{badness}Foo
'
);
expect(tpl.apply(data)).toEqual("Nicolas Ferrero's:
Foo
");
});
describe("parent", function() {
it("should be able to access parent object member via the parent object", function() {
var tpl = new Ext.XTemplate(
'',
'{parent.c}
',
''
);
expect(tpl.apply(objectData)).toEqual("cValue
cValue
");
});
it("should set the parent to the parent object if the action is '.'", function(){
var tpl = new Ext.XTemplate(
'',
'{parent.x}',
''
), data = {
x: 1,
y: 2,
z: 3
};
expect(tpl.apply(data)).toBe('111');
});
});
it("should set the xindex variable correctly when looping over nested objects", function() {
var result = new Ext.XTemplate(
'',
'{% if (Ext.isObject(values)) { %}',
'',
'{#}',
'',
'{% } %}',
'{#}',
''
).apply({a:1,b:1,c:1,d:{e:1,f:1},g:1});
expect(result).toBe('1231245');
});
}); // foreach
describe("insane overnesting of for and foreach loops", function () {
it("should apply the template", function() {
var id = 0,
data = (function assignIds(data) {
if (data instanceof Object) {
data.id = id++;
if (data instanceof Array) {
Ext.Array.each(data, function(item) {
assignIds(item);
});
} else {
Ext.Object.each(data, function(key, value) {
assignIds(value);
});
}
}
return data;
})({
a: [{
b: [1, 2],
c: {d: 3, e: 4}
}, {
f: {g: 5, h: 6},
i: [7, 8]
}, [
{j: 9, k: 10},
[11, 12]
]],
l: {
m: [{n: 13, o: 14}],
p: [[15, 16], [17, 18]]
}
}),
tpl = new Ext.XTemplate(
'',
'[key]{$}',
'{% if (Ext.isObject(values)) { %}',
'',
'[key]{$}',
'{% if (Ext.isObject(values)) { %}',
'',
'[key]{$}',
'{% if (Ext.isObject(values)) { %}',
'',
'[key]{$}[value]{.}[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'{% else if (Ext.isArray(values)) { %}',
'',
'[value]{.}[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'{% else if (Ext.isArray(values)) { %}',
'',
'{% if (Ext.isObject(values)) { %}',
'',
'[key]{$}[value]{.}[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'{% else if (Ext.isArray(values)) { %}',
'',
'[value]{.}[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'{% else if (Ext.isArray(values)) { %}',
'',
'{% if (Ext.isObject(values)) { %}',
'',
'[key]{$}',
'{% if (Ext.isObject(values)) { %}',
'',
'[key]{$}[value]{.}[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'{% else if (Ext.isArray(values)) { %}',
'',
'[value]{.}[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'{% else if (Ext.isArray(values)) { %}',
'',
'{% if (Ext.isObject(values)) { %}',
'',
'[key]{$}[value]{.}[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'{% else if (Ext.isArray(values)) { %}',
'',
'[value]{.}[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'[parent]{parent.id}[index]{#}',
'',
'{% } %}',
'[parent]{parent.id}[index]{#}',
''
);
// Although not required by the ecmascript spec, all modern browsers currently
// loop object properties in the order they/ were defined, which is why the
// following expectation passes. If this ever changes in the future, we may
// have to revisit this spec.
expect(tpl.apply(data)).toBe([
'[key]a[key]b[value]1[parent]3[index]1[value]2[parent]3[index]2',
'[parent]2[index]1[key]c[key]d[value]3[parent]4[index]1[key]e[value]4',
'[parent]4[index]2[key]id[value]4[parent]4[index]3[parent]2[index]2',
'[key]id[parent]2[index]3[parent]1[index]1[key]f[key]g[value]5[parent]6',
'[index]1[key]h[value]6[parent]6[index]2[key]id[value]6[parent]6[index]3',
'[parent]5[index]1[key]i[value]7[parent]7[index]1[value]8[parent]7',
'[index]2[parent]5[index]2[key]id[parent]5[index]3[parent]1[index]2',
'[key]j[value]9[parent]9[index]1[key]k[value]10[parent]9[index]2',
'[key]id[value]9[parent]9[index]3[parent]8[index]1[value]11[parent]10',
'[index]1[value]12[parent]10[index]2[parent]8[index]2[parent]1[index]3',
'[parent]0[index]1[key]l[key]m[key]n[value]13[parent]13[index]1[key]o',
'[value]14[parent]13[index]2[key]id[value]13[parent]13[index]3[parent]12',
'[index]1[parent]11[index]1[key]p[value]15[parent]15[index]1[value]16',
'[parent]15[index]2[parent]14[index]1[value]17[parent]16[index]1',
'[value]18[parent]16[index]2[parent]14[index]2[parent]11[index]2[key]id',
'[parent]11[index]3[parent]0[index]2[key]id[parent]0[index]3'
].join(''));
});
});
describe("exec", function() {
it("should considerer that anything between {[ ... ]} is code to be executed in the scope of the template", function() {
tpl = new Ext.XTemplate(
'Name: {name}
',
'Company: {[values.company.toUpperCase() + ", " + values.title]}
',
'Kids: ',
'',
'',
'{[fm.ellipsis(values.name, 5)]}/{[xcount]}',
'
',
'
'
);
var s = tpl.apply(data);
expect(s).toEqual('Name: Nicolas Ferrero
Company: SENCHA, Developer
Kids:
Jo.../3
Nina/3
So.../3
');
});
});
it('should handle like ', function() {
tpl = new Ext.XTemplate(
'Kids: ',
'',
'{name}
',
'
',
{
foo: 1
}
);
var s = tpl.apply(data.kids);
expect(tpl.foo).toEqual(2);
expect(s).toEqual('Kids:
');
});
it('should handle nested tags', function() {
tpl = new Ext.XTemplate(
'{{id}-bar}'
);
var s = tpl.apply({
id: 'foo'
});
expect(s).toEqual('{foo-bar}');
});
describe("execute code without producing any output with exec operator", function() {
describe("simple exec operator", function() {
beforeEach(function() {
tpl = new Ext.XTemplate(
'',
'',
'{name}
',
'',
'',
{
calls: 0
});
});
it("should execute the code", function() {
tpl.apply(data);
expect(tpl.calls).toEqual(3);
});
it("should not interfere with output even if exec return a value", function() {
expect(tpl.apply(data)).toEqual('Joshua
Nina
Solomon
');
});
});
describe("for and exec declared in the same tpl tag", function() {
beforeEach(function() {
tpl = new Ext.XTemplate(
'',
'{[this.spy.calls.length]}. {name}
',
'',
{
spy : jasmine.createSpy("tplMemberSpy")
});
});
it("should execute code for each item in the array", function() {
tpl.apply(data);
expect(tpl.spy.calls.length).toEqual(3);
});
it("should be run for each item in the array with index of the loop you are in, values of the current scope, and scope of ancestor template", function() {
tpl.apply(data);
expect(tpl.spy.calls[0].args).toEqual([data.kids[0], 1, data]);
expect(tpl.spy.calls[1].args).toEqual([data.kids[1], 2, data]);
expect(tpl.spy.calls[2].args).toEqual([data.kids[2], 3, data]);
});
it("should not interfere with output even if exec return a value", function() {
expect(tpl.apply(data)).toEqual('0. Joshua
1. Nina
2. Solomon
');
});
});
describe("if and exec declared in the same tpl tag", function() {
beforeEach(function() {
tpl = new Ext.XTemplate(
'',
'',
'{[this.inc]} - {name}
',
'',
'',
{
inc : 0
});
});
it("should be run only if the if operator conditional checks is true", function() {
tpl.apply(data);
expect(tpl.inc).toEqual(1);
});
it("should not interfere with output", function() {
expect(tpl.apply(data)).toEqual('1 - Joshua
');
});
});
});
});
describe("template member functions", function() {
var spy;
beforeEach(function() {
spy = jasmine.createSpy("membersArguments").andCallFake(function(value, suffix, limit) {
return Ext.String.ellipsis(value + ' ' + suffix, 13);
});
tpl = new Ext.XTemplate(
'{[this.addMr(values.name)]}
',
'Company: {company:this.spy("Incorporated", 10)}
',
'Title: {title:this.addJs()}
',
'Kids: ',
'',
'',
'Girl: {name} - {age}
',
'',
'Boy: {name} - {age}
',
'',
'',
'{name} is a baby!
',
'',
'
',
{
addMr: function(name) {
return "Mr. " + name;
},
addJs: function(title) {
return "Js " + title;
},
isGirl: function(name) {
return name == 'Nina';
},
isBaby: function(age) {
return age < 1;
},
spy: spy
}
);
});
it("should call members functions using various methods", function() {
var s = tpl.apply(data);
expect(s).toEqual("Mr. Nicolas Ferrero
Company: Sencha Inc...
Title: Js Developer
Kids:
Boy: Joshua - 3
Girl: Nina - 2
Boy: Solomon - 0
Solomon is a baby!
");
});
it("should call members format functions with passed arguments", function() {
tpl.apply(data);
expect(spy).toHaveBeenCalledWith(data.company, "Incorporated", 10);
});
});
describe("basic math support", function() {
it("should be able to apply basic math operators + - * / on numeric data values", function() {
tpl = new Ext.XTemplate(
'',
'{age + 5} {age - 7} {age * 3} {age / 2}
',
'{age + (5*2)}
',
''
);
expect(tpl.apply(data)).toEqual("8 -4 9 1.5
13
7 -5 6 1
12
5 -7 0 0
10
");
});
});
describe("special characters", function(){
it("should handle newlines", function(){
tpl = new Ext.XTemplate('\n
');
expect(tpl.apply()).toBe('\n
');
});
it("should handle empty braces", function(){
var s = 'cfg = cfg || {};';
tpl = new Ext.XTemplate(s);
expect(tpl.apply()).toBe(s);
});
it("should handle curly braces literally if there is no tag match", function() {
expect(new Ext.XTemplate(
'{ foo} foobar {bar } barfoo { foo bar } { foo {bar}}{\nfoo}{foo\n} {foo\nbar}{{bar}}',
''
).apply({
bar: 'baz'
})).toBe('{ foo} foobar {bar } barfoo { foo bar } { foo baz}{\nfoo}{foo\n} {foo\nbar}{baz}');
});
});
describe("Undefined and non-string properties", function(){
it("should ignore undefined", function () {
tpl = new Ext.XTemplate('-{foo}-');
expect(tpl.apply({})).toBe('--');
});
it("should ignore null", function () {
tpl = new Ext.XTemplate('-{foo}-');
expect(tpl.apply({foo:null})).toBe('--');
});
it("should ignore an empty string", function(){
tpl = new Ext.XTemplate('-{foo}-');
expect(tpl.apply({foo:''})).toBe('--');
});
it("should stringify false", function(){
tpl = new Ext.XTemplate('-{foo}-');
expect(tpl.apply({foo:false})).toBe('-false-');
});
it("should stringify zero", function(){
tpl = new Ext.XTemplate('-{foo}-');
expect(tpl.apply({foo:0})).toBe('-0-');
});
it("should evaluate undefined as false", function(){
tpl = new Ext.XTemplate('foonot foo');
expect(tpl.apply({})).toBe('not foo');
});
it("should evaluate null as false", function(){
tpl = new Ext.XTemplate('foonot foo');
expect(tpl.apply({foo:null})).toBe('not foo');
});
it("should evaluate zero as false", function(){
tpl = new Ext.XTemplate('foonot foo');
expect(tpl.apply({foo:0})).toBe('not foo');
});
});
describe("formats", function() {
var appliedObject;
beforeEach(function() {
appliedObject = {a: "123", b: "456789"};
});
describe("enabled", function() {
beforeEach(function() {
tpl = new Ext.XTemplate(
'{a:ellipsis(2)}'
);
});
it("should call ellipsis", function() {
expect(tpl.apply(appliedObject)).toEqual('...');
});
});
describe("disabled", function() {
beforeEach(function() {
tpl = new Ext.XTemplate(
'{a:ellipsis(2)}',
{disableFormats: true}
);
});
it("should not call Ext.String.ellipsis", function() {
expect(tpl.apply(appliedObject)).toEqual('123');
});
});
describe('method', function () {
it('should call a basic method', function () {
tpl = new Ext.XTemplate(
'Linkify: {text:this.linkify}',
{
/**
* Simply wraps a link tag around each detected url
*/
linkify: function(value) {
return value.replace(/(http:\/\/[^\s]*)/g, "$1");
}
}
);
var s = tpl.apply({ text: 'This page http://foo.bar.com/foobar.html is cool' });
expect(s).toEqual('Linkify: This page http://foo.bar.com/foobar.html is cool');
});
});
});
describe("Ext.XTemplate.from", function() {
var elWithHtml, elWithValue;
beforeEach(function() {
elWithHtml = Ext.getBody().createChild({tag: "div", html:"FOO {0}."});
elWithValue = Ext.getBody().createChild({tag: "input"});
elWithValue.dom.value = "BAR {0}.";
});
afterEach(function() {
elWithHtml.remove();
elWithValue.remove();
});
it("should create a template with dom element innerHTML", function() {
tpl = Ext.XTemplate.from(elWithHtml);
expect(tpl.apply(['BAR'])).toEqual('FOO BAR.');
});
it("should create a template with dom element value", function() {
tpl = Ext.XTemplate.from(elWithValue);
expect(tpl.apply(['FOO'])).toEqual('BAR FOO.');
});
});
describe('strict mode', function () {
it('should throw when substitution token is invalid', function () {
var tpl = new Ext.XTemplate('{foo.bar.baz}', {
strict: true
});
expect(function () {
tpl.apply({});
}).toThrow();
});
it('should throw when for expression is invalid', function () {
var tpl = new Ext.XTemplate('{.}', {
strict: true
});
expect(function () {
tpl.apply({});
}).toThrow();
});
it('should throw when if expression is invalid', function () {
var tpl = new Ext.XTemplate('{.}', {
strict: true
});
expect(function () {
tpl.apply({});
}).toThrow();
});
});
});