@ryanmorr/templar
Version:
A simple and versatile DOM templating engine
233 lines (176 loc) • 7.83 kB
JavaScript
import templar from '../../src/templar';
describe('nodes', () => {
const root = document.createElement('div');
beforeEach(() => {
root.innerHTML = '';
});
it('should update text nodes', () => {
const tpl = templar('{{foo}}', {foo: 'bar'});
tpl.mount(root);
expect(root.innerHTML).to.equal('bar');
tpl.set('foo', 'baz');
expect(root.innerHTML).to.equal('baz');
tpl.set('foo', 123);
expect(root.innerHTML).to.equal('123');
});
it('should update element nodes', () => {
const tpl = templar('<div>{{foo}}</div>', {foo: 'bar'});
tpl.mount(root);
expect(root.innerHTML).to.equal('<div>bar</div>');
tpl.set('foo', 'baz');
expect(root.innerHTML).to.equal('<div>baz</div>');
});
it('should updates multiple tokens within an element', () => {
const tpl = templar('<div>{{foo}} {{bar}}</div>');
tpl.mount(root);
tpl.set('foo', '123');
tpl.set('bar', '456');
expect(root.innerHTML).to.equal('<div>123 456</div>');
tpl.set('bar', '789');
expect(root.innerHTML).to.equal('<div>123 789</div>');
});
it('should support leading and trailing spaces between delimiters of tokens', () => {
const tpl = templar('<div>{{ foo }}</div>');
tpl.mount(root);
tpl.set('foo', 'bar');
expect(root.innerHTML).to.equal('<div>bar</div>');
});
it('should support the same token more than once', () => {
const tpl = templar('<div>{{foo}}</div><span>{{foo}}</span>');
tpl.mount(root);
tpl.set('foo', 'bar');
expect(root.innerHTML).to.equal('<div>bar</div><span>bar</span>');
});
it('should support setting multiple values via a key/value map', () => {
const tpl = templar('<div>{{foo}}</div><span>{{bar}}</span>');
tpl.mount(root);
tpl.set({foo: 123, bar: 456});
expect(root.innerHTML).to.equal('<div>123</div><span>456</span>');
});
it('should support interpolation with a DOM node', () => {
const tpl = templar('<div>{{foo}}</div>');
tpl.mount(root);
const el = document.createElement('strong');
tpl.set('foo', el);
expect(root.innerHTML).to.equal('<div><strong></strong></div>');
expect(root.querySelector('strong')).to.equal(el);
});
it('should support interpolation with a DOM fragment', () => {
const tpl = templar('<div>{{foo}}</div>');
tpl.mount(root);
const frag = document.createDocumentFragment();
for (let i = 0; i < 3; i++) frag.appendChild(document.createTextNode(i));
tpl.set('foo', frag);
expect(root.innerHTML).to.equal('<div>012</div>');
});
it('should parse an HTML string by default', () => {
const tpl = templar('<div>{{foo}}</div>');
tpl.mount(root);
tpl.set('foo', '<strong>foo</strong>');
expect(root.innerHTML).to.equal('<div><strong>foo</strong></div>');
});
it('should escape HTML characters if the token is immediately preceeded by an ampersand', () => {
const tpl = templar('<div>{{&foo}}</div>');
tpl.mount(root);
tpl.set('foo', '<i id="foo" class=\'bar\'>baz</i>');
expect(root.innerHTML).to.equal('<div><i id="foo" class=\'bar\'>baz</i></div>');
});
it('should support nested templates', () => {
const tpl1 = templar('<div>{{foo}}</div>');
const tpl2 = templar('<em>{{bar}}</em>');
const tpl3 = templar('<strong>{{baz}}</strong>');
tpl1.mount(root);
tpl1.set('foo', tpl2);
tpl2.set('bar', tpl3);
tpl3.set('baz', 'qux');
expect(root.innerHTML).to.equal('<div><em><strong>qux</strong></em></div>');
tpl3.set('baz', 'quxx');
expect(root.innerHTML).to.equal('<div><em><strong>quxx</strong></em></div>');
tpl1.set('foo', '123');
expect(root.innerHTML).to.equal('<div>123</div>');
});
it('should update multiple elements between existing elements', () => {
const tpl1 = templar('<div>123 {{foo}} 456 {{bar}} 789 {{baz}} 101112</div>');
const tpl2 = templar('<div>{{a}}</div><div>{{b}}</div>');
tpl1.mount(root);
const frag = document.createDocumentFragment();
for (let i = 0; i < 3; i++) {
const div = document.createElement('em');
div.textContent = i;
frag.appendChild(div);
}
tpl1.set('foo', tpl2);
tpl1.set('bar', '<span>a</span><span>b</span>');
tpl1.set('baz', frag);
tpl2.set('a', 1);
tpl2.set('b', 2);
expect(root.innerHTML).to.equal('<div>123 <div>1</div><div>2</div> 456 <span>a</span><span>b</span> 789 <em>0</em><em>1</em><em>2</em> 101112</div>');
tpl1.set('foo', 'abc');
tpl1.set('bar', 'def');
tpl1.set('baz', 'ghi');
expect(root.innerHTML).to.equal('<div>123 abc 456 def 789 ghi 101112</div>');
tpl1.set('foo', tpl2);
tpl2.set('a', 3);
expect(root.innerHTML).to.equal('<div>123 <div>3</div><div>2</div> 456 def 789 ghi 101112</div>');
});
it('should not render the token until it is defined', () => {
const tpl = templar('<div>{{foo}}</div>');
tpl.mount(root);
expect(root.innerHTML).to.equal('<div></div>');
tpl.set('foo', 'bar');
expect(root.innerHTML).to.equal('<div>bar</div>');
});
it('should emit a "change" custom event when a node is updated', () => {
const tpl = templar('<div>{{foo}}</div>');
const div = tpl.query('div')[0];
const onChange = sinon.spy((el) => {
expect(el).to.equal(div);
});
tpl.on('change', onChange);
tpl.set('foo', 'bar');
expect(onChange.called).to.equal(true);
});
it('should not emit a "change" custom event if a node is updated with the same value', () => {
const tpl = templar('<div>{{foo}}</div>');
const onChange = sinon.spy();
tpl.on('change', onChange);
const bar = document.createTextNode('bar');
tpl.set('foo', bar);
expect(onChange.callCount).to.equal(1);
tpl.set('foo', bar);
expect(onChange.callCount).to.equal(1);
const span = document.createElement('span');
tpl.set('foo', span);
expect(onChange.callCount).to.equal(2);
tpl.set('foo', span);
expect(onChange.callCount).to.equal(2);
const em = templar('<em></em>');
tpl.set('foo', em);
expect(onChange.callCount).to.equal(3);
tpl.set('foo', em);
expect(onChange.callCount).to.equal(3);
});
it('should ignore leading/trailing line breaks', () => {
const tpl = templar(`
<div>{{foo}}</div>
`);
tpl.mount(root);
tpl.set('foo', 'bar');
expect(root.innerHTML).to.equal('<div>bar</div>');
});
it('should support an array of children', () => {
const tpl = templar('<div>{{foo}}</div>');
tpl.mount(root);
const frag = document.createDocumentFragment();
for (let i = 0; i < 3; i++) frag.appendChild(document.createTextNode(i));
tpl.set('foo', [
'foo',
document.createElement('span'),
document.createTextNode('bar'),
frag,
345,
'<em></em>'
]);
expect(root.innerHTML).to.equal('<div>foo<span></span>bar012345<em></em></div>');
});
});