/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ // Tests that the DOM Template engine works properly let tempScope = {}; Cu.import("resource:///modules/devtools/Templater.jsm", tempScope); Cu.import("resource:///modules/devtools/Promise.jsm", tempScope); let template = tempScope.template; let Promise = tempScope.Promise; function test() { addTab("http://example.com/browser/browser/devtools/shared/test/browser_templater_basic.html", function() { info("Starting DOM Templater Tests"); runTest(0); }); } function runTest(index) { var options = tests[index] = tests[index](); var holder = content.document.createElement('div'); holder.id = options.name; var body = content.document.body; body.appendChild(holder); holder.innerHTML = options.template; info('Running ' + options.name); template(holder, options.data, options.options); if (typeof options.result == 'string') { is(holder.innerHTML, options.result, options.name); } else { ok(holder.innerHTML.match(options.result), options.name); } if (options.also) { options.also(options); } function runNextTest() { index++; if (index < tests.length) { runTest(index); } else { finished(); } } if (options.later) { var ais = is.bind(this); function createTester(holder, options) { return function() { ais(holder.innerHTML, options.later, options.name + ' later'); runNextTest(); }.bind(this); } executeSoon(createTester(holder, options)); } else { runNextTest(); } } function finished() { gBrowser.removeCurrentTab(); info("Finishing DOM Templater Tests"); tests = null; finish(); } /** * Why have an array of functions that return data rather than just an array * of the data itself? Some of these tests contain calls to delayReply() which * sets up async processing using executeSoon(). Since the execution of these * tests is asynchronous, the delayed reply will probably arrive before the * test is executed, making the test be synchronous. So we wrap the data in a * function so we only set it up just before we use it. */ var tests = [ function() { return { name: 'simpleNesting', template: '
${nested.value}
', data: { nested:{ value:'pass 1' } }, result: '
pass 1
' };}, function() { return { name: 'returnDom', template: '
${__element.ownerDocument.createTextNode(\'pass 2\')}
', options: { allowEval: true }, data: {}, result: '
pass 2
' };}, function() { return { name: 'srcChange', template: '', data: { fred:'green.png' }, result: // };}, function() { return { name: 'ifTrue', template: '

hello ${name}

', options: { allowEval: true }, data: { name: 'fred' }, result: '

hello fred

' };}, function() { return { name: 'ifFalse', template: '

hello ${name}

', options: { allowEval: true }, data: { name: 'jim' }, result: '' };}, function() { return { name: 'simpleLoop', template: '

${index}

', options: { allowEval: true }, data: {}, result: '

1

2

3

' };}, function() { return { name: 'loopElement', template: '${i}', data: { array: [ 1, 2, 3 ] }, result: '123' };}, // Bug 692028: DOMTemplate memory leak with asynchronous arrays // Bug 692031: DOMTemplate async loops do not drop the loop element function() { return { name: 'asyncLoopElement', template: '${i}', data: { array: delayReply([1, 2, 3]) }, result: '', later: '123' };}, function() { return { name: 'saveElement', template: '

${name}

', data: { name: 'pass 8' }, result: '

pass 8

', also: function(options) { ok(options.data.element.innerHTML, 'pass 9', 'saveElement saved'); delete options.data.element; } };}, function() { return { name: 'useElement', template: '

${adjust(__element)}

', options: { allowEval: true }, data: { adjust: function(element) { is('pass9', element.id, 'useElement adjust'); return 'pass 9b' } }, result: '

pass 9b

' };}, function() { return { name: 'asyncInline', template: '${delayed}', data: { delayed: delayReply('inline') }, result: '', later: 'inline' };}, // Bug 692028: DOMTemplate memory leak with asynchronous arrays function() { return { name: 'asyncArray', template: '

${i}

', data: { delayed: delayReply([1, 2, 3]) }, result: '', later: '

1

2

3

' };}, function() { return { name: 'asyncMember', template: '

${i}

', data: { delayed: [delayReply(4), delayReply(5), delayReply(6)] }, result: '', later: '

4

5

6

' };}, // Bug 692028: DOMTemplate memory leak with asynchronous arrays function() { return { name: 'asyncBoth', template: '

${i}

', data: { delayed: delayReply([ delayReply(4), delayReply(5), delayReply(6) ]) }, result: '', later: '

4

5

6

' };}, // Bug 701762: DOMTemplate fails when ${foo()} returns undefined function() { return { name: 'functionReturningUndefiend', template: '

${foo()}

', options: { allowEval: true }, data: { foo: function() {} }, result: '

undefined

' };}, // Bug 702642: DOMTemplate is relatively slow when evaluating JS ${} function() { return { name: 'propertySimple', template: '

${a.b.c}

', data: { a: { b: { c: 'hello' } } }, result: '

hello

' };}, function() { return { name: 'propertyPass', template: '

${Math.max(1, 2)}

', options: { allowEval: true }, result: '

2

' };}, function() { return { name: 'propertyFail', template: '

${Math.max(1, 2)}

', result: '

${Math.max(1, 2)}

' };} ]; function delayReply(data) { var p = new Promise(); executeSoon(function() { p.resolve(data); }); return p; }