als-document 1.2.0 → 1.3.0

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.
@@ -1,12 +1,44 @@
1
1
  class Document extends Node {
2
- constructor() {
3
- super('DOCUMENT',{},null);
2
+ constructor(html,url) {
3
+ super('ROOT',{},null);
4
4
  this.isSingle = false
5
- this.innerHTML = /*html*/`<!DOCTYPE html><html lang="en"><head><title></title></head><body></body></html>`
5
+ this.URL = url
6
+ if(html instanceof Document) {
7
+ this.childNodes = [...buildFromCache(cacheDoc(html)).childNodes]
8
+ // this.innerHTML = html.innerHTML
9
+ }
10
+ else if(typeof html === 'string') this.innerHTML = html
11
+ else this.body // create innerHTML
6
12
  }
7
13
 
8
- get body() {return this.$('body')}
9
- get head() {return this.$('head')}
10
- get title() {return this.$('title')}
11
- set title(title) {return this.$('title').innerHTML = title}
14
+ get documentElement() {return this.html}
15
+ get html() {
16
+ const html = this.$('html')
17
+ if(html === null) this.innerHTML = /*html*/`<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title></head><body></body></html>`
18
+ return this.$('html')
19
+ }
20
+
21
+ get head() {
22
+ const head = this.$('head')
23
+ if(head === null) this.html.insert(1,'<head></head>')
24
+ return this.$('head')
25
+ }
26
+
27
+ get body() {
28
+ const body = this.$('body')
29
+ if(body === null) this.head.insert(3,'<body></body>')
30
+ return this.$('body')
31
+ }
32
+
33
+ get title() {
34
+ const title = this.$('title')
35
+ if(title === null) this.head.insert(1,'<title></title>')
36
+ return this.$('title').innerText
37
+ }
38
+
39
+ get charset() {return this.$('meta[charset]')}
40
+
41
+ set title(title) {return this.$('title').innerText = title}
42
+
43
+ get clone() {return new Document(this)}
12
44
  }
package/lib/node/find.js CHANGED
@@ -1,4 +1,5 @@
1
1
  function find(selectors,element,collection,first=false,firstTime = true) {
2
+ if(!firstTime)
2
3
  for(let selector of selectors) {
3
4
  if(checkElement(element,selector)) collection.add(element)
4
5
  }
package/lib/node/node.js CHANGED
@@ -7,7 +7,8 @@ function insertBefore(arr, index, newItem) {
7
7
  class Node {
8
8
  constructor(tagName, attributes = {}, parent = null) {
9
9
  this.isSingle = false;
10
- this.tagName = tagName;
10
+ this._tagName = tagName.toLowerCase();
11
+ this.tagName = tagName.toUpperCase();
11
12
  this.attributes = attributes;
12
13
  this.childNodes = [];
13
14
  if (parent !== null) parent.childNodes.push(this)
@@ -43,13 +44,13 @@ class Node {
43
44
  }
44
45
  get previousElementSibling() { return this.prev }
45
46
  get prev() {
46
- if (!this.childIndex) return null // if no index or index == 0
47
+ if (this.childIndex === null) return null // if no index or index == 0
47
48
  return this.parent.children[this.childIndex - 1]
48
49
  }
49
50
 
50
51
  get nextElementSibling() { return this.next }
51
52
  get next() {
52
- if (!this.childIndex) return null
53
+ if (this.childIndex === null) return null
53
54
  return this.parent.children[this.childIndex + 1] || null
54
55
  }
55
56
 
@@ -70,7 +71,7 @@ class Node {
70
71
 
71
72
  get outerHTML() {
72
73
  const attrs = Object.entries(this.attributes).map(([key, val]) => val.length ? `${key}="${val}"` : key).join(" ");
73
- return `<${this.tagName}${attrs ? ' ' + attrs : ''}>${this.innerHTML}</${this.tagName}>`;
74
+ return `<${this._tagName}${attrs ? ' ' + attrs : ''}>${this.innerHTML}</${this._tagName}>`;
74
75
  }
75
76
 
76
77
  getAttribute(attrName) { return this.attributes[attrName] !== undefined ? this.attributes[attrName] : null }
@@ -91,6 +92,19 @@ class Node {
91
92
  }).join("");
92
93
  }
93
94
 
95
+ get innerText() {
96
+ return this.childNodes.map(child => {
97
+ if (child instanceof Node || child instanceof SingleNode) return child.innerText;
98
+ else if (child instanceof TextNode) return child.textContent; // Assuming child is a text node or something that can be stringified.
99
+ else return child
100
+ }).join("");
101
+ }
102
+
103
+ set innerText(value) {
104
+ this.childNodes = [new TextNode(value)]
105
+ return value
106
+ }
107
+
94
108
  $$(query) { return this.querySelectorAll(query) }
95
109
  querySelectorAll(query) {
96
110
  const selectors = Query.get(query)
@@ -109,7 +123,7 @@ class Node {
109
123
  get children() {
110
124
  return this.childNodes.filter(child => {
111
125
  if (!(child instanceof Node)) return false
112
- if (child.tagName === '#comment') return false
126
+ if (child._tagName === '#comment') return false
113
127
  return true
114
128
  });
115
129
  }
@@ -160,8 +174,8 @@ class Node {
160
174
 
161
175
  set innerHTML(html) {
162
176
  this.childNodes = html.trim().startsWith('<') ? parseHTML(html).childNodes : [html]
177
+ this.children.forEach(child => child.parent = this);
163
178
  }
164
-
165
179
  set outerHTML(html) {
166
180
  const parsed = parseHTML(html);
167
181
  if (!this.parent) throw new Error('element has no parent node')
@@ -6,9 +6,9 @@ class SingleNode extends Node {
6
6
  }
7
7
 
8
8
  get outerHTML() { // outerHTML for single node
9
- if (this.tagName === "#cdata-section") return `<![CDATA[${this.nodeValue}]]>`;
9
+ if (this._tagName === "#cdata-section") return `<![CDATA[${this.nodeValue}]]>`;
10
10
  const attrs = Object.entries(this.attributes).map(([key, val]) => val.length ? `${key}="${val}"` : key).join(" ");
11
- return `<${this.tagName} ${attrs}${this.tagName === '?xml' ? '?' : ''}>`;
11
+ return `<${this._tagName} ${attrs}${this._tagName === '?xml' ? '?' : ''}>`;
12
12
  }
13
13
  // Remove getters,setters and methods which no make sence in single node
14
14
  get innerHTML() { return ""; }
@@ -3,7 +3,7 @@ function buildFromCache(cached) {
3
3
  if(typeof cache === 'string') return parent.childNodes.push(cache)
4
4
  const {isSingle,tagName,attributes,childNodes,textContent} = cache
5
5
  if(textContent) return parent.childNodes.push(new TextNode(textContent))
6
- if(isSingle) return parent.childNodes.push(new SingleNode(tagName,attributes))
6
+ if(isSingle && parent) return parent.childNodes.push(new SingleNode(tagName,attributes))
7
7
  const newDoc = tagName === 'ROOT' ? new Root() : new Node(tagName,attributes,parent)
8
8
  childNodes.forEach(childNode => {
9
9
  buildNode(childNode,newDoc)
@@ -5,8 +5,8 @@ function checkElement(el,selector) {
5
5
  if(typeof el === 'string') return false
6
6
  if(id !== undefined && el.id === null) return false
7
7
  if(id && id !== el.id) return false
8
- if(tag && el.tagName === undefined) return false
9
- else if(tag && tag !== el.tagName) return false
8
+ if(tag && el._tagName === undefined) return false
9
+ else if(tag && tag !== el._tagName) return false
10
10
  const clas = el.attributes.class
11
11
  if(classList !== undefined && (clas === undefined || clas === '')) return false
12
12
  else if(classList !== undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "als-document",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "A powerful HTML parser & DOM manipulation library for both backend and frontend.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
package/readme.md CHANGED
@@ -40,16 +40,14 @@ import { parseHTML, Node, Query, TextNode, SingleNode, Root, Document } from 'al
40
40
  </script>
41
41
  ```
42
42
 
43
- ## Change log
44
- New in 1.2.0:
45
- * singleNode can insert(0) and insert(3)
46
- * insertAdjacentElement replace element instead cloning it
47
- * Document class
48
- * has structure <!DOCTYPE html><html lang="en"><head><title></title></head><body></body></html>
49
- * get title
50
- * set title
51
- * get body
52
- * get head
43
+ ## Change log for 1.3
44
+ * added getter and setter for node.innerText
45
+ * prev and next now works with childIndex=0
46
+ * querySelctor not includes the parent any more
47
+ * Document new getters and setters include clone
48
+ * tagName - uppers, _tagName - lowers
49
+
50
+
53
51
  ## parseHTML
54
52
 
55
53
  `parseHTML` is a function that takes an HTML string and constructs a DOM tree representation from it. It recognizes various HTML elements, such as comments, scripts, styles, and CDATA, and organizes them into nodes that can be manipulated and queried.
@@ -95,7 +93,9 @@ Remember, the actual tree structure will be more complex and detailed, but the p
95
93
  `Node` is a fundamental class that represents an element node in the DOM tree. It provides functionality similar to the native DOM API in browsers, but with its own implementation.
96
94
 
97
95
  ### Properties:
98
- - **tagName**: Represents the tag name of the element.
96
+ - **tagName**: Represents the tag name of the element (upper cased).
97
+ - **_tagName**: Represents the tag name of the element (lower cased).
98
+ - **innerText**
99
99
  - **attributes**: A dictionary of attributes and their values.
100
100
  - **childNodes**: An array of child nodes for the element.
101
101
  - **isSingle**: Boolean value to check if the node is a self-closing tag.
@@ -115,24 +115,6 @@ Remember, the actual tree structure will be more complex and detailed, but the p
115
115
  - **appendChild**: Add a child node to the element.
116
116
  - **insert(place,element)**: place (0-3) or beforebegin,afterbegin,... eleemnt - raw html or element
117
117
 
118
-
119
- ### SingleNode
120
-
121
- `SingleNode` extends from the `Node` class and represents elements that don't have closing tags (self-closing tags) in HTML. Examples include `<img>`, `<br>`, and `<!DOCTYPE>`. This class has restricted methods and properties since these elements can't have child nodes.
122
-
123
- ### TextNode
124
-
125
- `TextNode` is a class that represents text content within the DOM. A TextNode holds raw text data and does not have child nodes.
126
-
127
- ### Document node (extends Node)
128
-
129
- Has additional getters and setters:
130
- * getter root.title
131
- * setter root.title
132
- * getter root.body
133
- * getter root.head
134
-
135
-
136
118
 
137
119
  ### Examples:
138
120
 
@@ -153,6 +135,26 @@ console.log(foundP.textContent); // Outputs: Hello, world!
153
135
  ```
154
136
 
155
137
 
138
+ ### SingleNode
139
+
140
+ `SingleNode` extends from the `Node` class and represents elements that don't have closing tags (self-closing tags) in HTML. Examples include `<img>`, `<br>`, and `<!DOCTYPE>`. This class has restricted methods and properties since these elements can't have child nodes.
141
+
142
+ ### TextNode
143
+
144
+ `TextNode` is a class that represents text content within the DOM. A TextNode holds raw text data and does not have child nodes.
145
+
146
+ ### Document node (extends Node)
147
+
148
+ Has additional getters and setters:
149
+ * get documentElement
150
+ * get html
151
+ * get head
152
+ * get body
153
+ * get title
154
+ * get charset
155
+ * set title
156
+ * get clone - return cloned new instance of Document
157
+
156
158
  ## Query
157
159
 
158
160
  The `Query` class is designed to parse CSS selector strings and transform them into a structured object format, providing detailed insights into each selector and its components.
@@ -0,0 +1,67 @@
1
+ const { describe, it, beforeEach } = require('node:test');
2
+ const assert = require('node:assert');
3
+ const { Node, Root, TextNode, Document } = require('../index')
4
+
5
+ describe('NodeClassList', () => {
6
+ let node;
7
+
8
+ beforeEach(() => {
9
+ node = new Node('div');
10
+ });
11
+
12
+ it('className', () => {
13
+ node.setAttribute('class','some test')
14
+ assert(node.className === 'some test')
15
+ })
16
+
17
+ it('initially has no classes', () => {
18
+ assert.deepStrictEqual(node.classList.classes, []);
19
+ });
20
+
21
+ it('adds a class', () => {
22
+ node.classList.add('test-class');
23
+ assert.deepStrictEqual(node.classList.classes, ['test-class']);
24
+ assert.strictEqual(node.attributes.class, 'test-class');
25
+ });
26
+
27
+ it('removes a class', () => {
28
+ node.attributes.class = 'test-class another-class';
29
+ node.classList.remove('test-class');
30
+ assert.deepStrictEqual(node.classList.classes, ['another-class']);
31
+ });
32
+
33
+ it('does not remove a class that does not exist', () => {
34
+ node.attributes.class = 'test-class';
35
+ node.classList.remove('nonexistent-class');
36
+ assert.deepStrictEqual(node.classList.classes, ['test-class']);
37
+ });
38
+
39
+ it('toggles a class off if it is present', () => {
40
+ node.attributes.class = 'test-class';
41
+ node.classList.toggle('test-class');
42
+ assert.deepStrictEqual(node.classList.classes, []);
43
+ });
44
+
45
+ it('toggles a class on if it is not present', () => {
46
+ node.classList.toggle('test-class');
47
+ assert.deepStrictEqual(node.classList.classes, ['test-class']);
48
+ });
49
+
50
+ it('replaces an old class with a new one', () => {
51
+ node.attributes.class = 'old-class';
52
+ node.classList.replace('old-class', 'new-class');
53
+ assert.deepStrictEqual(node.classList.classes, ['new-class']);
54
+ });
55
+
56
+ it('contains checks for the presence of a class', () => {
57
+ node.attributes.class = 'test-class';
58
+ assert(node.classList.contains('test-class'));
59
+ assert(!node.classList.contains('nonexistent-class'));
60
+ });
61
+
62
+ it('sets multiple classes', () => {
63
+ node.classList.classes = ['class1', 'class2'];
64
+ assert.strictEqual(node.attributes.class, 'class1 class2');
65
+ assert.deepStrictEqual(node.classList.classes, ['class1', 'class2']);
66
+ });
67
+ });
@@ -0,0 +1,90 @@
1
+ const { describe, it, beforeEach } = require('node:test');
2
+ const assert = require('node:assert');
3
+ const { Node, Document } = require('../index');
4
+
5
+ describe('Constructor and Basic Properties', () => {
6
+ let doc;
7
+
8
+ beforeEach(() => {
9
+ doc = new Document('<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Test Title</title></head><body></body></html>', 'http://example.com');
10
+ });
11
+
12
+ it('get documentElement', () => {
13
+ assert.strictEqual(doc.documentElement.tagName, 'HTML');
14
+ });
15
+
16
+ it('get html', () => {
17
+ assert.strictEqual(doc.html.tagName, 'HTML');
18
+ });
19
+
20
+ it('get head', () => {
21
+ assert.strictEqual(doc.head.tagName, 'HEAD');
22
+ });
23
+
24
+ it('get body', () => {
25
+ assert.strictEqual(doc.body.tagName, 'BODY');
26
+ });
27
+
28
+ it('get title', () => {
29
+ assert.strictEqual(doc.title, 'Test Title');
30
+ });
31
+
32
+ it('get charset', () => {
33
+ assert.strictEqual(doc.charset.getAttribute('charset'), 'UTF-8');
34
+ });
35
+
36
+ it('set title', () => {
37
+ doc.title = 'New Title';
38
+ assert.strictEqual(doc.title, 'New Title');
39
+ });
40
+
41
+ it('get clone', () => {
42
+ const clone = doc.clone;
43
+ assert(clone instanceof Document);
44
+ assert.strictEqual(clone.title, doc.title);
45
+ assert.notStrictEqual(clone, doc); // Ensure that cloned object is a separate instance
46
+ assert(doc.innerHTML === clone.innerHTML)
47
+ });
48
+
49
+ });
50
+
51
+ describe('Document Class Tests with Various Scenarios', () => {
52
+ describe('Missing Elements Handling', () => {
53
+ it('should create and return a new head if head is initially missing', () => {
54
+ const doc = new Document('<!DOCTYPE html><html lang="en"><body></body></html>', 'http://example.com');
55
+ assert.strictEqual(doc.head.tagName, 'HEAD');
56
+ });
57
+
58
+ it('should create and return a new body if body is initially missing', () => {
59
+ const doc = new Document('<!DOCTYPE html><html lang="en"><head></head></html>', 'http://example.com');
60
+ assert.strictEqual(doc.body.tagName, 'BODY');
61
+ });
62
+
63
+ it('should handle missing html element gracefully', () => {
64
+ const doc = new Document('', 'http://example.com');
65
+ assert.strictEqual(doc.html.tagName, 'HTML');
66
+ assert.strictEqual(doc.head.tagName, 'HEAD');
67
+ assert.strictEqual(doc.body.tagName, 'BODY');
68
+ });
69
+
70
+ it('should handle completely empty document and reconstruct the HTML structure', () => {
71
+ const doc = new Document('', 'http://example.com');
72
+ assert.strictEqual(doc.html.tagName, 'HTML');
73
+ assert(doc.head, 'Head element should be created if missing');
74
+ assert(doc.body, 'Body element should be created if missing');
75
+ });
76
+
77
+ it('should handle missing title tag and be able to set a new title', () => {
78
+ const doc = new Document('<!DOCTYPE html><html lang="en"><head></head><body></body></html>', 'http://example.com');
79
+ assert.strictEqual(doc.title, ''); // Assuming title is empty if missing
80
+ doc.title = 'New Title';
81
+ assert.strictEqual(doc.title, 'New Title');
82
+ });
83
+
84
+ it('should handle documents with no charset meta tag', () => {
85
+ const doc = new Document('<!DOCTYPE html><html lang="en"><head><title></title></head><body></body></html>', 'http://example.com');
86
+ assert.strictEqual(doc.charset, null); // Assuming charset is null if no meta charset tag
87
+ });
88
+
89
+ });
90
+ });
@@ -13,7 +13,7 @@ describe('Constructor and Basic Properties', () => {
13
13
  const rootNode = new Node('ROOT');
14
14
  const divNode = new Node('div', { class: 'container' }, rootNode);
15
15
 
16
- assert(divNode.tagName === 'div', "Tag name is correct");
16
+ assert(divNode.tagName === 'DIV', "Tag name is correct");
17
17
  assert(divNode.attributes.class === 'container', "Attributes are correct");
18
18
  assert(divNode.parent === rootNode, "Parent node is correct");
19
19
  });
@@ -128,13 +128,13 @@ describe('Content Manipulation', () => {
128
128
  const childNode = new Node('p', {}, rootNode);
129
129
 
130
130
  childNode.insertAdjacentElement('beforebegin', new Node('span'));
131
- assert(rootNode.childNodes[0].tagName === 'span');
131
+ assert(rootNode.childNodes[0].tagName === 'SPAN');
132
132
 
133
133
  childNode.insertAdjacentElement('afterend', new Node('a'));
134
- assert(rootNode.childNodes[2].tagName === 'a');
134
+ assert(rootNode.childNodes[2].tagName === 'A');
135
135
 
136
136
  childNode.insertAdjacentHTML('beforebegin', '<strong></strong>');
137
- assert(rootNode.childNodes[1].tagName === 'strong');
137
+ assert(rootNode.childNodes[1].tagName === 'STRONG');
138
138
 
139
139
  childNode.insertAdjacentText('afterend', 'Some text');
140
140
  assert(typeof rootNode.childNodes[3].nodeValue === 'string');
@@ -185,9 +185,9 @@ describe('Other Methods and Properties', () => {
185
185
 
186
186
  // Проверяем свойство children
187
187
  assert(rootNode.children.length === 3);
188
- assert(rootNode.children[0].tagName === 'p');
189
- assert(rootNode.children[1].tagName === 'span');
190
- assert(rootNode.children[2].tagName === 'a');
188
+ assert(rootNode.children[0].tagName.toLowerCase() === 'p');
189
+ assert(rootNode.children[1].tagName.toLowerCase() === 'span');
190
+ assert(rootNode.children[2].tagName.toLowerCase() === 'a');
191
191
  });
192
192
 
193
193
  it('Gets the parent element', () => {
@@ -403,9 +403,9 @@ describe('Document element', () => {
403
403
  it('get and set title', () => {
404
404
  const root = new Document();
405
405
  root.title = 'Original Title';
406
- assert.strictEqual(root.title.textContent, 'Original Title', 'Should get the title');
406
+ assert.strictEqual(root.title, 'Original Title', 'Should get the title');
407
407
  root.title = 'New Title';
408
- assert.strictEqual(root.title.textContent, 'New Title', 'Should set the new title');
408
+ assert.strictEqual(root.title, 'New Title', 'Should set the new title');
409
409
  });
410
410
 
411
411
  })
@@ -16,17 +16,17 @@ describe('HTML Parser', () => {
16
16
  });
17
17
 
18
18
  it('correctly sets node type', () => {
19
- assert(parsedHTML.tagName === 'div');
19
+ assert(parsedHTML.tagName.toLowerCase() === 'div');
20
20
  });
21
21
 
22
22
  it.skip('correctly sets child nodes', () => {
23
23
  assert(parsedHTML.children.leng === 1);
24
- assert(parsedHTML.children[0].tagName === 'p');
24
+ assert(parsedHTML.children[0].tagName.toLowerCase() === 'p');
25
25
  });
26
26
 
27
27
  it('correctly parses nested HTML', () => {
28
28
  const nestedHTML = parseHTML('<div><span><a href="#">Link</a></span></div>');
29
- assert(nestedHTML.children[0].children[0].children[0].tagName === 'a');
29
+ assert(nestedHTML.children[0].children[0].children[0].tagName.toLowerCase() === 'a');
30
30
  });
31
31
 
32
32
  it('correctly parses text nodes', () => {
@@ -65,7 +65,7 @@ describe('Advanced tests', () => {
65
65
  const result = parseHTML('<div><p>Text</div>');
66
66
  // Depending on the behavior you expect: either an error, or a specific structure.
67
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');
68
+ assert(result.children[0].children[0].tagName.toLowerCase() === 'p');
69
69
  });
70
70
 
71
71
  it('handles attributes without values', () => {
@@ -76,7 +76,7 @@ describe('Advanced tests', () => {
76
76
  it('ignores comments', () => {
77
77
  const result = parseHTML('<!-- this is a comment --><div></div>');
78
78
  assert(result.children.length === 1);
79
- assert(result.children[0].tagName === 'div');
79
+ assert(result.children[0].tagName.toLowerCase() === 'div');
80
80
  });
81
81
 
82
82
  it('correctly parses script content', () => {
@@ -152,17 +152,17 @@ describe('CDATA', () => {
152
152
  it('basic test', () => {
153
153
  const test1 = '<![CDATA[This is CDATA content]]>';
154
154
  const root1 = parseHTML(test1);
155
- assert(root1.childNodes[0].tagName === "#cdata-section", "Test 1: CDATA node not created");
155
+ assert(root1.childNodes[0].tagName.toLowerCase() === "#cdata-section", "Test 1: CDATA node not created");
156
156
  assert(root1.childNodes[0].nodeValue === "This is CDATA content", "Test 1: CDATA content not correct");
157
157
  })
158
158
 
159
159
  it('nested CDATA', () => {
160
160
  const test2 = '<div><![CDATA[Inside a div]]><p>Paragraph</p></div>';
161
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");
162
+ assert(root2.childNodes[0].tagName.toLowerCase() === "div", "Test 2: Parent div not created");
163
+ assert(root2.childNodes[0].childNodes[0].tagName.toLowerCase() === "#cdata-section", "Test 2: CDATA node not created inside div");
164
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");
165
+ assert(root2.childNodes[0].childNodes[1].tagName.toLowerCase() === "p", "Test 2: Paragraph not created after CDATA");
166
166
  })
167
167
 
168
168
  it('multiple lines', () => {
@@ -173,7 +173,7 @@ inside this CDATA
173
173
  block.
174
174
  ]]>`;
175
175
  const root3 = parseHTML(test3);
176
- assert(root3.childNodes[0].tagName === "#cdata-section", "Test 3: CDATA node not created");
176
+ assert(root3.childNodes[0].tagName.toLowerCase() === "#cdata-section", "Test 3: CDATA node not created");
177
177
  assert(root3.childNodes[0].nodeValue.trim() === "Multiple lines \ninside this CDATA\nblock.", "Test 3: Multi-line CDATA content not correct");
178
178
 
179
179
  })
@@ -181,7 +181,7 @@ block.
181
181
  it('inside html', () => {
182
182
  const test4 = '<![CDATA[<span>This should be text</span>]]>';
183
183
  const root4 = parseHTML(test4);
184
- assert(root4.childNodes[0].tagName === "#cdata-section", "Test 4: CDATA node not created");
184
+ assert(root4.childNodes[0].tagName.toLowerCase() === "#cdata-section", "Test 4: CDATA node not created");
185
185
  assert(root4.childNodes[0].nodeValue === "<span>This should be text</span>", "Test 4: HTML inside CDATA not treated as text");
186
186
 
187
187
  })
@@ -201,9 +201,9 @@ describe('signle tags, script and style', () => {
201
201
  </script>
202
202
  `;
203
203
  const rootStyleScript = parseHTML(testStyleScript);
204
- assert(rootStyleScript.childNodes[0].tagName === "style", "Test Style/Script 1: Style tag not created");
204
+ assert(rootStyleScript.childNodes[0].tagName.toLowerCase() === "style", "Test Style/Script 1: Style tag not created");
205
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");
206
+ assert(rootStyleScript.childNodes[1].tagName.toLowerCase() === "script", "Test Style/Script 2: Script tag not created");
207
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
208
  })
209
209
 
@@ -213,9 +213,9 @@ describe('signle tags, script and style', () => {
213
213
  <link rel="stylesheet" href="styles.css">
214
214
  `;
215
215
  const rootMetaLink = parseHTML(testMetaLink);
216
- assert(rootMetaLink.children[0].tagName === "meta", "Test Meta/Link 1: Meta tag not created");
216
+ assert(rootMetaLink.children[0].tagName.toLowerCase() === "meta", "Test Meta/Link 1: Meta tag not created");
217
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");
218
+ assert(rootMetaLink.children[1].tagName.toLowerCase() === "link", "Test Meta/Link 2: Link tag not created");
219
219
  assert(rootMetaLink.children[1].getAttribute("rel") === "stylesheet", "Test Meta/Link 2: Link rel attribute not correct");
220
220
  assert(rootMetaLink.children[1].getAttribute("href") === "styles.css", "Test Meta/Link 2: Link href attribute not correct");
221
221
  })
@@ -224,7 +224,7 @@ describe('signle tags, script and style', () => {
224
224
  const testUnmatchedClose = `<div>Some content</p></div>`;
225
225
  const rootUnmatchedClose = parseHTML(testUnmatchedClose);
226
226
  // Зависит от вашего решения обработки. Если вы решите исправлять такой HTML, тест может выглядеть так:
227
- assert(rootUnmatchedClose.childNodes[0].tagName === "div", "Test Unmatched Close: Div tag not created");
227
+ assert(rootUnmatchedClose.childNodes[0].tagName.toLowerCase() === "div", "Test Unmatched Close: Div tag not created");
228
228
  assert(rootUnmatchedClose.childNodes[0].textContent.trim() === "Some content", "Test Unmatched Close: Div content not correct");
229
229
  })
230
230
 
@@ -232,7 +232,7 @@ describe('signle tags, script and style', () => {
232
232
  const testUnmatchedOpen = `<div>Some content`;
233
233
  const rootUnmatchedOpen = parseHTML(testUnmatchedOpen);
234
234
  // Снова зависит от вашего решения. Если вы решите автоматически закрывать тег:
235
- assert(rootUnmatchedOpen.childNodes[0].tagName === "div", "Test Unmatched Open: Div tag not created");
235
+ assert(rootUnmatchedOpen.childNodes[0].tagName.toLowerCase() === "div", "Test Unmatched Open: Div tag not created");
236
236
  assert(rootUnmatchedOpen.childNodes[0].textContent.trim() === "Some content", "Test Unmatched Open: Div content not correct");
237
237
  })
238
238
  })
@@ -284,7 +284,7 @@ describe('Specific elements handling', () => {
284
284
  const html = parseHTML(canvas)
285
285
  const canvasElement = html.children[0]
286
286
 
287
- assert(canvasElement.tagName === 'canvas');
287
+ assert(canvasElement.tagName.toLowerCase() === 'canvas');
288
288
  assert(canvasElement.getAttribute('id') === 'myCanvas');
289
289
  assert(canvasElement.getAttribute('width') === '300');
290
290
  assert(canvasElement.getAttribute('height') === '150');
@@ -299,7 +299,7 @@ describe('Specific elements handling', () => {
299
299
  const html = parseHTML(svgHTML);
300
300
  const svgElement = html.children[0]
301
301
 
302
- assert(svgElement.tagName === 'svg');
302
+ assert(svgElement.tagName.toLowerCase() === 'svg');
303
303
  assert(svgElement.getAttribute('xmlns') === svgNamespace);
304
304
  assert(svgElement.getAttribute('xmlns:xml') === xmlNamespace);
305
305
  });