diff -r 000000000000 -r 6474c204b198 browser/devtools/shared/test/browser_templater_basic.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/browser/devtools/shared/test/browser_templater_basic.js Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,288 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the DOM Template engine works properly + +/* + * These tests run both in Mozilla/Mochitest and plain browsers (as does + * domtemplate) + * We should endevour to keep the source in sync. + */ + +var promise = Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {}).Promise; +var template = Cu.import("resource://gre/modules/devtools/Templater.jsm", {}).template; + +const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/browser_templater_basic.html"; + +function test() { + addTab(TEST_URI, 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) != null, + options.name + ' result=\'' + holder.innerHTML + '\''); + } + + 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: '
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: '${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)}
' + };}, + + // Bug 723431: DOMTemplate should allow customisation of display of + // null/undefined values + function() { return { + name: 'propertyUndefAttrFull', + template: '${nullvar}|${undefinedvar1}|${undefinedvar2}
', + data: { nullvar: null, undefinedvar1: undefined }, + result: 'null|undefined|undefined
' + };}, + + function() { return { + name: 'propertyUndefAttrBlank', + template: '${nullvar}|${undefinedvar1}|${undefinedvar2}
', + data: { nullvar: null, undefinedvar1: undefined }, + options: { blankNullUndefined: true }, + result: '||
' + };}, + + function() { return { + name: 'propertyUndefAttrFull', + template: '