UNPKG

dom-layer

Version:
459 lines (309 loc) 15.2 kB
var h = require('../helper/h'); var _ = require('../helper/util'); var Tree = require('../../src/tree/tree'); describe("Tree", function() { var testBody, tree, mountPoint, parentNode; beforeEach(function() { testBody = document.getElementById('test'); testBody.innerHTML = '<div id="mount-point"></div>'; mountPoint = document.getElementById('mount-point'); parentNode = mountPoint.parentNode; tree = new Tree(); }) afterEach(function() { testBody.innerHTML = ''; }); describe(".mount()", function() { it("mounts a virtual tree", function() { var mountId = tree.mount('#mount-point', h({}, ['#1', '#2', '#3'])); expect(mountPoint.textContent).toBe('#1#2#3'); expect(mountPoint.domLayerTreeId).toBe(mountId); }); it("mounts in a transcluded way", function() { var mountId = tree.mount('#mount-point', function() { return h({}, ['#1', '#2', '#3']); } , { transclude: true }); expect(mountPoint.parentNode).toBe(null); expect(mountPoint.textContent).toBe(''); expect(parentNode.textContent).toBe('#1#2#3'); }); it("mounts/unmounts nested transclusions", function() { var mounted; var mountId1 = tree.mount('#mount-point', function() { return h({ attrs: { id: 'mount-point2' } }); }, { transclude: true }); expect(parentNode.childNodes[0].id).toBe('mount-point2'); mounted = tree.mounted(mountId1); expect(mounted.element).toBe(document.getElementById('mount-point2')); expect(mounted.children[0].element).toBe(document.getElementById('mount-point2')); var mountId2 = tree.mount(parentNode.childNodes[0], function() { return h({ attrs: { id: 'mount-point3' } }); }, { transclude: true }); expect(parentNode.childNodes[0].id).toBe('mount-point3'); mounted = tree.mounted(mountId1); expect(mounted.element).toBe(document.getElementById('mount-point3')); expect(mounted.children[0].element).toBe(document.getElementById('mount-point3')); mounted = tree.mounted(mountId2); expect(mounted.element).toBe(document.getElementById('mount-point3')); expect(mounted.children[0].element).toBe(document.getElementById('mount-point3')); var mountId3 = tree.mount(parentNode.childNodes[0], function() { return h({ attrs: { id: 'mount-point4' } }); }, { transclude: true }); expect(parentNode.childNodes[0].id).toBe('mount-point4'); mounted = tree.mounted(mountId1); expect(mounted.element).toBe(document.getElementById('mount-point4')); expect(mounted.children[0].element).toBe(document.getElementById('mount-point4')); mounted = tree.mounted(mountId2); expect(mounted.element).toBe(document.getElementById('mount-point4')); expect(mounted.children[0].element).toBe(document.getElementById('mount-point4')); mounted = tree.mounted(mountId3); expect(mounted.element).toBe(document.getElementById('mount-point4')); expect(mounted.children[0].element).toBe(document.getElementById('mount-point4')); tree.unmount(mountId3); expect(parentNode.childNodes[0].id).toBe('mount-point3'); mounted = tree.mounted(mountId1); expect(mounted.element).toBe(document.getElementById('mount-point3')); expect(mounted.children[0].element).toBe(document.getElementById('mount-point3')); mounted = tree.mounted(mountId2); expect(mounted.element).toBe(document.getElementById('mount-point3')); expect(mounted.children[0].element).toBe(document.getElementById('mount-point3')); tree.unmount(mountId2); expect(parentNode.childNodes[0].id).toBe('mount-point2'); mounted = tree.mounted(mountId1); expect(mounted.element).toBe(document.getElementById('mount-point2')); expect(mounted.children[0].element).toBe(document.getElementById('mount-point2')); tree.unmount(mountId1); expect(parentNode.childNodes[0].id).toBe('mount-point'); }); it("mounts a virtual tree using a custom UUID identifier", function() { var bookedId = tree.uuid(); var mountId = tree.mount('#mount-point', h({}, ['#1', '#2', '#3']), { mountId: bookedId }); expect(mountPoint.textContent).toBe('#1#2#3'); expect(mountPoint.domLayerTreeId).toBe(mountId); expect(bookedId).toBe(mountId); }); it("mounts a factory", function() { var mountId = tree.mount('#mount-point', function() { return h({}, ['#1', '#2', '#3']); }); expect(mountPoint.textContent).toBe('#1#2#3'); }); it("auto unmounts a already mounted virtual tree on mount", function() { var mountId1 = tree.mount('#mount-point', h({}, ['#1', '#2', '#3'])); expect(mountPoint.textContent).toBe('#1#2#3'); expect(mountPoint.domLayerTreeId).toBe(mountId1); var mountId2 = tree.mount('#mount-point', h({}, ['#4', '#5', '#6'])); expect(mountPoint.textContent).toBe('#4#5#6'); expect(mountPoint.domLayerTreeId).toBe(mountId2); expect(Object.keys(tree.mounted())).toEqual([mountId2]); }); it("broadcast the `inserted` hook on mount", function() { var params; var tag = h({ hooks: { inserted : function() { params = Array.prototype.slice.call(arguments); } } }); var mountId = tree.mount('#mount-point', tag); expect(params).toEqual([tag, tag.element]); }); it("throw an error when trying to transclude unsing a non unique DOM element", function() { var closure = function() { var mountId = tree.mount('#mount-point', function() { return [h({}, ['#1']), h({}, ['#2'])]; } , { transclude: true }); }; expect(closure).toThrow(new Error('Transclusion requires a single DOMElement to transclude.')); }); it("throw an error when trying to use a selector which doesn't identify a unique DOM element", function() { testBody.innerHTML = '<div class="mount-point"></div><div class="mount-point"></div>'; var closure = function() { tree.mount('.mount-point', h()); }; expect(closure).toThrow(new Error('The selector must identify an unique DOM element.')); }); }); describe(".attach()", function() { it("attaches a previously rendered html using a function", function() { testBody.innerHTML = '<div id="mount-point"><button>Click me!</button></div>'; var from = function() { return h({ tagName: 'button', events: { onclick: onclick} }, ['Click me!']); }; var mountId = tree.attach('#mount-point', from); var mountPoint = document.getElementById('mount-point'); expect(mountPoint.innerHTML).toBe('<button>Click me!</button>'); expect(mountPoint.domLayerTreeId).toBe(mountId); var mount = tree.mounted(mountId); expect(mount.children[0].element).toBe(mountPoint.childNodes[0]); expect(mount.children[0].element.textContent).toBe('Click me!'); }); it("populates domLayerNode when `events` is set", function() { testBody.innerHTML = '<div id="mount-point"><button>Click me!</button></div>'; var onclick = function () {}; var from = h({ tagName: 'button', events: { onclick: onclick} }, ['Click me!']); var mountId = tree.attach('#mount-point', from); var mountPoint = document.getElementById('mount-point'); expect(mountPoint.innerHTML).toBe('<button>Click me!</button>'); expect(mountPoint.domLayerTreeId).toBe(mountId); expect(from.element).toBe(mountPoint.childNodes[0]); expect(from.element.textContent).toBe('Click me!'); expect(from.element.domLayerNode).toBe(from); expect(from.element.domLayerNode.events.onclick).toBe(onclick); }); it("manages the consecutive textual nodes edge case", function() { testBody.innerHTML = '<div id="mount-point"><div>#1#2#3</div></div>'; var from = h({}, ['#1', '#2', '#3']); var mountId = tree.attach('#mount-point', from); var mountPoint = document.getElementById('mount-point'); expect(mountPoint.textContent).toBe('#1#2#3'); expect(mountPoint.domLayerTreeId).toBe(mountId); expect(from.element).toBe(mountPoint.childNodes[0]); var children = from.children; var childNodes = mountPoint.childNodes; expect(children[0].element).toBe(childNodes[0].childNodes[0]); expect(children[0].element.textContent).toBe('#1#2#3'); expect(children[0].data).toBe('#1#2#3'); expect(children[1].data).toBe(''); expect(children[2].data).toBe(''); }); it("throw an error when trying to use a selector which doesn't identify a unique DOM element", function() { testBody.innerHTML = '<div class="mount-point"></div><div class="mount-point"></div>'; var closure = function() { tree.attach('.mount-point', h()); }; expect(closure).toThrow(new Error('The selector must identify an unique DOM element.')); }); it("ignores `null` virtual nodes", function() { testBody.innerHTML = '<div id="mount-point"><button>Click me!</button></div>'; var from = h({ tagName: 'button', events: { onclick: onclick} }, [null, 'Click me!', null]); var mountId = tree.attach('#mount-point', from); var mountPoint = document.getElementById('mount-point'); expect(mountPoint.innerHTML).toBe('<button>Click me!</button>'); expect(mountPoint.domLayerTreeId).toBe(mountId); var mount = tree.mounted(mountId); expect(mount.children[0].element).toBe(mountPoint.childNodes[0]); expect(mount.children[0].element.textContent).toBe('Click me!'); }); }); describe(".umount()", function() { it("unmounts a virtual tree", function() { var mountId = tree.mount('#mount-point', h({}, ['#1', '#2', '#3'])); expect(mountPoint.textContent).toBe('#1#2#3'); tree.unmount(mountId); expect(mountPoint.textContent).toBe(''); expect(mountPoint.domLayerTreeId).toBe(undefined); }); it("umounts a transcluded mount", function() { var mountId = tree.mount('#mount-point', function() { return h({}, ['#1', '#2', '#3']); } , { transclude: true }); tree.unmount(mountId); expect(mountPoint.parentNode).toBe(parentNode); expect(mountPoint.textContent).toBe(''); expect(mountPoint.domLayerTreeId).toBe(undefined); }); it("unmounts all virtual trees", function() { var mountId = tree.mount('#mount-point', h({}, ['#1', '#2', '#3'])); expect(mountPoint.textContent).toBe('#1#2#3'); tree.unmount(); expect(mountPoint.textContent).toBe(''); expect(mountPoint.domLayerTreeId).toBe(undefined); }); it("bails out with an invalid mount id", function() { var mountId = tree.mount('#mount-point', h({}, ['#1', '#2', '#3'])); expect(mountPoint.textContent).toBe('#1#2#3'); tree.unmount('abc'); expect(mountPoint.textContent).toBe('#1#2#3'); expect(mountPoint.domLayerTreeId).toBe(mountId); }); }); describe(".update()", function() { it("updates a mounted tree", function() { testBody.innerHTML = '<div id="mount-point"></div>'; var mountId = tree.mount('#mount-point', h({ tagName: 'div' }, ['from'])); tree.update(mountId, h({ tagName: 'span' }, ['to'])); var mountPoint = document.getElementById('mount-point'); expect(mountPoint.textContent).toBe('to'); }); it("updates a mounted tree using a factory", function() { function Component() { this.order = 'asc'; } Component.prototype.render = function() { var children = ['#1', '#2', '#3']; if (this.order !== 'asc') { children.reverse(); } return h({}, children); }; var component = new Component(); var mountId = tree.mount('#mount-point', component.render.bind(component)); expect(mountPoint.textContent).toBe('#1#2#3'); component.order = 'desc'; tree.update(mountId); expect(mountPoint.textContent).toBe('#3#2#1'); }); it("updates all mounted trees", function() { testBody.innerHTML = '<div id="mount-point"></div><div id="mount-point2"></div>'; function Component() { this.order = 'asc'; } Component.prototype.render = function() { var children = ['#1', '#2', '#3']; if (this.order !== 'asc') { children.reverse(); } return h({}, children); }; var component = new Component(); var mountId = tree.mount('#mount-point', component.render.bind(component)); var mountPoint = document.getElementById('mount-point'); expect(mountPoint.textContent).toBe('#1#2#3'); var component2 = new Component(); var mountId2 = tree.mount('#mount-point2', component2.render.bind(component2)); var mountPoint2 = document.getElementById('mount-point2'); expect(mountPoint2.textContent).toBe('#1#2#3'); component.order = 'desc'; component2.order = 'desc'; tree.update(); expect(mountPoint.textContent).toBe('#3#2#1'); expect(mountPoint2.textContent).toBe('#3#2#1'); }); it("maintains focus", function () { var from = [ h({ tagName: 'input', key: 0, attrs: { id: 'input1' } }), h({ tagName: 'input', key: 1, attrs: { id: 'input2' } }), h({ tagName: 'input', key: 2, attrs: { id: 'input3' } }), h({ tagName: 'input', key: 3, attrs: { id: 'input4' } }) ]; var to = [ h({ tagName: 'input', key: 1, attrs: { id: 'input2' } }), h({ tagName: 'input', key: 2, attrs: { id: 'input3' } }), h({ tagName: 'input', key: 3, attrs: { id: 'input4' } }), h({ tagName: 'input', key: 0, attrs: { id: 'input1' } }) ]; var mountId = tree.mount('#mount-point', from); var input = document.getElementById('input1'); input.focus(); expect(input).toBe(document.activeElement); tree.update(mountId, to); expect(input).toBe(document.activeElement); }); it("ignores updates with invalid id", function() { expect(tree.update('invalid_id')).toBe(undefined); }); }); describe(".mounted()", function() { it("returns the definition of a mount", function() { var children = h({}, ['#1', '#2', '#3']); var mountId = tree.mount('#mount-point', children, { custom: 'custom' }); expect(mountPoint.textContent).toBe('#1#2#3'); var mounted = tree.mounted(mountId); expect(mounted.element).toBe(mountPoint); expect(mounted.factory).toBe(children); expect(mounted.custom).toBe('custom'); }); it("returns the definition of all mounts", function() { var children = h({}, ['#1', '#2', '#3']); var mountId = tree.mount('#mount-point', children, { custom: 'custom' }); expect(mountPoint.textContent).toBe('#1#2#3'); var mounted = tree.mounted(); expect(mounted[mountId].element).toBe(mountPoint); expect(mounted[mountId].factory).toBe(children); expect(mounted[mountId].custom).toBe('custom'); }); }); });