/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; // 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. */ const {template} = require("devtools/shared/gcli/templater"); const TEST_URI = TEST_URI_ROOT + "browser_templater_basic.html"; var test = Task.async(function* () { yield addTab("about:blank"); let [host,, doc] = yield createHost("bottom", TEST_URI); info("Starting DOM Templater Tests"); runTest(0, host, doc); }); function runTest(index, host, doc) { let options = tests[index] = tests[index](); let holder = doc.createElement("div"); holder.id = options.name; let body = doc.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, host, doc); } else { finished(host); } } if (options.later) { let ais = is.bind(this); function createTester(testHolder, testOptions) { return () => { ais(testHolder.innerHTML, testOptions.later, testOptions.name + " later"); runNextTest(); }; } executeSoon(createTester(holder, options)); } else { runNextTest(); } } function finished(host) { host.destroy(); 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 = [ () => ({ name: "simpleNesting", template: '
${nested.value}
', data: { nested: { value: "pass 1" } }, result: '
pass 1
' }), () => ({ name: "returnDom", template: '
${__element.ownerDocument.createTextNode(\'pass 2\')}
', options: { allowEval: true }, data: {}, result: '
pass 2
' }), () => ({ name: "srcChange", template: '', data: { fred: "green.png" }, result: // }), () => ({ name: "ifTrue", template: '

hello ${name}

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

hello fred

" }), () => ({ name: "ifFalse", template: '

hello ${name}

', options: { allowEval: true }, data: { name: "jim" }, result: "" }), () => ({ name: "simpleLoop", template: '

${index}

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

1

2

3

" }), () => ({ 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 () => ({ name: "asyncLoopElement", template: '${i}', data: { array: delayReply([1, 2, 3]) }, result: "", later: "123" }), () => ({ 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; } }), () => ({ name: "useElement", template: '

${adjust(__element)}

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

pass 9b

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

${i}

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

1

2

3

" }), () => ({ 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 () => ({ 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 () => ({ name: "functionReturningUndefiend", template: "

${foo()}

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

undefined

" }), // Bug 702642: DOMTemplate is relatively slow when evaluating JS ${} () => ({ name: "propertySimple", template: "

${a.b.c}

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

hello

" }), () => ({ name: "propertyPass", template: "

${Math.max(1, 2)}

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

2

" }), () => ({ name: "propertyFail", template: "

${Math.max(1, 2)}

", result: "

${Math.max(1, 2)}

" }), // Bug 723431: DOMTemplate should allow customisation of display of // null/undefined values () => ({ name: "propertyUndefAttrFull", template: "

${nullvar}|${undefinedvar1}|${undefinedvar2}

", data: { nullvar: null, undefinedvar1: undefined }, result: "

null|undefined|undefined

" }), () => ({ name: "propertyUndefAttrBlank", template: "

${nullvar}|${undefinedvar1}|${undefinedvar2}

", data: { nullvar: null, undefinedvar1: undefined }, options: { blankNullUndefined: true }, result: "

||

" }), /* eslint-disable max-len */ () => ({ name: "propertyUndefAttrFull", template: '

', data: { nullvar: null, undefinedvar1: undefined }, result: '

' }), () => ({ name: "propertyUndefAttrBlank", template: '

', data: { nullvar: null, undefinedvar1: undefined }, options: { blankNullUndefined: true }, result: '

' }) /* eslint-enable max-len */ ]; function delayReply(data) { return new Promise(resolve => resolve(data)); }