'use strict'; /* global Template */ require('/shared/js/template.js'); suite('Template', function() { suite('extracted template strings', function() { var domElement; suiteSetup(function() { domElement = document.createElement('div'); domElement.id = 'existing-id'; domElement.appendChild(document.createComment('testing')); document.body.appendChild(domElement); }); suiteTeardown(function() { if (domElement && domElement.parentNode) { document.body.removeChild(domElement); domElement = null; } }); test('extract(node)', function() { var node = document.createElement('div'); var comment = document.createComment('${str}'); node.appendChild(document.createTextNode(' ')); node.appendChild(comment); assert.equal( Template(node).toString(), '${str}' ); node.textContent = ''; assert.equal( Template(node).toString(), '' ); }); test('extract(null)', function() { assert.equal(Template(null), ''); }); test('extract(non-element)', function() { assert.equal(Template(document), ''); assert.equal(Template(window), ''); assert.equal(Template(document.createComment('')), ''); }); test('extract("non-existing-id")', function() { assert.equal(Template('non-existing-id'), ''); }); test('extract("existing-id")', function() { assert.equal(Template('existing-id').toString(), 'testing'); }); }); suite('interpolate', function() { var html = document.createElement('div'); var htmlNoIntrpltn = document.createElement('div'); var css = document.createElement('div'); html.appendChild(document.createComment('${str}')); htmlNoIntrpltn.appendChild(document.createComment('Nothing')); css.appendChild(document.createComment('#foo { height: ${height}px; }')); test('interpolate(data) => html', function() { var tmpl = Template(html); var interpolated = tmpl.interpolate({ str: 'test' }); assert.equal(typeof interpolated, 'string'); assert.equal(interpolated, 'test'); }); test('interpolate(data) => css', function() { var tmpl = Template(css); var interpolated = tmpl.interpolate({ height: '100' }); assert.equal(typeof interpolated, 'string'); assert.equal(interpolated, '#foo { height: 100px; }'); }); test('interpolate() => html', function() { var tmpl = Template(htmlNoIntrpltn); var interpolated = tmpl.interpolate(); assert.equal(typeof interpolated, 'string'); assert.equal(interpolated, 'Nothing'); }); test('interpolate(data, options.safe[bad type]) => throws', function() { var tmpl = Template(html); var pseudoArray = { length: 1 }; assert.throw(() => tmpl.interpolate({}, { safe: pseudoArray }), '"options.safe" must be an Array, not object'); assert.throw(() => tmpl.interpolate({}, { safe: 'badType' }), '"options.safe" must be an Array, not string'); }); test('interpolate(data.undefined) => throws', function() { var tmpl = Template(html); assert.throw(tmpl.interpolate.bind(tmpl), 'No value provided for template identifier "str"'); }); test('interpolate(data.property[not a string]) => throws', function() { var tmpl = Template(html); assert.throw(() => tmpl.interpolate({ str: 666 }), '"data.str" must be a String, not number'); assert.throw(() => tmpl.interpolate({ str: [] }), '"data.str" must be a String, not object'); assert.throw(() => tmpl.interpolate({ str: {} }), '"data.str" must be a String, not object'); }); }); suite('interpolate: escape', function() { var node = document.createElement('div'); node.appendChild(document.createComment('${str}')); test('escape: & => &', function() { var tmpl = Template(node); var interpolated = tmpl.interpolate({ str: '&' }); assert.equal(interpolated, '&'); }); test('escape: < => <', function() { var tmpl = Template(node); var interpolated = tmpl.interpolate({ str: '<' }); assert.equal(interpolated, '<'); }); test('escape: > => >', function() { var tmpl = Template(node); var interpolated = tmpl.interpolate({ str: '>' }); assert.equal(interpolated, '>'); }); }); suite('interpolate: sanitize', function() { test('HTML removal with escaping', function() { var node, interpolated; node = document.createElement('div'); node.appendChild(document.createComment('${str}')); interpolated = Template(node).interpolate({ str: 'George & Lenny' }); assert.equal( interpolated, '<textarea><p>George & Lenny</p>' ); node = document.createElement('div'); node.appendChild(document.createComment('${str}')); interpolated = Template(node).interpolate({ str: 'George & Lenny' }); assert.equal( interpolated, '<textarea><div>George & Lenny</div>' ); }); test('HTML removal (script)', function() { var node = document.createElement('div'); node.appendChild(document.createComment('${str}')); var interpolated = Template(node).interpolate({ str: '' }); assert.equal( interpolated, '<script>alert("hi!")</script>' ); }); test('HTML removal (any)', function() { var node = document.createElement('div'); node.appendChild(document.createComment('${str}')); var interpolated = Template(node).interpolate({ str: 'hi!' }); assert.equal( interpolated, '<textarea><div>hi!</div>' ); }); test('HTML safe list', function() { var node = document.createElement('div'); node.appendChild(document.createComment('${foo}${bar}')); var interpolated = Template(node).interpolate({ foo: '', bar: 'this is ok' }, { safe: ['bar'] }); assert.equal( interpolated, '<script>alert("hi!")</script>this is ok' ); }); }); suite('prepare', function() { var htmlTemplate, cssTemplate; setup(function() { var html = document.createElement('div'); var css = document.createElement('div'); html.appendChild(document.createComment('${str}')); css.appendChild(document.createComment('#foo { height: ${height}px; }')); htmlTemplate = Template(html); cssTemplate = Template(css); }); test('prepare(data).toString => html', function() { var interpolated = htmlTemplate.prepare({ str: 'test' }).toString(); assert.equal(typeof interpolated, 'string'); assert.equal(interpolated, 'test'); }); test('prepare(data).toString => css', function() { var interpolated = cssTemplate.prepare({ height: '100' }).toString(); assert.equal(typeof interpolated, 'string'); assert.equal(interpolated, '#foo { height: 100px; }'); }); test('prepare(data).toDocumentFragment => html', function() { var interpolated = htmlTemplate.prepare({ str: 'test' }).toDocumentFragment(); assert.instanceOf(interpolated, DocumentFragment); assert.equal(interpolated.children.length, 1); assert.equal(interpolated.querySelector('span').textContent, 'test'); }); test('prepare(data).toDocumentFragment => css', function() { var interpolated = cssTemplate.prepare({ height: '100' }).toDocumentFragment(); assert.instanceOf(interpolated, DocumentFragment); assert.equal(interpolated.childNodes.length, 1); assert.equal(interpolated.firstChild.nodeType, Node.TEXT_NODE); assert.equal( interpolated.firstChild.textContent, '#foo { height: 100px; }' ); }); test('prepare.toDocumentFragment returns clone on every call', function() { var interpolated = htmlTemplate.prepare({ str: 'test' }); var documentFragments = new Set(); for (var i = 0; i < 5; i++) { documentFragments.add(interpolated.toDocumentFragment()); } // Verify that all document fragments aren't equal, so Set should have // separate entry for every new fragment assert.equal(documentFragments.size, 5); documentFragments.forEach(function(fragment) { assert.instanceOf(fragment, DocumentFragment); assert.equal(fragment.children.length, 1); assert.equal(fragment.querySelector('span').textContent, 'test'); }); }); }); suite('Template.escape', function() { test('valid', function() { var fixture = '"Hello!"& \' '; assert.equal( Template.escape(fixture), '<div>"Hello!"& ' </div>' ); }); test('invalid', function() { var expect = ''; assert.equal(Template.escape(0), expect); assert.equal(Template.escape(false), expect); assert.equal(Template.escape(true), expect); assert.equal(Template.escape(null), expect); assert.equal(Template.escape({}), expect); assert.equal(Template.escape([]), expect); }); }); });
George & Lenny
${str}
<textarea><div>George & Lenny</div>
this is ok