• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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