1import { ParserStream } from '../lib/index.js'; 2import { generateParsingTests } from 'parse5-test-utils/utils/generate-parsing-tests.js'; 3import { makeChunks, generateTestsForEachTreeAdapter, finished } from 'parse5-test-utils/utils/common.js'; 4import { runInNewContext } from 'node:vm'; 5 6function pause(): Promise<void> { 7 return new Promise((resolve) => setTimeout(resolve, 5)); 8} 9 10const suitePath = new URL('../../../test/data/tree-construction-scripting', import.meta.url); 11 12generateParsingTests( 13 'ParserStream - Scripting', 14 'ParserStream - Scripting', 15 { 16 withoutErrors: true, 17 suitePath, 18 }, 19 async (test, opts) => { 20 const chunks = makeChunks(test.input); 21 const parser = test.fragmentContext 22 ? ParserStream.getFragmentStream(test.fragmentContext, opts) 23 : new ParserStream(opts); 24 25 parser.on('script', async (scriptElement, documentWrite, resume) => { 26 const scriptTextNode = opts.treeAdapter.getChildNodes(scriptElement)[0]; 27 const script = scriptTextNode ? opts.treeAdapter.getTextNodeContent(scriptTextNode) : ''; 28 29 //NOTE: emulate postponed script execution 30 await pause(); 31 32 try { 33 runInNewContext(script, { document: { write: documentWrite } }); 34 resume(); 35 } catch (error) { 36 parser.emit('error', error); 37 } 38 }); 39 40 //NOTE: emulate async input stream behavior 41 for (const chunk of chunks) { 42 parser.write(chunk); 43 await pause(); 44 } 45 46 parser.end(); 47 48 await finished(parser); 49 50 return { 51 node: test.fragmentContext ? parser.getFragment() : parser.document, 52 chunks, 53 }; 54 } 55); 56 57generateTestsForEachTreeAdapter('ParserStream', (treeAdapter) => { 58 test('Regression - Synchronously calling resume() leads to crash (GH-98)', (done) => { 59 const parser = new ParserStream({ treeAdapter }); 60 61 parser.on('script', (_el, _docWrite, resume) => resume()); 62 63 parser.end('<!doctype html><script>abc</script>'); 64 65 process.nextTick(done); 66 }); 67 68 test('Regression - Parsing loop lock causes accidental hang ups (GH-101)', () => { 69 const parser = new ParserStream({ treeAdapter }); 70 71 parser.on('script', (_scriptElement, _documentWrite, resume) => process.nextTick(resume)); 72 73 parser.write('<script>yo</script>'); 74 parser.end('dawg'); 75 76 return finished(parser); 77 }); 78}); 79