als-document 1.1.2 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/browser-tests/data/html1.js +2579 -0
  2. package/browser-tests/data/html2.js +1124 -0
  3. package/browser-tests/data/svg.js +66 -0
  4. package/{tests → browser-tests}/index.html +1 -1
  5. package/browser-tests/utils.js +37 -0
  6. package/build-readme.js +8 -0
  7. package/{src/build.js → build.js} +4 -4
  8. package/docs/#.md +52 -0
  9. package/docs/1.parseHTML.md +39 -0
  10. package/docs/2.node.md +25 -0
  11. package/docs/3.singleNode.md +3 -0
  12. package/docs/4.tTextNode.md +3 -0
  13. package/docs/5. Document.md +28 -0
  14. package/docs/6.Query.md +110 -0
  15. package/docs/7.cache.md +14 -0
  16. package/document.js +6 -4
  17. package/index.js +6 -4
  18. package/index.mjs +6 -4
  19. package/{src/node/root.js → lib/node/document.js} +3 -2
  20. package/{src → lib}/node/node.js +6 -3
  21. package/lib/node/root.js +6 -0
  22. package/{src → lib}/node/single-node.js +22 -4
  23. package/package.json +6 -4
  24. package/readme.md +21 -14
  25. package/tests/cache.test.js +23 -0
  26. package/tests/node.test.js +411 -0
  27. package/tests/parser.test.js +353 -0
  28. package/tests/query.test.js +65 -0
  29. package/tests/single-node.test.js +88 -0
  30. package/tests/utils.js +2 -0
  31. /package/{tests → browser-tests}/cache.js +0 -0
  32. /package/{tests → browser-tests}/node.js +0 -0
  33. /package/{tests → browser-tests}/parse-real.js +0 -0
  34. /package/{tests → browser-tests}/parser.js +0 -0
  35. /package/{tests → browser-tests}/query.js +0 -0
  36. /package/{tests/test.js → browser-tests/simple-test.js} +0 -0
  37. /package/{src → lib}/node/class-list.js +0 -0
  38. /package/{src → lib}/node/dataset.js +0 -0
  39. /package/{src → lib}/node/find.js +0 -0
  40. /package/{src → lib}/node/style.js +0 -0
  41. /package/{src → lib}/node/text-node.js +0 -0
  42. /package/{src → lib}/parse/cache.js +0 -0
  43. /package/{src → lib}/parse/parse-atts.js +0 -0
  44. /package/{src → lib}/parse/parser.js +0 -0
  45. /package/{src → lib}/parse/void-tags.js +0 -0
  46. /package/{src → lib}/query/check-element.js +0 -0
  47. /package/{src → lib}/query/query.js +0 -0
