Hello
', - 'Hello
', - 'HTML.P("Hello")'); - - run([], '', '', '[]'); - run([null, null], '', '', '[null, null]'); - - // Test crazy character references - - // `𝕫` is "Mathematical double-struck small z" a.k.a. "open-face z" - run(P(CharRef({html: '𝕫', str: '\ud835\udd6b'})), - '\ud835\udd6b
', - '𝕫
', - 'HTML.P(HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"}))'); - - run(P({id: CharRef({html: '𝕫', str: '\ud835\udd6b'})}, 'Hello'), - 'Hello
', - 'Hello
', - 'HTML.P({id: HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"})}, "Hello")'); - - run(P({id: [CharRef({html: '𝕫', str: '\ud835\udd6b'}), '!']}, 'Hello'), - 'Hello
', - 'Hello
', - 'HTML.P({id: [HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"}), "!"]}, "Hello")'); - - // Test comments - - run(DIV(Comment('Test')), - '', // our innerHTML-canonicalization function kills comment contents - '', - 'HTML.DIV(HTML.Comment("Test"))'); - - // Test arrays - - run([P('Hello'), P('World')], - 'Hello
World
', - 'Hello
World
', - '[HTML.P("Hello"), HTML.P("World")]'); - - // Test slightly more complicated structure - - run(DIV({'class': 'foo'}, UL(LI(P(A({href: '#one'}, 'One'))), - LI(P('Two', BR(), 'Three')))), - 'Two
Three
Two
Three
Hello
'); - - var div = document.createElement("DIV"); - materialize(test1, div); - test.equal(canonicalizeHtml(div.innerHTML), "Hello
"); - - R.set('World'); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), "World
"); - })(); - - // Reactively change an array of text nodes - (function () { - var R = ReactiveVar(['Hello', ' World']); - var test1 = function () { - return P(Blaze.View(function () { return R.get(); })); - }; - - test.equal(toHTML(test1()), 'Hello World
'); - - var div = document.createElement("DIV"); - materialize(test1, div); - test.equal(canonicalizeHtml(div.innerHTML), "Hello World
"); - - R.set(['Goodbye', ' World']); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), "Goodbye World
"); - })(); - -}); - -// IE strips malformed styles like "bar::d" from the `style` -// attribute. We detect this to adjust expectations for the StyleHandler -// test below. -var malformedStylesAllowed = function () { - var div = document.createElement("div"); - div.setAttribute("style", "bar::d;"); - return (div.getAttribute("style") === "bar::d;"); -}; - -Tinytest.add("blaze - render - view GC", function (test) { - // test that removing parent element removes listeners and stops autoruns. - (function () { - var R = ReactiveVar('Hello'); - var test1 = P(Blaze.View(function () { return R.get(); })); - - var div = document.createElement("DIV"); - materialize(test1, div); - test.equal(canonicalizeHtml(div.innerHTML), "Hello
"); - - R.set('World'); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), "World
"); - - test.equal(R._numListeners(), 1); - - $(div).remove(); - - test.equal(R._numListeners(), 0); - - R.set('Steve'); - Tracker.flush(); - // should not have changed: - test.equal(canonicalizeHtml(div.innerHTML), "World
"); - })(); - -}); - -Tinytest.add("blaze - render - reactive attributes", function (test) { - (function () { - var R = ReactiveVar({'class': ['david gre', CharRef({html: 'ë', str: '\u00eb'}), 'nspan'], - id: 'foo'}); - - var spanFunc = function () { - return SPAN(HTML.Attrs( - function () { return R.get(); })); - }; - - test.equal(Blaze.toHTML(spanFunc()), - ''); - - test.equal(R._numListeners(), 0); - - var div = document.createElement("DIV"); - Blaze.render(spanFunc, div); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - test.equal(R._numListeners(), 1); - - var span = div.firstChild; - test.equal(span.nodeName, 'SPAN'); - span.className += ' blah'; // change the element's class outside of Blaze. this simulates what a jQuery could do - - R.set({'class': 'david smith', id: 'bar'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - test.equal(R._numListeners(), 1); - - R.set({}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - test.equal(R._numListeners(), 1); - - $(div).remove(); - - test.equal(R._numListeners(), 0); - })(); - - // Test styles. - (function () { - // Test the case where there is a semicolon in the css attribute. - var R = ReactiveVar({'style': 'foo: "a;aa"; bar: b;', - id: 'foo'}); - - var spanFunc = function () { - return SPAN(HTML.Attrs(function () { return R.get(); })); - }; - - test.equal(Blaze.toHTML(spanFunc()), ''); - - test.equal(R._numListeners(), 0); - - var div = document.createElement("DIV"); - Blaze.render(spanFunc, div); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - test.equal(R._numListeners(), 1); - var span = div.firstChild; - test.equal(span.nodeName, 'SPAN'); - - span.setAttribute('style', span.getAttribute('style') + '; jquery-style: hidden'); - - R.set({'style': 'foo: "a;zz;aa";', id: 'bar'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML, true), ''); - test.equal(R._numListeners(), 1); - - R.set({}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - test.equal(R._numListeners(), 1); - - $(div).remove(); - - test.equal(R._numListeners(), 0); - })(); - - // Test that identical styles are successfully overwritten. - (function () { - - var R = ReactiveVar({'style': 'foo: a;'}); - - var spanFunc = function () { - return SPAN(HTML.Attrs(function () { return R.get(); })); - }; - - var div = document.createElement("DIV"); - document.body.appendChild(div); - Blaze.render(spanFunc, div); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - var span = div.firstChild; - test.equal(span.nodeName, 'SPAN'); - span.setAttribute("style", 'foo: b;'); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({'style': 'foo: c;'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - // test malformed styles - different expectations in IE (which - // strips malformed styles) from other browsers - R.set({'style': 'foo: a; bar::d;:e; baz: c;'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), - malformedStylesAllowed() ? - '' : - ''); - - // Test strange styles - R.set({'style': ' foo: c; constructor: a; __proto__: b;'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({'style': 'foo: bar;'}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - })(); - - // Test `null`, `undefined`, and `[]` attributes - (function () { - var R = ReactiveVar({id: 'foo', - aaa: null, - bbb: undefined, - ccc: [], - ddd: [null], - eee: [undefined], - fff: [[]], - ggg: ['x', ['y', ['z']]]}); - - var spanFunc = function () { - return SPAN(HTML.Attrs( - function () { return R.get(); })); - }; - - test.equal(Blaze.toHTML(spanFunc()), ''); - test.equal(toCode(SPAN(R.get())), - 'HTML.SPAN({id: "foo", ggg: ["x", ["y", ["z"]]]})'); - - var div = document.createElement("DIV"); - Blaze.render(spanFunc, div); - var span = div.firstChild; - test.equal(span.nodeName, 'SPAN'); - - test.equal(canonicalizeHtml(div.innerHTML), ''); - R.set({id: 'foo', ggg: [[], [], []]}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({id: 'foo', ggg: null}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({id: 'foo', ggg: ''}); - Tracker.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - $(div).remove(); - - test.equal(R._numListeners(), 0); - })(); -}); - -Tinytest.add("blaze - render - templates and views", function (test) { - (function () { - var counter = 1; - var buf = []; - - var myTemplate = Blaze.Template( - 'myTemplate', - function () { - return [String(this.number), - (this.number < 3 ? makeView() : HR())]; - }); - - myTemplate.constructView = function (number) { - var view = Template.prototype.constructView.call(this); - view.number = number; - return view; - }; - - myTemplate.created = function () { - test.isFalse(Tracker.active); - var view = this.view; - var parent = Blaze.getView(view, 'myTemplate'); - if (parent) { - buf.push('parent of ' + view.number + ' is ' + - parent.number); - } - - buf.push('created ' + Template.currentData()); - }; - - myTemplate.onRendered(function () { - test.isFalse(Tracker.active); - var nodeDescr = function (node) { - if (node.nodeType === 8) // comment - return ''; - if (node.nodeType === 3) // text - return node.nodeValue; - - return node.nodeName; - }; - - var view = this.view; - var start = view.firstNode(); - var end = view.lastNode(); - // skip marker nodes - while (start !== end && ! nodeDescr(start)) - start = start.nextSibling; - while (end !== start && ! nodeDescr(end)) - end = end.previousSibling; - - buf.push('dom-' + Template.currentData() + - ' is ' + nodeDescr(start) +'..' + - nodeDescr(end)); - }); - - myTemplate.onDestroyed(function () { - test.isFalse(Tracker.active); - buf.push('destroyed ' + Template.currentData()); - }); - - var makeView = function () { - var number = counter++; - return Blaze.With(number, function () { - return myTemplate.constructView(number); - }); - }; - - var div = document.createElement("DIV"); - - Blaze.render(makeView, div); - buf.push('---flush---'); - Tracker.flush(); - test.equal(buf, ['created 1', - 'parent of 2 is 1', - 'created 2', - 'parent of 3 is 2', - 'created 3', - '---flush---', - // (proper order for these has not be thought out:) - 'dom-3 is 3..HR', - 'dom-2 is 2..HR', - 'dom-1 is 1..HR']); - - test.equal(canonicalizeHtml(div.innerHTML), '123