@tkeron/html-parser 0.1.4 → 0.1.5
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.
- package/README.md +5 -5
- package/index.ts +0 -5
- package/package.json +1 -1
- package/src/css-selector.ts +0 -5
- package/src/dom-simulator.ts +122 -45
- package/src/tokenizer.ts +0 -20
- package/tests/advanced.test.ts +2 -2
- package/tests/cloneNode.test.ts +50 -50
- package/tests/custom-elements.test.ts +8 -8
- package/tests/official/acid/acid-tests.test.ts +6 -6
- package/tests/official/final-output/final-output.test.ts +15 -15
- package/tests/official/html5lib/tokenizer-utils.ts +19 -31
- package/tests/official/html5lib/tokenizer.test.ts +4 -4
- package/tests/official/html5lib/tree-construction-utils.ts +20 -34
- package/tests/official/html5lib/tree-construction.test.ts +5 -5
- package/tests/official/validator/validator-tests.test.ts +11 -11
- package/tests/official/wpt/wpt-tests.test.ts +5 -5
- package/tests/outerHTML-replacement.test.ts +208 -0
- package/tests/parser.test.ts +1 -1
- package/tests/test-page-0.txt +12 -355
- package/tests/api-integration.test.ts +0 -114
- package/tests/cloneNode-bug-reproduction.test.ts +0 -325
- package/tests/cloneNode-interactive.ts +0 -235
- package/tests/dom-adoption.test.ts +0 -363
- package/tests/dom-synchronization.test.ts +0 -675
- package/tests/setAttribute-outerHTML.test.ts +0 -102
package/tests/test-page-0.txt
CHANGED
|
@@ -1,362 +1,19 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
2
|
<!DOCTYPE html>
|
|
4
|
-
<html lang="
|
|
3
|
+
<html lang="en"><head>
|
|
5
4
|
<meta charset="UTF-8">
|
|
6
|
-
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
7
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
8
|
-
<title>
|
|
9
|
-
<style
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
background-size: cover;
|
|
19
|
-
|
|
20
|
-
position: relative;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.container .content {
|
|
24
|
-
max-width: 1280px;
|
|
25
|
-
width: 100%;
|
|
26
|
-
z-index: 1;
|
|
27
|
-
padding: 0px 15px;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.container .bg_color {
|
|
31
|
-
position: absolute;
|
|
32
|
-
|
|
33
|
-
top: 0px;
|
|
34
|
-
left: 0px;
|
|
35
|
-
|
|
36
|
-
height: 100%;
|
|
37
|
-
width: 100%;
|
|
38
|
-
|
|
39
|
-
z-index: 0;
|
|
40
|
-
}
|
|
41
|
-
</style><style>a.a {
|
|
42
|
-
text-decoration: none;
|
|
43
|
-
}
|
|
44
|
-
</style><style>.logo {
|
|
45
|
-
height: 62%;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
a.logo {
|
|
49
|
-
height: 100%;
|
|
50
|
-
}
|
|
51
|
-
</style><style>.footer {
|
|
52
|
-
padding-top: 80px;
|
|
53
|
-
width: 100%;
|
|
54
|
-
background: #060303;
|
|
55
|
-
color: #eed;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.footer a {
|
|
59
|
-
text-decoration: none;
|
|
60
|
-
color: #eed;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.footer a:visited {
|
|
64
|
-
color: inherit;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.footer a {
|
|
68
|
-
grid-area: a;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.footer .copyright {
|
|
72
|
-
grid-area: c;
|
|
73
|
-
justify-self: center;
|
|
74
|
-
margin-top: 40px;
|
|
75
|
-
font-size: 12px;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.footer .content {
|
|
79
|
-
display: grid;
|
|
80
|
-
grid-template:
|
|
81
|
-
"l a1 a4"
|
|
82
|
-
"l a2 a5"
|
|
83
|
-
"l a3 a6"
|
|
84
|
-
"l a7 a8"
|
|
85
|
-
"c c c";
|
|
86
|
-
justify-content: space-between;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.footer .logo {
|
|
90
|
-
max-width: 250px;
|
|
91
|
-
height: auto;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.footer a.logo {
|
|
95
|
-
grid-area: l;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@media screen and (max-width: 800px) {
|
|
99
|
-
.footer .content {
|
|
100
|
-
display: grid;
|
|
101
|
-
grid-template:
|
|
102
|
-
"a1 a4"
|
|
103
|
-
"a2 a5"
|
|
104
|
-
"a3 a6"
|
|
105
|
-
"a7 a8"
|
|
106
|
-
"l l"
|
|
107
|
-
"c c";
|
|
108
|
-
justify-content: space-evenly;
|
|
109
|
-
}
|
|
110
|
-
.footer .logo {
|
|
111
|
-
margin-top: 20px;
|
|
112
|
-
justify-self: center;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
</style><style>.top {
|
|
116
|
-
background: linear-gradient(0deg, #060303, #6c6868);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.container.top .content {
|
|
120
|
-
display: flex;
|
|
121
|
-
flex-direction: row;
|
|
122
|
-
justify-content: space-between;
|
|
123
|
-
align-items: center;
|
|
124
|
-
|
|
125
|
-
height: 90px;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.container.top .content a {
|
|
129
|
-
display: flex;
|
|
130
|
-
|
|
131
|
-
align-items: center;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
@media screen and (max-width: 600px) {
|
|
135
|
-
.container.top .content {
|
|
136
|
-
height: 60px;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
</style><style>
|
|
140
|
-
.sectionMenu .content {
|
|
141
|
-
width: 100%;
|
|
142
|
-
display: flex;
|
|
143
|
-
justify-content: space-between;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
padding-top: 10px;
|
|
147
|
-
padding-bottom: 10px;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
font-weight: bold;
|
|
151
|
-
font-size: 20px;
|
|
152
|
-
color: #fff;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.sectionMenu {
|
|
156
|
-
background: linear-gradient(0deg, #f2be11, #87722d);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.sectionMenu a.a {
|
|
160
|
-
color: white;
|
|
161
|
-
}
|
|
162
|
-
</style><style></style><style>.button,
|
|
163
|
-
button {
|
|
164
|
-
border: none;
|
|
165
|
-
padding: 20px 35px;
|
|
166
|
-
font-size: 30px;
|
|
167
|
-
font-weight: bold;
|
|
168
|
-
border-radius: 15px;
|
|
169
|
-
cursor: pointer;
|
|
170
|
-
|
|
171
|
-
color: #1c1c1c;
|
|
172
|
-
background: #f2be11;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
a.button {
|
|
176
|
-
display: block;
|
|
177
|
-
width: fit-content;
|
|
178
|
-
margin: 20px;
|
|
179
|
-
text-align: center;
|
|
180
|
-
}
|
|
181
|
-
</style><style>.container.header .content {
|
|
182
|
-
display: grid;
|
|
183
|
-
grid-template-areas:
|
|
184
|
-
"h1 h1"
|
|
185
|
-
"im h2";
|
|
186
|
-
grid-template-columns: 1fr 720px;
|
|
187
|
-
gap: 30px;
|
|
188
|
-
margin: 50px auto;
|
|
189
|
-
color: #eed;
|
|
190
|
-
}
|
|
191
|
-
.service .content {
|
|
192
|
-
display: grid;
|
|
193
|
-
grid-template-areas:
|
|
194
|
-
"h3 h3"
|
|
195
|
-
"h4 h4"
|
|
196
|
-
"a p";
|
|
197
|
-
grid-template-columns: 1fr 720px;
|
|
198
|
-
gap: 30px;
|
|
199
|
-
margin: 100px auto;
|
|
200
|
-
color: #4c4c4c;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
.header .content h1 {
|
|
204
|
-
grid-area: h1;
|
|
205
|
-
}
|
|
206
|
-
.header .content h2 {
|
|
207
|
-
grid-area: h2;
|
|
208
|
-
}
|
|
209
|
-
.header .content img {
|
|
210
|
-
grid-area: im;
|
|
211
|
-
width: 100%;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
.service .content a {
|
|
215
|
-
display: flex;
|
|
216
|
-
grid-area: a;
|
|
217
|
-
justify-content: center;
|
|
218
|
-
align-items: center;
|
|
219
|
-
margin-left: 0;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.service .content h3 {
|
|
223
|
-
grid-area: h3;
|
|
224
|
-
max-width: 720px;
|
|
225
|
-
}
|
|
226
|
-
.service .content h4 {
|
|
227
|
-
grid-area: h4;
|
|
228
|
-
max-width: 720px;
|
|
229
|
-
}
|
|
230
|
-
.service .content p {
|
|
231
|
-
grid-area: p;
|
|
232
|
-
max-width: 720px;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
.service.service4,
|
|
236
|
-
.service.service2 {
|
|
237
|
-
background: #4c4c4c;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
.service.service4 .content,
|
|
241
|
-
.service.service2 .content {
|
|
242
|
-
color: #eed;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
.container.cta .content {
|
|
246
|
-
display: flex;
|
|
247
|
-
justify-content: center;
|
|
248
|
-
align-items: center;
|
|
249
|
-
flex-direction: column;
|
|
250
|
-
margin: 100px auto;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
@media screen and (max-width: 1280px) {
|
|
254
|
-
.service .content {
|
|
255
|
-
grid-template-areas:
|
|
256
|
-
"h3 h3"
|
|
257
|
-
"h4 h4"
|
|
258
|
-
". p"
|
|
259
|
-
"a a";
|
|
260
|
-
grid-template-columns: 1fr;
|
|
261
|
-
gap: 30px;
|
|
262
|
-
}
|
|
263
|
-
.service .content a {
|
|
264
|
-
justify-content: center;
|
|
265
|
-
align-items: center;
|
|
266
|
-
margin-left: 0;
|
|
267
|
-
justify-self: end;
|
|
268
|
-
margin-right: 0;
|
|
269
|
-
}
|
|
270
|
-
.container.header .content {
|
|
271
|
-
display: grid;
|
|
272
|
-
grid-template-areas:
|
|
273
|
-
"h1 h1"
|
|
274
|
-
"im h2";
|
|
275
|
-
grid-template-columns: 1fr 2fr;
|
|
276
|
-
gap: 30px;
|
|
277
|
-
margin: 50px auto;
|
|
278
|
-
color: #eed;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
@media screen and (max-width: 700px) {
|
|
282
|
-
.container.header .content {
|
|
283
|
-
grid-template-areas:
|
|
284
|
-
"h1"
|
|
285
|
-
"h2";
|
|
286
|
-
grid-template-columns: 1fr;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
</style><style>* {
|
|
290
|
-
margin: 0;
|
|
291
|
-
padding: 0;
|
|
292
|
-
box-sizing: border-box;
|
|
293
|
-
transition: all 0.3s ease;
|
|
294
|
-
font-family: inherit;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
body,
|
|
298
|
-
button {
|
|
299
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
300
|
-
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
|
301
|
-
|
|
302
|
-
line-height: 1.6;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
h1 {
|
|
306
|
-
font-size: 60px;
|
|
307
|
-
}
|
|
308
|
-
h2 {
|
|
309
|
-
font-size: 42px;
|
|
310
|
-
}
|
|
311
|
-
h3 {
|
|
312
|
-
font-size: 32px;
|
|
313
|
-
}
|
|
314
|
-
h4 {
|
|
315
|
-
font-size: 20px;
|
|
316
|
-
}
|
|
317
|
-
p {
|
|
318
|
-
font-size: 18px;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
@media screen and (max-width: 1200px) {
|
|
322
|
-
h1 {
|
|
323
|
-
font-size: 42px;
|
|
324
|
-
}
|
|
325
|
-
h2 {
|
|
326
|
-
font-size: 32px;
|
|
327
|
-
}
|
|
328
|
-
h3 {
|
|
329
|
-
font-size: 20px;
|
|
330
|
-
}
|
|
331
|
-
h4 {
|
|
332
|
-
font-size: 18px;
|
|
333
|
-
}
|
|
334
|
-
p {
|
|
335
|
-
font-size: 16px;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
@media screen and (max-width: 800px) {
|
|
340
|
-
h1 {
|
|
341
|
-
font-size: 32px;
|
|
342
|
-
}
|
|
343
|
-
h2 {
|
|
344
|
-
font-size: 20px;
|
|
345
|
-
}
|
|
346
|
-
h3 {
|
|
347
|
-
font-size: 18px;
|
|
348
|
-
}
|
|
349
|
-
h4{
|
|
350
|
-
font-size: 16px;
|
|
351
|
-
}
|
|
352
|
-
p {
|
|
353
|
-
font-size: 14px;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
</style><script id='tkeron_page_js'>(()=>{})();
|
|
357
|
-
</script></head>
|
|
6
|
+
<title>Lorem Ipsum Services</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
body { font-family: Arial, sans-serif; line-height: 1.6; }
|
|
10
|
+
.container { max-width: 1200px; margin: 0 auto; padding: 20px; }
|
|
11
|
+
.header { background: #333; color: #fff; text-align: center; padding: 60px 20px; }
|
|
12
|
+
.service { margin: 40px 0; padding: 20px; border: 1px solid #ddd; }
|
|
13
|
+
.footer { background: #f4f4f4; padding: 20px; text-align: center; margin-top: 40px; }
|
|
14
|
+
</style>
|
|
15
|
+
</head>
|
|
358
16
|
|
|
359
17
|
<body>
|
|
360
18
|
|
|
361
|
-
<div class="container top"><div class="content"><a class="a logo" href="/"><img class="logo" src="/./
|
|
362
|
-
</body></html>
|
|
19
|
+
<div class="container top"><div class="content"><a class="a logo" href="/"><img class="logo" src="/./logo.png"></a></div></div><div class="container sectionMenu"><div class="content"><a class="a" href="/">HOME</a><a class="a" href="/services">SERVICES</a><a class="a" href="/contact">CONTACT</a></div></div><div class="container header" style="background-image: url("/./bg.png");"><div class="bg_color" style="background: rgba(0, 0, 0, 0.4);"></div><div class="content"><h1>Our Services</h1><h2>Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor.</h2></div></div><div class="container service service1"><div class="content"><h3>Custom Lorem Applications</h3><h4>Lorem ipsum dolor sit amet consectetur adipiscing elit.</h4><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p><a class="a button" href="/contact/custom-apps">Request custom app</a></div></div><div class="container service service2"><div class="content"><h3>Process Automation</h3><h4>Ut enim ad minim veniam quis nostrud exercitation ullamco.</h4><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p><a class="a button" href="/contact/automation">Automate processes</a></div></div><div class="container service service3"><div class="content"><h3>Custom Widgets</h3><h4>Excepteur sint occaecat cupidatat non proident sunt in culpa.</h4><p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.</p><a class="a button" href="/contact/widgets">Add custom widget</a></div></div><div class="container service service4"><div class="content"><h3>API Integrations</h3><h4>Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut.</h4><p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium.</p><a class="a button" href="/contact/api">Integrate APIs</a></div></div><div class="container service service5"><div class="content"><h3>Other Custom Needs</h3><h4>Quis autem vel eum iure reprehenderit qui in ea voluptate.</h4><p>Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates.</p><a class="a button" href="/contact/other">Propose your idea</a></div></div><div class="container footer"><div class="content"><a class="a logo" href="/"><img class="logo" src="/./logo.png"></a><div class="copyright">© 2025 LOREM IPSUM TECH. All rights reserved.</div><a class="a" href="/" style="grid-area: a1;">Home</a><a class="a" href="/services" style="grid-area: a2;">Services</a><a class="a" href="/contact" style="grid-area: a3;">Contact</a><a class="a" href="/privacy-policy" style="grid-area: a4;">Privacy Policy</a><a class="a" href="/terms" style="grid-area: a5;">Terms</a><a class="a" href="/cookies" style="grid-area: a6;">Cookies Policy</a></div></div><script defer src="https://static.cloudflareinsights.com/beacon.min.js/vcd15cbe7772f49c399c6a5babf22c1241717689176015" integrity="sha512-ZpsOmlRQV6y907TI0dKBHq9Md29nnaEIPlkf84rnaERnq6zvWvPUqr2ft8M1aS28oN72PdrCzSjY4U6VaAw1EQ==" data-cf-beacon='{"rayId":"955eb8668eaacdc9","version":"2025.6.2","r":1,"token":"09161630e3ae4c94992e51777c351c88","serverTiming":{"name":{"cfExtPri":true,"cfEdge":true,"cfOrigin":true,"cfL4":true,"cfSpeedBrain":true,"cfCacheStatus":true}}}' crossorigin="anonymous"></script>
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'bun:test';
|
|
2
|
-
import { parseHTML } from '../index';
|
|
3
|
-
|
|
4
|
-
describe('API Integration Tests - Real DOM Usage', () => {
|
|
5
|
-
it('should work like real DOM API - querySelector and setAttribute integrated', () => {
|
|
6
|
-
const doc = parseHTML(`
|
|
7
|
-
<html>
|
|
8
|
-
<head>
|
|
9
|
-
<title>Test Document</title>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<div id="container" class="main">
|
|
13
|
-
<h1>Welcome</h1>
|
|
14
|
-
<p class="intro">This is a paragraph.</p>
|
|
15
|
-
<ul>
|
|
16
|
-
<li>Item 1</li>
|
|
17
|
-
<li>Item 2</li>
|
|
18
|
-
</ul>
|
|
19
|
-
</div>
|
|
20
|
-
</body>
|
|
21
|
-
</html>
|
|
22
|
-
`);
|
|
23
|
-
|
|
24
|
-
expect(typeof doc.querySelector).toBe('function');
|
|
25
|
-
expect(typeof doc.querySelectorAll).toBe('function');
|
|
26
|
-
expect(typeof doc.createElement).toBe('function');
|
|
27
|
-
expect(typeof doc.createTextNode).toBe('function');
|
|
28
|
-
|
|
29
|
-
const container = doc.querySelector('#container');
|
|
30
|
-
expect(container).toBeTruthy();
|
|
31
|
-
expect(container?.tagName).toBe('DIV');
|
|
32
|
-
|
|
33
|
-
expect(typeof container?.querySelector).toBe('function');
|
|
34
|
-
expect(typeof container?.setAttribute).toBe('function');
|
|
35
|
-
expect(typeof container?.getAttribute).toBe('function');
|
|
36
|
-
|
|
37
|
-
const h1 = container?.querySelector('h1');
|
|
38
|
-
expect(h1).toBeTruthy();
|
|
39
|
-
expect(h1?.tagName).toBe('H1');
|
|
40
|
-
expect(h1?.textContent).toBe('Welcome');
|
|
41
|
-
|
|
42
|
-
h1?.setAttribute('class', 'title');
|
|
43
|
-
expect(h1?.getAttribute('class')).toBe('title');
|
|
44
|
-
expect(h1?.hasAttribute('class')).toBe(true);
|
|
45
|
-
|
|
46
|
-
const allLi = doc.querySelectorAll('li');
|
|
47
|
-
expect(allLi.length).toBe(2);
|
|
48
|
-
expect(allLi[0]?.tagName).toBe('LI');
|
|
49
|
-
expect(allLi[1]?.tagName).toBe('LI');
|
|
50
|
-
|
|
51
|
-
const newElement = doc.createElement('span');
|
|
52
|
-
newElement.setAttribute('id', 'new-span');
|
|
53
|
-
container?.appendChild(newElement);
|
|
54
|
-
|
|
55
|
-
const spanElement = container?.querySelector('#new-span');
|
|
56
|
-
expect(spanElement).toBeTruthy();
|
|
57
|
-
expect(spanElement?.tagName).toBe('SPAN');
|
|
58
|
-
expect(spanElement?.getAttribute('id')).toBe('new-span');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should work for complex DOM manipulation scenarios', () => {
|
|
62
|
-
const doc = parseHTML('<div><p>Hello</p></div>');
|
|
63
|
-
|
|
64
|
-
const div = doc.querySelector('div');
|
|
65
|
-
expect(div).toBeTruthy();
|
|
66
|
-
|
|
67
|
-
const p = div?.querySelector('p');
|
|
68
|
-
expect(p).toBeTruthy();
|
|
69
|
-
expect(p?.textContent).toBe('Hello');
|
|
70
|
-
|
|
71
|
-
p?.setAttribute('class', 'greeting');
|
|
72
|
-
expect(p?.getAttribute('class')).toBe('greeting');
|
|
73
|
-
|
|
74
|
-
const span = doc.createElement('span');
|
|
75
|
-
span.setAttribute('id', 'dynamic');
|
|
76
|
-
|
|
77
|
-
div?.appendChild(span);
|
|
78
|
-
|
|
79
|
-
const foundSpan = div?.querySelector('#dynamic');
|
|
80
|
-
expect(foundSpan).toBeTruthy();
|
|
81
|
-
expect(foundSpan?.getAttribute('id')).toBe('dynamic');
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('should handle removeChild correctly', () => {
|
|
85
|
-
const doc = parseHTML('<div><p>First</p><span>Second</span></div>');
|
|
86
|
-
const div = doc.querySelector('div');
|
|
87
|
-
const p = div?.querySelector('p');
|
|
88
|
-
|
|
89
|
-
expect(div?.childNodes.length).toBe(2);
|
|
90
|
-
expect(p?.textContent).toBe('First');
|
|
91
|
-
|
|
92
|
-
if (p) {
|
|
93
|
-
div?.removeChild(p);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
expect(div?.childNodes.length).toBe(1);
|
|
97
|
-
expect(div?.querySelector('p')).toBe(null);
|
|
98
|
-
expect(div?.querySelector('span')).toBeTruthy();
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should demonstrate clean API without helper functions', () => {
|
|
102
|
-
const doc = parseHTML('<html><body><div id="test">Content</div></body></html>');
|
|
103
|
-
|
|
104
|
-
const testDiv = doc.querySelector('#test');
|
|
105
|
-
testDiv?.setAttribute('class', 'active');
|
|
106
|
-
const className = testDiv?.getAttribute('class');
|
|
107
|
-
const bodyDiv = doc.body?.querySelector('#test');
|
|
108
|
-
|
|
109
|
-
expect(testDiv).toBeTruthy();
|
|
110
|
-
expect(className).toBe('active');
|
|
111
|
-
expect(bodyDiv).toBeTruthy();
|
|
112
|
-
expect(testDiv === bodyDiv).toBe(true);
|
|
113
|
-
});
|
|
114
|
-
});
|