UNPKG

can-stache

Version:

Live binding handlebars templates

171 lines (126 loc) 5.82 kB
var QUnit = require("steal-qunit"); var stache = require("can-stache"); var DefineMap = require("can-define/map/map"); var globals = require("can-globals"); var domMutate = require("can-dom-mutate"); var domMutateNode = require("can-dom-mutate/node"); var canSymbol = require("can-symbol"); var stacheTestHelpers = require("../test/helpers")(document); require("./-portal"); QUnit.module("can-stache #portal helper"); QUnit.test("basics", function(assert) { var el = document.createElement("div"); var template = stache("{{#portal(root)}}hello {{name}}{{/portal}}"); var vm = new DefineMap({name: "Matthew", root: el}); template(vm); var cleaned = stacheTestHelpers.cloneAndClean(el); assert.equal(cleaned.firstChild.nextSibling.nodeValue, "Matthew"); vm.name ="Wilbur"; assert.equal(stacheTestHelpers.cloneAndClean(el).firstChild.nextSibling.nodeValue, "Wilbur"); }); QUnit.test("element is observable", function(assert) { var el = document.createElement("div"); var template = stache("{{#portal(root)}}{{name}}{{/}}"); var vm = new DefineMap({name: "Matthew", root: null}); template(vm); vm.root = el; assert.equal(stacheTestHelpers.cloneAndClean(el).firstChild.nodeValue, "Matthew"); }); QUnit.test("element changes", function(assert) { var one = document.createElement("div"); var two = document.createElement("div"); var template = stache("{{#portal(root)}}{{name}}{{/}}"); var vm = new DefineMap({name: "Matthew", root: one}); template(vm); assert.equal(stacheTestHelpers.cloneAndClean(one).firstChild.nodeValue, "Matthew"); vm.root = two; assert.equal(stacheTestHelpers.cloneAndClean(two).firstChild.nodeValue, "Matthew"); assert.equal(one.firstChild, null, "One had its children removed"); }); QUnit.test("tears down when the element is removed", function(assert) { var doc = document.implementation.createHTMLDocument("test"); globals.setKeyValue("document", doc); var el = doc.createElement("div"); domMutateNode.appendChild.call(doc.body, el); var template = stache("{{#portal(root)}}{{name}}{{/}}"); var vm = new DefineMap({name: "Matthew", root: el}); template(vm); assert.equal(stacheTestHelpers.cloneAndClean(el).firstChild.nodeValue, "Matthew"); var done = assert.async(); domMutate.onNodeRemoved(el, function() { // parent nodes removed is always called first ... this fixes it setTimeout(function(){ assert.equal( vm[canSymbol.for("can.meta")].handlers.get(["name"]).length, 0, "no handlers"); done(); },1); }); domMutateNode.removeChild.call(doc.body, el); }); QUnit.test("conditionally rendering a portal", function(assert) { var one = document.createElement("div"); var two = document.createElement("span"); var template = stache("{{#eq(page, 'one')}}{{#portal(this.one)}}{{name}}{{/portal}}{{/eq}}" + "{{#eq(page, 'two')}}{{#portal(this.two)}}{{name}}{{/portal}}{{/eq}}"); var vm = new DefineMap({page: "one", name: "Matthew", one: one, two: two}); template(vm); assert.equal(stacheTestHelpers.cloneAndClean(one).firstChild.nodeValue, "Matthew"); assert.equal(stacheTestHelpers.cloneAndClean(two).firstChild, null, "nothing rendered to two"); vm.page = "two"; assert.equal(stacheTestHelpers.cloneAndClean(one).firstChild, null, "nothing rendered to one"); assert.equal(stacheTestHelpers.cloneAndClean(two).firstChild.nodeValue, "Matthew"); }); QUnit.test("Doesn't mess with existing DOM", function(assert) { var el = document.createElement("div"); el.appendChild(document.createTextNode("Hello")); var template = stache("{{#portal(root)}}{{name}}{{/portal}}"); var vm = new DefineMap({name: "Matthew", root: el}); template(vm); assert.equal(stacheTestHelpers.cloneAndClean(el).firstChild.nodeValue, "Hello", "existing content left alone"); assert.equal(stacheTestHelpers.cloneAndClean(el).firstChild.nextSibling.nodeValue, "Matthew"); }); QUnit.test("Adds the done.keepNode symbol to nodes", function(assert) { var el = document.createElement("div"); var template = stache("{{#portal(root)}}<span>one</span><div>two</div>{{/portal}}"); var vm = new DefineMap({ root: el }); template(vm); var child = el.firstChild; do { assert.ok(child[canSymbol.for("done.keepNode")], "symbol added to this node"); child = child.nextSibling; } while(child); }); QUnit.test("Doesn't do anything if there isn't a place to put the content", function(assert) { var view = stache("{{#portal(root)}}<span>two</span>{{/portal}}"); var vm = new DefineMap({ root: null }); var frag = view(vm); assert.equal(frag.firstChild.nodeType, 8, "Only rendered the comment node"); }); QUnit.test("Dynamic content outside portal", function(assert) { var view = stache("{{#portal(root)}}<span>two</span>{{/portal}}<div>{{#if(showThing)}}<span>one</span>{{/if}}</div>"); var vm = new DefineMap({ showThing: false, root: null }); var frag = view(vm); var div = frag.querySelector("div"); assert.equal(div.firstChild.firstChild, null, "nothing rendered in the div yet"); // Flip the conditional vm.showThing = true; assert.equal(stacheTestHelpers.cloneAndClean(div).firstChild.firstChild.nodeValue, "one", "shows the template content"); // Set the element vm.root = div; assert.equal(stacheTestHelpers.cloneAndClean(div).firstChild.nextSibling.firstChild.nodeValue, "two", "shows the portaled content"); }); QUnit.test("Works when DOM nodes are removed outside of stache", function(assert) { var view = stache("{{#if(show)}}{{#portal(root)}} <span>tests</span> {{/portal}}{{/if}}"); var root = document.createElement("div"); var vm = new DefineMap({ root: root, show: true }); view(vm); var badScript = function() { domMutateNode.removeChild.call(root, root.firstChild); }; badScript(); try { vm.show = false; assert.ok(true, "Did not throw"); } catch(e) { assert.ok(false, e); } });