1import * as assert from 'node:assert'; 2import { parseFragment, parse } from 'parse5'; 3import { jest } from '@jest/globals'; 4import { generateParsingTests } from 'parse5-test-utils/utils/generate-parsing-tests.js'; 5import { treeAdapters } from 'parse5-test-utils/utils/common.js'; 6 7generateParsingTests( 8 'parser', 9 'Parser', 10 { 11 expectErrors: [ 12 //TODO(GH-448): Foreign content behaviour was updated in the HTML spec. 13 //The old test suite still tests the old behaviour. 14 '269.foreign-fragment', 15 '270.foreign-fragment', 16 '307.foreign-fragment', 17 '309.foreign-fragment', 18 '316.foreign-fragment', 19 '317.foreign-fragment', 20 ], 21 }, 22 (test, opts) => ({ 23 node: test.fragmentContext ? parseFragment(test.fragmentContext, test.input, opts) : parse(test.input, opts), 24 }) 25); 26 27generateParsingTests( 28 'parser upstream', 29 'Parser', 30 { 31 withoutErrors: true, 32 suitePath: new URL('../../../../test/data/html5lib-tests/tree-construction', import.meta.url), 33 expectErrors: ['505.search-element', '506.search-element'], 34 }, 35 (test, opts) => ({ 36 node: test.fragmentContext ? parseFragment(test.fragmentContext, test.input, opts) : parse(test.input, opts), 37 }) 38); 39 40describe('parser', () => { 41 it('Regression - HTML5 Legacy Doctype Misparsed with htmlparser2 tree adapter (GH-45)', () => { 42 const html = '<!DOCTYPE html SYSTEM "about:legacy-compat"><html><head></head><body>Hi there!</body></html>'; 43 const document = parse(html, { treeAdapter: treeAdapters.htmlparser2 }); 44 45 assert.ok(treeAdapters.htmlparser2.isDocumentTypeNode(document.childNodes[0])); 46 assert.strictEqual(document.childNodes[0].data, '!DOCTYPE html SYSTEM "about:legacy-compat"'); 47 }); 48 49 describe("Regression - Don't inherit from Object when creating collections (GH-119)", () => { 50 beforeEach(() => { 51 /*eslint-disable no-extend-native*/ 52 // @ts-expect-error Adding unknown prototype method 53 Object.prototype.heyYo = 123; 54 /*eslint-enable no-extend-native*/ 55 }); 56 57 afterEach(() => { 58 // @ts-expect-error Deleting unknown prototype property 59 delete Object.prototype.heyYo; 60 }); 61 62 it('parses correctly', () => { 63 const fragment = parseFragment('<div id="123">', { 64 treeAdapter: treeAdapters.htmlparser2, 65 }); 66 67 assert.ok(treeAdapters.htmlparser2.isElementNode(fragment.childNodes[0])); 68 assert.strictEqual(treeAdapters.htmlparser2.getAttrList(fragment.childNodes[0]).length, 1); 69 }); 70 }); 71 72 it('Regression - DOCTYPE empty fields (GH-236)', () => { 73 const document = parse('<!DOCTYPE>'); 74 const doctype = document.childNodes[0]; 75 76 expect(doctype).toHaveProperty('name', ''); 77 expect(doctype).toHaveProperty('publicId', ''); 78 expect(doctype).toHaveProperty('systemId', ''); 79 }); 80 81 describe('Tree adapters', () => { 82 it('should support onItemPush and onItemPop', () => { 83 const onItemPush = jest.fn(); 84 const onItemPop = jest.fn(); 85 const document = parse('<p><p>', { 86 treeAdapter: { 87 ...treeAdapters.default, 88 onItemPush, 89 onItemPop, 90 }, 91 }); 92 93 const htmlElement = document.childNodes[0]; 94 assert.ok(treeAdapters.default.isElementNode(htmlElement)); 95 const bodyElement = htmlElement.childNodes[1]; 96 assert.ok(treeAdapters.default.isElementNode(bodyElement)); 97 // Expect 5 opened elements; in order: html, head, body, and 2x p 98 expect(onItemPush).toHaveBeenCalledTimes(5); 99 expect(onItemPush).toHaveBeenNthCalledWith(1, htmlElement); 100 expect(onItemPush).toHaveBeenNthCalledWith(3, bodyElement); 101 // The last opened element is the second p 102 expect(onItemPush).toHaveBeenLastCalledWith(bodyElement.childNodes[1]); 103 // The second p isn't closed, plus we never pop body and html. Alas, only 2 pop events (head and p). 104 expect(onItemPop).toHaveBeenCalledTimes(2); 105 // The last pop event should be the first p. 106 expect(onItemPop).toHaveBeenLastCalledWith(bodyElement.childNodes[0], bodyElement); 107 }); 108 }); 109}); 110