@@ -0,0 +1,353 @@
1
+ const { describe, it, beforeEach } = require('node:test')
2
+ const assert = require('node:assert')
3
+ const { Node, parseHTML, Root } = require('../index')
4
+ const generator = require('./utils')
5
+
6
+ describe('HTML Parser', () => {
7
+ let parsedHTML;
8
+
9
+ beforeEach(() => {
10
+ parsedHTML = parseHTML('<div><p>Text</p></div>').children[0];
11
+ });
12
+
13
+ describe('parseHTML', () => {
14
+ it('returns an instance of Node', () => {
15
+ assert(parsedHTML instanceof Node );
16
+ });
17
+
18
+ it('correctly sets node type', () => {
19
+ assert(parsedHTML.tagName === 'div');
20
+ });
21
+
22
+ it.skip('correctly sets child nodes', () => {
23
+ assert(parsedHTML.children.leng === 1);
24
+ assert(parsedHTML.children[0].tagName === 'p');
25
+ });
26
+
27
+ it('correctly parses nested HTML', () => {
28
+ const nestedHTML = parseHTML('<div><span><a href="#">Link</a></span></div>');
29
+ assert(nestedHTML.children[0].children[0].children[0].tagName === 'a');
30
+ });
31
+
32
+ it('correctly parses text nodes', () => {
33
+ assert(parsedHTML.children[0].innerHTML === 'Text');
34
+ });
35
+ });
36
+
37
+ });
38
+
39
+ describe('Advanced tests', () => {
40
+ it('handles empty HTML correctly', () => {
41
+ const result = parseHTML('');
42
+ assert(result.children.length === 0);
43
+ });
44
+
45
+ it('handles deeply nested HTML', () => {
46
+ let deepHTML = '<div>';
47
+ for (let i = 0; i < 1000; i++) {
48
+ deepHTML += '<div>';
49
+ deepHTML += generator.generate();
50
+ }
51
+ for (let i = 0; i < 1000; i++) {
52
+ deepHTML += '</div>';
53
+ }
54
+ const now = Date.now()
55
+ // const memoryBefore = performance.memory.totalJSHeapSize
56
+ const result = parseHTML(deepHTML);
57
+ // const memoryAfter = performance.memory.totalJSHeapSize
58
+ let time = Date.now() - now
59
+ // console.log(memoryAfter - memoryBefore)
60
+ assert(time < 20, `Big html (${(deepHTML.length / 1024).toFixed(2)}KB) in less then 20ms (${time}ms)`)
61
+ assert(result instanceof Root); // or any other validation you see fit
62
+ });
63
+
64
+ it('handles incorrectly closed tags', () => {
65
+ const result = parseHTML('<div><p>Text</div>');
66
+ // Depending on the behavior you expect: either an error, or a specific structure.
67
+ // For this example, I'll assume you expect the <p> tag to be auto-closed
68
+ assert(result.children[0].children[0].tagName === 'p');
69
+ });
70
+
71
+ it('handles attributes without values', () => {
72
+ const result = parseHTML('<input disabled>');
73
+ assert(result.children[0].attributes.disabled !== undefined);
74
+ });
75
+
76
+ it('ignores comments', () => {
77
+ const result = parseHTML('<!-- this is a comment --><div></div>');
78
+ assert(result.children.length === 1);
79
+ assert(result.children[0].tagName === 'div');
80
+ });
81
+
82
+ it('correctly parses script content', () => {
83
+ const result = parseHTML('<script>let x = 5;<\/script>');
84
+ assert(result.children[0].innerHTML === 'let x = 5;');
85
+ });
86
+
87
+ it('parses special entities correctly', () => {
88
+ const result = parseHTML('<p>&lt; &amp; &gt;</p>');
89
+ assert(result.children[0].innerHTML === '&lt; &amp; &gt;');
90
+ });
91
+
92
+ it.skip('should correctly retrieve data-* attributes', () => {
93
+ const element = document.createElement('div');
94
+ element.setAttribute('data-test', 'testValue');
95
+
96
+ const value = element.dataset.test;
97
+ assert(value === 'testValue');
98
+ });
99
+
100
+ it('dataset2', () => {
101
+ const node = new Node('div', { 'data-example': 'test' });
102
+ assert(node.dataset.example === 'test')
103
+ node.dataset.example = 'new value';
104
+ assert(node.dataset.example === 'new value');
105
+ delete node.dataset.example;
106
+ assert(node.dataset.example === undefined);
107
+ })
108
+
109
+ })
110
+
111
+ describe('More adnvanced tests', () => {
112
+
113
+ it('Attributes parsing', () => {
114
+ const customHTML = '<div class="some class" data-value="A &quot;value&quot;" custom-attr=\'test\'></div>';
115
+ const parsedDiv = parseHTML(customHTML).querySelector('div');
116
+ assert(parsedDiv.getAttribute('class') === 'some class', 'Class attribute parsed correctly');
117
+ assert(parsedDiv.getAttribute('custom-attr') === 'test', 'Attribute with single quotes parsed');
118
+ });
119
+
120
+ it('Nested hierarchy check', () => {
121
+ const customHTML = '<div><span><a href="#">Link</a></span></div>';
122
+ const parsedDiv = parseHTML(customHTML).querySelector('div');
123
+ const parsedSpan = parsedDiv.querySelector('span');
124
+ const parsedA = parsedSpan.querySelector('a');
125
+
126
+ assert(parsedA.getAttribute('href') === '#', 'Anchor tag nested correctly');
127
+ });
128
+
129
+ it('Self-closing tags check', () => {
130
+ const customHTML = '<input type="text"/><br/><hr/>';
131
+ const parsedHTML = parseHTML(customHTML);
132
+ assert(parsedHTML.querySelectorAll('input').length === 1, 'Input tag parsed correctly');
133
+ assert(parsedHTML.querySelectorAll('br').length === 1, 'BR tag parsed correctly');
134
+ assert(parsedHTML.querySelectorAll('hr').length === 1, 'HR tag parsed correctly');
135
+ });
136
+
137
+ it('Edge cases', () => {
138
+ // Несколько открывающих тегов подряд
139
+ const erroneousHTML1 = '<div><div><div></div></div>';
140
+ const parsedHTML1 = parseHTML(erroneousHTML1);
141
+ assert(parsedHTML1.querySelectorAll('div').length === 3, 'Multiple opening tags handled');
142
+
143
+ // Несколько закрывающих тегов подряд
144
+ const erroneousHTML2 = '<div></div></div></div>';
145
+ const parsedHTML2 = parseHTML(erroneousHTML2);
146
+ assert(parsedHTML2.querySelectorAll('div').length === 1, 'Multiple closing tags handled');
147
+ });
148
+
149
+ })
150
+
151
+ describe('CDATA', () => {
152
+ it('basic test', () => {
153
+ const test1 = '<![CDATA[This is CDATA content]]>';
154
+ const root1 = parseHTML(test1);
155
+ assert(root1.childNodes[0].tagName === "#cdata-section", "Test 1: CDATA node not created");
156
+ assert(root1.childNodes[0].nodeValue === "This is CDATA content", "Test 1: CDATA content not correct");
157
+ })
158
+
159
+ it('nested CDATA', () => {
160
+ const test2 = '<div><![CDATA[Inside a div]]><p>Paragraph</p></div>';
161
+ const root2 = parseHTML(test2);
162
+ assert(root2.childNodes[0].tagName === "div", "Test 2: Parent div not created");
163
+ assert(root2.childNodes[0].childNodes[0].tagName === "#cdata-section", "Test 2: CDATA node not created inside div");
164
+ assert(root2.childNodes[0].childNodes[0].nodeValue === "Inside a div", "Test 2: CDATA content not correct inside div");
165
+ assert(root2.childNodes[0].childNodes[1].tagName === "p", "Test 2: Paragraph not created after CDATA");
166
+ })
167
+
168
+ it('multiple lines', () => {
169
+ const test3 = `
170
+ <![CDATA[
171
+ Multiple lines
172
+ inside this CDATA
173
+ block.
174
+ ]]>`;
175
+ const root3 = parseHTML(test3);
176
+ assert(root3.childNodes[0].tagName === "#cdata-section", "Test 3: CDATA node not created");
177
+ assert(root3.childNodes[0].nodeValue.trim() === "Multiple lines \ninside this CDATA\nblock.", "Test 3: Multi-line CDATA content not correct");
178
+
179
+ })
180
+
181
+ it('inside html', () => {
182
+ const test4 = '<![CDATA[<span>This should be text</span>]]>';
183
+ const root4 = parseHTML(test4);
184
+ assert(root4.childNodes[0].tagName === "#cdata-section", "Test 4: CDATA node not created");
185
+ assert(root4.childNodes[0].nodeValue === "<span>This should be text</span>", "Test 4: HTML inside CDATA not treated as text");
186
+
187
+ })
188
+ })
189
+
190
+ describe('signle tags, script and style', () => {
191
+ it('script and style', () => {
192
+ const testStyleScript = `
193
+ <style>
194
+ body { color: red; }
195
+ p > a { text-decoration: none; }
196
+ </style>
197
+ <script>
198
+ if (x < 5 && y > 3) {
199
+ console.log("This shouldn't be parsed as tags");
200
+ }
201
+ </script>
202
+ `;
203
+ const rootStyleScript = parseHTML(testStyleScript);
204
+ assert(rootStyleScript.childNodes[0].tagName === "style", "Test Style/Script 1: Style tag not created");
205
+ assert(rootStyleScript.childNodes[0].textContent.trim() === "body { color: red; }\n p > a { text-decoration: none; }", "Test Style/Script 1: Style content not correct");
206
+ assert(rootStyleScript.childNodes[1].tagName === "script", "Test Style/Script 2: Script tag not created");
207
+ assert(rootStyleScript.childNodes[1].textContent.trim() === 'if (x < 5 && y > 3) {\n console.log("This shouldn\'t be parsed as tags");\n }', "Test Style/Script 2: Script content not correct");
208
+ })
209
+
210
+ it('meta and link tags', () => {
211
+ const testMetaLink = `
212
+ <meta charset="UTF-8">
213
+ <link rel="stylesheet" href="styles.css">
214
+ `;
215
+ const rootMetaLink = parseHTML(testMetaLink);
216
+ assert(rootMetaLink.children[0].tagName === "meta", "Test Meta/Link 1: Meta tag not created");
217
+ assert(rootMetaLink.children[0].getAttribute("charset") === "UTF-8", "Test Meta/Link 1: Meta content not correct");
218
+ assert(rootMetaLink.children[1].tagName === "link", "Test Meta/Link 2: Link tag not created");
219
+ assert(rootMetaLink.children[1].getAttribute("rel") === "stylesheet", "Test Meta/Link 2: Link rel attribute not correct");
220
+ assert(rootMetaLink.children[1].getAttribute("href") === "styles.css", "Test Meta/Link 2: Link href attribute not correct");
221
+ })
222
+
223
+ it('broken html structure', () => {
224
+ const testUnmatchedClose = `<div>Some content</p></div>`;
225
+ const rootUnmatchedClose = parseHTML(testUnmatchedClose);
226
+ // Зависит от вашего решения обработки. Если вы решите исправлять такой HTML, тест может выглядеть так:
227
+ assert(rootUnmatchedClose.childNodes[0].tagName === "div", "Test Unmatched Close: Div tag not created");
228
+ assert(rootUnmatchedClose.childNodes[0].textContent.trim() === "Some content", "Test Unmatched Close: Div content not correct");
229
+ })
230
+
231
+ it('wrong open tags', () => {
232
+ const testUnmatchedOpen = `<div>Some content`;
233
+ const rootUnmatchedOpen = parseHTML(testUnmatchedOpen);
234
+ // Снова зависит от вашего решения. Если вы решите автоматически закрывать тег:
235
+ assert(rootUnmatchedOpen.childNodes[0].tagName === "div", "Test Unmatched Open: Div tag not created");
236
+ assert(rootUnmatchedOpen.childNodes[0].textContent.trim() === "Some content", "Test Unmatched Open: Div content not correct");
237
+ })
238
+ })
239
+
240
+ describe('js as content', () => {
241
+ const jsCode = 'console.log(`<div>hello</div>`)'
242
+ it('html inside onclick', () => {
243
+ const html = parseHTML(`<button onclick="${jsCode}">test</button>'`)
244
+ assert(html.childNodes[0].getAttribute('onclick') === jsCode)
245
+ })
246
+ it('html in script', () => {
247
+ const html = parseHTML(`<script>${jsCode}</script>`)
248
+ assert(html.childNodes[0].innerHTML === jsCode)
249
+ })
250
+ })
251
+
252
+ describe('Specific elements handling', () => {
253
+
254
+ it.skip('should correctly handle SVG elements', async () => {
255
+ document.body.insertAdjacentHTML('beforeend',/*html*/`<div id="svg">${svg}</div>`)
256
+ const svgElement = document.querySelector('#svg>svg')
257
+ const html = parseHTML(svg)
258
+ const svgParsed = html.querySelector('svg')
259
+
260
+ assert(svgParsed.tagName === svgElement.tagName)
261
+
262
+ assert(svgElement.getAttribute('version') === svgParsed.getAttribute('version'))
263
+ assert(svgElement.getAttribute('id') === svgParsed.getAttribute('id'))
264
+ assert(svgElement.getAttribute('width') === svgParsed.getAttribute('width'))
265
+ assert(svgElement.getAttribute('height') === svgParsed.getAttribute('height'))
266
+
267
+ assert(svgElement.querySelector('defs') !== null); // Проверка наличия элемента <defs>
268
+ assert(svgParsed.querySelector('defs') !== null)
269
+
270
+ const layer1Group = svgElement.querySelector('g[id="layer1"]');
271
+ const layer1GroupParsed = svgParsed.querySelector('g[id="layer1"]');
272
+
273
+ assert(layer1Group !== null); // Проверка наличия группы с id="layer1"
274
+ assert(layer1GroupParsed !== null); // Проверка наличия группы с id="layer1"
275
+
276
+ const paths = layer1Group.querySelectorAll('path');
277
+ const pathsParsed = layer1GroupParsed.querySelectorAll('path');
278
+ assert(paths.length >= 1); // Проверка, что есть хотя бы один элемент <path>
279
+ assert(pathsParsed.length >= 1); // Проверка, что есть хотя бы один элемент <path>
280
+ });
281
+
282
+ it('should correctly handle canvas', () => {
283
+ const canvas = /*html*/`<canvas id="myCanvas" width="300" height="150" style="border:1px solid grey"></canvas>`
284
+ const html = parseHTML(canvas)
285
+ const canvasElement = html.children[0]
286
+
287
+ assert(canvasElement.tagName === 'canvas');
288
+ assert(canvasElement.getAttribute('id') === 'myCanvas');
289
+ assert(canvasElement.getAttribute('width') === '300');
290
+ assert(canvasElement.getAttribute('height') === '150');
291
+ assert(canvasElement.style.border === '1px solid grey');
292
+ });
293
+
294
+ it('should handle namespaces correctly', () => {
295
+ const svgNamespace = 'http://www.w3.org/2000/svg';
296
+ const xmlNamespace = 'http://www.w3.org/XML/1998/namespace';
297
+
298
+ const svgHTML = /*html*/`<svg xmlns="${svgNamespace}" xmlns:xml="${xmlNamespace}"><circle cx="50" cy="50" r="10" stroke="black" stroke-width="2" fill="red" /></svg>`;
299
+ const html = parseHTML(svgHTML);
300
+ const svgElement = html.children[0]
301
+
302
+ assert(svgElement.tagName === 'svg');
303
+ assert(svgElement.getAttribute('xmlns') === svgNamespace);
304
+ assert(svgElement.getAttribute('xmlns:xml') === xmlNamespace);
305
+ });
306
+
307
+ it('should handle large amounts of data efficiently', () => {
308
+ const largeAmountOfDivs = /*html*/`<div>${new Array(1000).fill('<div class="test-div"></div>').join('')}</div>`;
309
+ let start = performance.now();
310
+ const rootElement = parseHTML(largeAmountOfDivs);
311
+ let end = performance.now();
312
+ time = end - start
313
+ assert(time < 200,`${time} ms`)
314
+
315
+ // 1. Проверка, что все элементы были добавлены
316
+ assert(rootElement.querySelectorAll('.test-div').length === 1000);
317
+
318
+ start = performance.now();
319
+ const randomDiv = rootElement.querySelector('.test-div');
320
+ randomDiv.setAttribute('id', 'randomDiv');
321
+ assert(randomDiv.getAttribute('id') === 'randomDiv');
322
+
323
+ end = performance.now();
324
+
325
+ time = end - start
326
+ assert(time < 200,`${time} ms`)
327
+ });
328
+
329
+ it('image data:', () => {
330
+ const src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='
331
+ const img = /*html*/`<img src="${src}" alt="Red dot" />`
332
+ const rootElement = parseHTML(img);
333
+ assert(rootElement.children[0].getAttribute('src') === src)
334
+ })
335
+
336
+ });
337
+
338
+ describe.skip('Query API', () => {
339
+ beforeEach(() => {
340
+ parsedHTML = parseHTML('<div><p>Text</p></div>').children[0];
341
+ });
342
+
343
+ it('can select a node by type', () => {
344
+ const collection = parsedHTML.querySelectorAll('p')
345
+ expect(collection[0].innerHTML).equalTo('Text');
346
+ });
347
+
348
+ it('can select nested nodes', () => {
349
+ const nestedHTML = parseHTML('<div><span><a href="#">Link</a></span></div>');
350
+ const collection = nestedHTML.querySelectorAll('a');
351
+ expect(collection[0].tagName).equalTo('a');
352
+ });
353
+ });
@@ -0,0 +1,65 @@
1
+ const { describe, it } = require('node:test')
2
+ const assert = require('node:assert')
3
+ const { Query } = require('../index')
4
+
5
+
6
+ const q1 = 'html>body>div.tabs~.some[type $= "some"][test]>p+div>.some-id .tab-content~input[disabled] div.some'
7
+ const s1 = Query.get(q1)[0]
8
+
9
+ describe('query tests',() => {
10
+ it('Check target',() => {
11
+ const expected = 'div.some'
12
+ let {tag,classList} = s1
13
+ assert(`${tag}.${classList[0]}` === expected)
14
+ })
15
+ it('Check ancestors length',() => {
16
+ assert(s1.ancestors.length === 2)
17
+ })
18
+ it('Check prev group',() => {
19
+ const expected = s1.ancestors[0].group.split('+')[0]
20
+ assert(s1.ancestors[0].prev.group === expected)
21
+ })
22
+ it('Check parents length',() => {
23
+ assert(s1.ancestors[0].parents.length === 1)
24
+ })
25
+ it('Check prev any, prev and classList',() => {
26
+ assert(s1.ancestors[0].prev.prevAny.classList[0] === 'tabs')
27
+ })
28
+ it('Check attributes length',() => {
29
+ assert(s1.ancestors[0].prev.parents[0].attribs.length === 2)
30
+ })
31
+ it('Check attributes fn $',() => {
32
+ assert(s1.ancestors[0].prev.parents[0].attribs[0].check('test and some') === true)
33
+ })
34
+ it('Check attributes fn *=',() => {
35
+ assert(s1.ancestors[0].prev.parents[0].attribs[0].check('some') === true)
36
+ })
37
+ it('Check attributes fn *=',() => {
38
+ let s = Query.get('[test*="some value"]')[0]
39
+ assert(s.attribs[0].check('some value test') === true)
40
+ })
41
+ it('Check attributes fn ~= prase instead single word',() => {
42
+ let s = Query.get('[test~="some value"]')[0]
43
+ assert(s.attribs[0].check('some value test') === false)
44
+ })
45
+ it('Check attributes fn ~=',() => {
46
+ let s = Query.get('[test~="value"]')[0]
47
+ assert(s.attribs[0].check('some value test') === true)
48
+ })
49
+ it('Check attributes fn ^=',() => {
50
+ let s = Query.get('[test^="some"]')[0]
51
+ assert(s.attribs[0].check('some value test') === true)
52
+ })
53
+ it('Check attributes fn |= with few words',() => {
54
+ let s = Query.get('[test|="some value test"]')[0]
55
+ assert(s.attribs[0].check('some') === false)
56
+ })
57
+ it('Check attributes fn |=word',() => {
58
+ let s = Query.get('[test|="some"]')[0]
59
+ assert(s.attribs[0].check('some') === true)
60
+ })
61
+ it('Check attributes fn |=word-word',() => {
62
+ let s = Query.get('[test|="some"]')[0]
63
+ assert(s.attribs[0].check('some-value') === true)
64
+ })
65
+ })
@@ -0,0 +1,88 @@
1
+ const { describe, it, beforeEach } = require('node:test');
2
+ const assert = require('node:assert');
3
+ const { SingleNode, Node } = require('../index');
4
+
5
+ describe('SingleNode Class Tests', () => {
6
+ let singleNode;
7
+
8
+ beforeEach(() => {
9
+ singleNode = new SingleNode('meta', { name: "viewport", content: "width=device-width" });
10
+ });
11
+
12
+
13
+ it('querySelectorAll',() => {
14
+ assert.deepStrictEqual(singleNode.querySelectorAll('div'),[])
15
+
16
+ })
17
+ it('querySelector',() => {
18
+ assert.deepStrictEqual(singleNode.querySelector('div'),null)
19
+
20
+ })
21
+
22
+ it('Should correctly set attributes and generate outerHTML', () => {
23
+ assert.strictEqual(singleNode.outerHTML, '<meta name="viewport" content="width=device-width">', 'outerHTML does not match expected HTML');
24
+ });
25
+
26
+ it('Should return empty innerHTML', () => {
27
+ assert.strictEqual(singleNode.innerHTML, '', 'innerHTML should be empty for SingleNode');
28
+ });
29
+
30
+ it('Should ignore any set operations on innerHTML', () => {
31
+ assert.doesNotThrow(() => { singleNode.innerHTML = '<div></div>'; }, 'Setting innerHTML should not throw');
32
+ assert.strictEqual(singleNode.innerHTML, '', 'innerHTML should still be empty after set operation');
33
+ });
34
+
35
+ it('Should return null for query selectors', () => {
36
+ assert.strictEqual(singleNode.$('div'), null, '$ should always return null');
37
+ assert.deepStrictEqual(singleNode.$$('div'), [], '$$ should always return an empty array');
38
+ });
39
+
40
+ it('Should return empty array for getElementsByClassName', () => {
41
+ assert.deepStrictEqual(singleNode.getElementsByClassName('test'), [], 'getElementsByClassName should always return an empty array');
42
+ });
43
+
44
+ it('Should return empty array for getElementsByTagName', () => {
45
+ assert.deepStrictEqual(singleNode.getElementsByTagName('div'), [], 'getElementsByTagName should always return an empty array');
46
+ });
47
+
48
+ it('Should return null for getElementById', () => {
49
+ assert.strictEqual(singleNode.getElementById('id'), null, 'getElementById should always return null');
50
+ });
51
+
52
+ it('Should always return an empty array for children', () => {
53
+ assert.deepStrictEqual(singleNode.children, [], 'children should always return an empty array');
54
+ });
55
+
56
+ it('Should correctly redirect insert operations for SingleNode', () => {
57
+ const rootNode = new Node('div');
58
+ rootNode.appendChild(singleNode);
59
+ const commentNode = new Node('#comment', {}, rootNode);
60
+
61
+ singleNode.insertAdjacentElement('afterbegin', commentNode);
62
+ assert.strictEqual(rootNode.childNodes.includes(commentNode), true, 'commentNode should be redirected and inserted before singleNode');
63
+ singleNode.insertAdjacentElement('beforeend', commentNode);
64
+ assert.strictEqual(rootNode.childNodes.includes(commentNode), true, 'commentNode should be redirected and inserted after singleNode');
65
+ });
66
+
67
+ it('Should not allow appendChild operation', () => {
68
+ assert.doesNotThrow(() => { singleNode.appendChild(new Node('span')); }, 'appendChild should not throw');
69
+ assert.deepEqual(singleNode.childNodes, [], 'appendChild should have no effect');
70
+ });
71
+
72
+ it('Should always return empty string for textContent', () => {
73
+ assert.strictEqual(singleNode.textContent, '', 'textContent should always return an empty string');
74
+ });
75
+
76
+ it('Should ignore any set operations on textContent', () => {
77
+ assert.doesNotThrow(() => { singleNode.textContent = 'New content'; }, 'Setting textContent should not throw');
78
+ assert.strictEqual(singleNode.textContent, '', 'textContent should still be empty after set operation');
79
+ });
80
+
81
+ it('Should handle insertAdjacentHTML and insertAdjacentText with correct redirection', () => {
82
+ const rootNode = new Node('div');
83
+ rootNode.appendChild(singleNode);
84
+ singleNode.insertAdjacentHTML('afterbegin', '<p>Hello</p>');
85
+ singleNode.insertAdjacentText('beforeend', 'World');
86
+ assert.strictEqual(rootNode.childNodes.length, 3, 'rootNode should contain three child nodes due to redirection');
87
+ });
88
+ });
package/tests/utils.js CHANGED
@@ -35,3 +35,5 @@ class RandomSentenceGenerator {
35
35
  }
36
36
 
37
37
  const generator = new RandomSentenceGenerator()
38
+
39
+ module.exports = generator
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes