/* global console */ var test = require('tape'); var HTML = require('../index'); test('parse', function (t) { var html = '

'; var parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: { class: 'oh' }, voidElement: false, children: [ { type: 'tag', name: 'p', attrs: {}, children: [], voidElement: false } ] }]); t.equal(html, HTML.stringify(parsed)); html = '

hi

'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: { class: 'oh' }, voidElement: false, children: [ { type: 'tag', name: 'p', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'hi' } ] } ] }]); t.equal(html, HTML.stringify(parsed)); html = '
oh hello there! How are you?
'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'oh ' }, { type: 'tag', name: 'strong', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'hello' } ] }, { type: 'text', content: ' there! How are ' }, { type: 'tag', name: 'span', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'you' } ] }, { type: 'text', content: '?' } ] }]); t.equal(html, HTML.stringify(parsed)); html = '
'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: { class: 'handles multiple classes', and: 'attributes' }, voidElement: false, children: [] }]); t.equal(html, HTML.stringify(parsed)); html = '
'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: { class: 'handles', other: '47', and: 'attributes' }, voidElement: false, children: [] }]); t.equal(HTML.stringify(parsed), '
'); html = '

should be ignored

'; parsed = HTML.parse(html, { components: { 'my-component': 'something' } }); t.deepEqual(parsed, [{ type: 'tag', name: 'div-custom', attrs: { class: 'oh' }, voidElement: false, children: [ { type: 'component', name: 'my-component', attrs: { some: 'thing' }, voidElement: false, children: [] } ] }], 'should not include children of registered components in AST'); html = '
okok
'; parsed = HTML.parse(html, { components: { 'my-component': 'something' } }); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'component', name: 'my-component', attrs: { thing: 'one' }, voidElement: false, children: [] }, { type: 'component', name: 'my-component', attrs: { thing: 'two' }, voidElement: false, children: [] } ] }]); html = '
'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'tag', name: 'img', attrs: {}, voidElement: true, children: [] } ] }], 'should handle unclosed void elements'); t.equal(HTML.stringify(parsed), '
'); html = '
'; parsed = HTML.parse(html); t.deepEqual(parsed, [ { type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [] }, { type: 'tag', name: 'img', attrs: {}, voidElement: true, children: [] } ], 'should handle multiple root nodes'); t.equal(HTML.stringify(parsed), '
'); html = '
'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'tag', name: 'void-web-component', attrs: {}, voidElement: true, children: [] } ] }], 'should handle custom void tags if self-closing'); html = '
'; parsed = HTML.parse(html, {components: {'void-registered-component': true}}); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'component', name: 'void-registered-component', attrs: {}, voidElement: true, children: [] } ] }], 'should handle registered void tags if self-closing'); html = '
9 10
'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'text', content: ' 9 ' }, { type: 'tag', name: 'input', attrs: { type: 'text' }, children: [], voidElement: true, }, { type: 'text', content: ' 10 ' }, ] }], 'should not give voidElements children'); html = '
\n'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [] }], 'should not explode on trailing whitespace'); html = '
Hi
There '; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'Hi' } ] },{ type: 'text', content: ' There ' }], 'should handle trailing text nodes at the top-level'); html = '
Hi
There something else '; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'Hi' } ] },{ type: 'text', content: ' There ' },{ type: 'tag', name: 'span', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'something' } ] },{ type: 'text', content: ' ' }, { type: 'tag', name: 'a', attrs: {}, voidElement: false, children: [] },{ type: 'text', content: 'else ' }], 'should handle text nodes in the middle of tags at the top-level'); html = '\n
Hi!
\n'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'text', content: ' '}, { type: 'tag', name: 'span', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'Hi!' } ] }, { type: 'text', content: ' '} ] }], 'should trim whitespace from the beginning and end of the parsed nodes'); html = '
Hi
\n\n There \t
\n\t
'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'Hi' } ] },{ type: 'text', content: ' ' }, { type: 'tag', name: 'span', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'There' } ] },{ type: 'text', content: ' ' },{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'text', content: ' ' } ] }], 'should collapse whitespace'); // See https://www.w3.org/TR/html4/struct/text.html#h-9.1 html = '
Hi
\n\n There \t '; parsed = HTML.parse(html, { ignoreWhitespace: true }); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'Hi' } ] },{ type: 'tag', name: 'span', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'There' } ] },{ type: 'tag', name: 'iframe', attrs: {}, voidElement: false, children: [] }], 'should remove text nodes that are nothing but whitespace if the ignoreWhitespace option is passed'); html = '\n
Hi
'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'Hi'} ] }], 'should ignore HTML comments'); html = '
Hi there!
'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'tag', name: 'div', attrs: {}, voidElement: false, children: [ { type: 'text', content: 'Hi '}, { type: 'text', content: 'there'}, { type: 'tag', name: 'strong', attrs: {}, voidElement: false, children: [{ type: 'text', content: '!'}] } ] },{ type: 'tag', name: 'span', attrs: {}, voidElement: false, children: [] }], 'should ignore nested HTML comments'); html = 'Hello, world!'; parsed = HTML.parse(html); t.deepEqual(parsed, [{ type: 'text', content: 'Hello, world!' }], 'should handle just text'); t.end(); }); test('simple speed sanity check', function (t) { var i = 100000; var groupSize = 1000; var waitLoopSize = 10000000; var groups = i / groupSize; var html = 'Some page

Hey, we need content


'; var parse = HTML.parse; var times = []; var count; var waitCount; var total = 0; var start, stepAverage; console.log('running ' + i + ' iterations...'); while(i--) { count = groupSize; // grab groups if (i % count === 0) { start = Date.now(); while(count--) { parse(html); } var diff = Date.now() - start; stepAverage = diff/groupSize; console.log('group ' + (groups - (i / groupSize)) + ': ' + stepAverage); times.push(stepAverage); total += stepAverage; waitCount = waitLoopSize; // forcing a bit of a pause between tests while(waitCount--) {} } } // trim off first // it's always a slower outlier // with higher variability that // makes it harder to find differences times.shift(); var max = Math.max.apply(null, times); var min = Math.min.apply(null, times); var average = total / times.length; console.log('max', max); console.log('min', min); console.log('avg', average); t.end(); });