@gjsify/dom-elements 0.4.0 → 0.4.3

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 (53) hide show
  1. package/lib/types/location-stub.d.ts +1 -1
  2. package/package.json +78 -75
  3. package/src/attr.ts +0 -61
  4. package/src/character-data.ts +0 -79
  5. package/src/comment.ts +0 -31
  6. package/src/document-fragment.ts +0 -137
  7. package/src/document.ts +0 -103
  8. package/src/dom-matrix.ts +0 -109
  9. package/src/dom-token-list.ts +0 -140
  10. package/src/element.ts +0 -316
  11. package/src/font-face.ts +0 -97
  12. package/src/gst-time.ts +0 -26
  13. package/src/html-canvas-element.ts +0 -90
  14. package/src/html-element.ts +0 -502
  15. package/src/html-image-element.spec.ts +0 -285
  16. package/src/html-image-element.ts +0 -295
  17. package/src/html-media-element.ts +0 -123
  18. package/src/html-video-element.ts +0 -143
  19. package/src/image.ts +0 -31
  20. package/src/index.spec.ts +0 -914
  21. package/src/index.ts +0 -39
  22. package/src/intersection-observer.ts +0 -42
  23. package/src/location-stub.ts +0 -20
  24. package/src/match-media.ts +0 -32
  25. package/src/mutation-observer.ts +0 -39
  26. package/src/named-node-map.ts +0 -159
  27. package/src/namespace-uri.ts +0 -11
  28. package/src/node-list.ts +0 -52
  29. package/src/node-type.ts +0 -14
  30. package/src/node.ts +0 -280
  31. package/src/property-symbol.ts +0 -23
  32. package/src/register/canvas.ts +0 -23
  33. package/src/register/document.ts +0 -64
  34. package/src/register/font-face.ts +0 -18
  35. package/src/register/helpers.ts +0 -15
  36. package/src/register/image.ts +0 -8
  37. package/src/register/location.ts +0 -6
  38. package/src/register/match-media.ts +0 -6
  39. package/src/register/navigator.ts +0 -6
  40. package/src/register/observers.ts +0 -10
  41. package/src/register.spec.ts +0 -136
  42. package/src/register.ts +0 -13
  43. package/src/resize-observer.ts +0 -28
  44. package/src/stubs.spec.ts +0 -284
  45. package/src/test.browser.mts +0 -686
  46. package/src/test.mts +0 -9
  47. package/src/text.ts +0 -67
  48. package/src/types/i-html-image-element.ts +0 -44
  49. package/src/types/image-data.ts +0 -12
  50. package/src/types/index.ts +0 -3
  51. package/src/types/predefined-color-space.ts +0 -1
  52. package/tsconfig.json +0 -37
  53. package/tsconfig.tsbuildinfo +0 -1
@@ -1,686 +0,0 @@
1
- // Browser unit tests for @gjsify/dom-elements APIs.
2
- // Tests native browser globals to validate that the browser behaves the way
3
- // our GJS implementation assumes. Do NOT import @gjsify/* — that would drag in
4
- // @girs/* / gi:// GObject bindings that have no browser equivalent.
5
-
6
- import { run, describe, it, expect } from '@gjsify/unit';
7
-
8
- run({
9
- async DomElementsTest() {
10
-
11
- // -- Node constants --
12
-
13
- await describe('Node constants', async () => {
14
- await it('static constants are correct', async () => {
15
- expect(Node.ELEMENT_NODE).toBe(1);
16
- expect(Node.TEXT_NODE).toBe(3);
17
- expect(Node.COMMENT_NODE).toBe(8);
18
- expect(Node.DOCUMENT_NODE).toBe(9);
19
- expect(Node.DOCUMENT_FRAGMENT_NODE).toBe(11);
20
- });
21
-
22
- await it('instance constants match static', async () => {
23
- const el = document.createElement('div');
24
- expect(el.ELEMENT_NODE).toBe(1);
25
- expect(el.TEXT_NODE).toBe(3);
26
- expect(el.nodeType).toBe(Node.ELEMENT_NODE);
27
- });
28
- });
29
-
30
- // -- Node tree operations --
31
-
32
- await describe('Node tree ops', async () => {
33
- await it('appendChild sets parentNode and childNodes', async () => {
34
- const parent = document.createElement('div');
35
- const child = document.createElement('span');
36
- parent.appendChild(child);
37
- expect(child.parentNode).toBe(parent);
38
- expect(parent.hasChildNodes()).toBe(true);
39
- expect(parent.childNodes.length).toBe(1);
40
- expect(parent.firstChild).toBe(child);
41
- expect(parent.lastChild).toBe(child);
42
- });
43
-
44
- await it('removeChild clears parentNode', async () => {
45
- const parent = document.createElement('div');
46
- const child = document.createElement('span');
47
- parent.appendChild(child);
48
- parent.removeChild(child);
49
- expect(child.parentNode).toBeNull();
50
- expect(parent.hasChildNodes()).toBe(false);
51
- });
52
-
53
- await it('insertBefore inserts at correct position', async () => {
54
- const parent = document.createElement('div');
55
- const a = document.createElement('b');
56
- const b = document.createElement('i');
57
- const c = document.createElement('u');
58
- parent.appendChild(a);
59
- parent.appendChild(c);
60
- parent.insertBefore(b, c);
61
- expect(parent.childNodes.length).toBe(3);
62
- expect(parent.childNodes.item(0)).toBe(a);
63
- expect(parent.childNodes.item(1)).toBe(b);
64
- expect(parent.childNodes.item(2)).toBe(c);
65
- });
66
-
67
- await it('insertBefore with null appends', async () => {
68
- const parent = document.createElement('div');
69
- const child = document.createElement('span');
70
- parent.insertBefore(child, null);
71
- expect(parent.firstChild).toBe(child);
72
- });
73
-
74
- await it('replaceChild swaps nodes', async () => {
75
- const parent = document.createElement('div');
76
- const old = document.createElement('span');
77
- const neo = document.createElement('b');
78
- parent.appendChild(old);
79
- parent.replaceChild(neo, old);
80
- expect(parent.firstChild).toBe(neo);
81
- expect(old.parentNode).toBeNull();
82
- });
83
-
84
- await it('sibling navigation works', async () => {
85
- const parent = document.createElement('div');
86
- const a = document.createElement('b');
87
- const b = document.createElement('i');
88
- const c = document.createElement('u');
89
- parent.appendChild(a);
90
- parent.appendChild(b);
91
- parent.appendChild(c);
92
- expect(a.previousSibling).toBeNull();
93
- expect(a.nextSibling).toBe(b);
94
- expect(b.previousSibling).toBe(a);
95
- expect(b.nextSibling).toBe(c);
96
- expect(c.nextSibling).toBeNull();
97
- });
98
-
99
- await it('contains() checks descendants', async () => {
100
- const parent = document.createElement('div');
101
- const child = document.createElement('span');
102
- const grandchild = document.createElement('b');
103
- parent.appendChild(child);
104
- child.appendChild(grandchild);
105
- expect(parent.contains(child)).toBe(true);
106
- expect(parent.contains(grandchild)).toBe(true);
107
- expect(parent.contains(parent)).toBe(true);
108
- expect(child.contains(parent)).toBe(false);
109
- });
110
-
111
- await it('cloneNode shallow does not copy children', async () => {
112
- const parent = document.createElement('div');
113
- parent.appendChild(document.createElement('span'));
114
- const clone = parent.cloneNode(false);
115
- expect(clone.hasChildNodes()).toBe(false);
116
- });
117
-
118
- await it('cloneNode deep copies children', async () => {
119
- const parent = document.createElement('div');
120
- const child = document.createElement('span');
121
- parent.appendChild(child);
122
- const clone = parent.cloneNode(true);
123
- expect(clone.hasChildNodes()).toBe(true);
124
- expect(clone.firstChild).not.toBe(child);
125
- });
126
-
127
- await it('re-appending a child moves it to new parent', async () => {
128
- const p1 = document.createElement('div');
129
- const p2 = document.createElement('div');
130
- const child = document.createElement('span');
131
- p1.appendChild(child);
132
- p2.appendChild(child);
133
- expect(p1.hasChildNodes()).toBe(false);
134
- expect(p2.firstChild).toBe(child);
135
- expect(child.parentNode).toBe(p2);
136
- });
137
- });
138
-
139
- // -- Element attributes --
140
-
141
- await describe('Element attributes', async () => {
142
- await it('setAttribute / getAttribute / hasAttribute', async () => {
143
- const el = document.createElement('div');
144
- el.setAttribute('id', 'test');
145
- expect(el.getAttribute('id')).toBe('test');
146
- expect(el.hasAttribute('id')).toBe(true);
147
- });
148
-
149
- await it('removeAttribute clears the attr', async () => {
150
- const el = document.createElement('div');
151
- el.setAttribute('class', 'foo');
152
- el.removeAttribute('class');
153
- expect(el.getAttribute('class')).toBeNull();
154
- expect(el.hasAttribute('class')).toBe(false);
155
- });
156
-
157
- await it('id property mirrors attribute', async () => {
158
- const el = document.createElement('div');
159
- el.id = 'myId';
160
- expect(el.id).toBe('myId');
161
- expect(el.getAttribute('id')).toBe('myId');
162
- });
163
-
164
- await it('className property mirrors class attribute', async () => {
165
- const el = document.createElement('div');
166
- el.className = 'foo bar';
167
- expect(el.className).toBe('foo bar');
168
- expect(el.getAttribute('class')).toBe('foo bar');
169
- });
170
-
171
- await it('toggleAttribute adds then removes', async () => {
172
- const el = document.createElement('div');
173
- expect(el.toggleAttribute('hidden')).toBe(true);
174
- expect(el.hasAttribute('hidden')).toBe(true);
175
- expect(el.toggleAttribute('hidden')).toBe(false);
176
- expect(el.hasAttribute('hidden')).toBe(false);
177
- });
178
-
179
- await it('toggleAttribute with force', async () => {
180
- const el = document.createElement('div');
181
- expect(el.toggleAttribute('hidden', true)).toBe(true);
182
- expect(el.hasAttribute('hidden')).toBe(true);
183
- expect(el.toggleAttribute('hidden', false)).toBe(false);
184
- expect(el.hasAttribute('hidden')).toBe(false);
185
- });
186
-
187
- await it('hasAttributes reflects attribute presence', async () => {
188
- const el = document.createElement('div');
189
- expect(el.hasAttributes()).toBe(false);
190
- el.setAttribute('id', 'test');
191
- expect(el.hasAttributes()).toBe(true);
192
- });
193
-
194
- await it('attributes.length reflects count', async () => {
195
- const el = document.createElement('div');
196
- el.setAttribute('id', 'test');
197
- el.setAttribute('class', 'foo');
198
- expect(el.attributes.length).toBe(2);
199
- });
200
-
201
- await it('attributes is iterable', async () => {
202
- const el = document.createElement('div');
203
- el.setAttribute('id', 'test');
204
- el.setAttribute('class', 'foo');
205
- const names: string[] = [];
206
- for (const attr of el.attributes) {
207
- names.push(attr.name);
208
- }
209
- expect(names.length).toBe(2);
210
- expect(names).toContain('id');
211
- expect(names).toContain('class');
212
- });
213
-
214
- await it('element children tracking', async () => {
215
- const parent = document.createElement('div');
216
- const c1 = document.createElement('span');
217
- const c2 = document.createElement('b');
218
- parent.appendChild(c1);
219
- parent.appendChild(c2);
220
- expect(parent.children.length).toBe(2);
221
- expect(parent.childElementCount).toBe(2);
222
- expect(parent.firstElementChild).toBe(c1);
223
- expect(parent.lastElementChild).toBe(c2);
224
- });
225
-
226
- await it('element sibling navigation', async () => {
227
- const parent = document.createElement('div');
228
- const a = document.createElement('span');
229
- const b = document.createElement('b');
230
- parent.appendChild(a);
231
- parent.appendChild(b);
232
- expect(a.nextElementSibling).toBe(b);
233
- expect(b.previousElementSibling).toBe(a);
234
- expect(a.previousElementSibling).toBeNull();
235
- expect(b.nextElementSibling).toBeNull();
236
- });
237
-
238
- await it('event dispatch via addEventListener', async () => {
239
- const el = document.createElement('div');
240
- let fired = false;
241
- el.addEventListener('click', () => { fired = true; });
242
- el.dispatchEvent(new Event('click'));
243
- expect(fired).toBe(true);
244
- });
245
- });
246
-
247
- // -- DOMTokenList (via element.classList) --
248
-
249
- await describe('DOMTokenList (classList)', async () => {
250
- await it('add creates tokens and updates class attribute', async () => {
251
- const el = document.createElement('div');
252
- el.classList.add('foo', 'bar');
253
- expect(el.classList.length).toBe(2);
254
- expect(el.classList.contains('foo')).toBe(true);
255
- expect(el.classList.contains('bar')).toBe(true);
256
- expect(el.getAttribute('class')).toBe('foo bar');
257
- });
258
-
259
- await it('remove removes tokens', async () => {
260
- const el = document.createElement('div');
261
- el.className = 'foo bar baz';
262
- el.classList.remove('bar');
263
- expect(el.classList.contains('bar')).toBe(false);
264
- expect(el.classList.contains('foo')).toBe(true);
265
- expect(el.classList.contains('baz')).toBe(true);
266
- });
267
-
268
- await it('toggle adds/removes', async () => {
269
- const el = document.createElement('div');
270
- const added = el.classList.toggle('active');
271
- expect(added).toBe(true);
272
- expect(el.classList.contains('active')).toBe(true);
273
- const removed = el.classList.toggle('active');
274
- expect(removed).toBe(false);
275
- expect(el.classList.contains('active')).toBe(false);
276
- });
277
-
278
- await it('toggle with force', async () => {
279
- const el = document.createElement('div');
280
- el.classList.toggle('active', true);
281
- expect(el.classList.contains('active')).toBe(true);
282
- el.classList.toggle('active', true);
283
- expect(el.classList.contains('active')).toBe(true);
284
- el.classList.toggle('active', false);
285
- expect(el.classList.contains('active')).toBe(false);
286
- });
287
-
288
- await it('item() by index', async () => {
289
- const el = document.createElement('div');
290
- el.className = 'a b c';
291
- expect(el.classList.item(0)).toBe('a');
292
- expect(el.classList.item(1)).toBe('b');
293
- expect(el.classList.item(2)).toBe('c');
294
- expect(el.classList.item(3)).toBeNull();
295
- });
296
-
297
- await it('value getter', async () => {
298
- const el = document.createElement('div');
299
- el.className = 'foo bar';
300
- expect(el.classList.value).toBe('foo bar');
301
- });
302
-
303
- await it('toString', async () => {
304
- const el = document.createElement('div');
305
- el.className = 'a b';
306
- expect(el.classList.toString()).toBe('a b');
307
- });
308
- });
309
-
310
- // -- HTMLElement properties --
311
-
312
- await describe('HTMLElement properties', async () => {
313
- await it('title', async () => {
314
- const el = document.createElement('div');
315
- expect(el.title).toBe('');
316
- el.title = 'My Title';
317
- expect(el.title).toBe('My Title');
318
- expect(el.getAttribute('title')).toBe('My Title');
319
- });
320
-
321
- await it('lang', async () => {
322
- const el = document.createElement('div');
323
- expect(el.lang).toBe('');
324
- el.lang = 'en';
325
- expect(el.lang).toBe('en');
326
- });
327
-
328
- await it('dir', async () => {
329
- const el = document.createElement('div');
330
- expect(el.dir).toBe('');
331
- el.dir = 'rtl';
332
- expect(el.dir).toBe('rtl');
333
- });
334
-
335
- await it('hidden (boolean attr)', async () => {
336
- const el = document.createElement('div');
337
- expect(el.hidden).toBe(false);
338
- el.hidden = true;
339
- expect(el.hidden).toBe(true);
340
- expect(el.hasAttribute('hidden')).toBe(true);
341
- el.hidden = false;
342
- expect(el.hidden).toBe(false);
343
- expect(el.hasAttribute('hidden')).toBe(false);
344
- });
345
-
346
- await it('tabIndex', async () => {
347
- const el = document.createElement('div');
348
- el.tabIndex = 0;
349
- expect(el.tabIndex).toBe(0);
350
- expect(el.getAttribute('tabindex')).toBe('0');
351
- });
352
-
353
- await it('draggable', async () => {
354
- const el = document.createElement('div');
355
- expect(el.draggable).toBe(false);
356
- el.draggable = true;
357
- expect(el.draggable).toBe(true);
358
- expect(el.getAttribute('draggable')).toBe('true');
359
- });
360
-
361
- await it('contentEditable', async () => {
362
- const el = document.createElement('div');
363
- el.contentEditable = 'true';
364
- expect(el.contentEditable).toBe('true');
365
- expect(el.isContentEditable).toBe(true);
366
- el.contentEditable = 'false';
367
- expect(el.isContentEditable).toBe(false);
368
- });
369
-
370
- await it('layout properties are numbers (zero for detached)', async () => {
371
- const el = document.createElement('div');
372
- expect(typeof el.offsetHeight).toBe('number');
373
- expect(typeof el.offsetWidth).toBe('number');
374
- expect(typeof el.clientHeight).toBe('number');
375
- expect(typeof el.clientWidth).toBe('number');
376
- expect(el.offsetParent).toBeNull();
377
- });
378
-
379
- await it('onclick handler fires on click()', async () => {
380
- const el = document.createElement('div');
381
- let clicked = false;
382
- el.onclick = () => { clicked = true; };
383
- el.click();
384
- expect(clicked).toBe(true);
385
- });
386
-
387
- await it('onload handler fires on dispatchEvent', async () => {
388
- const el = document.createElement('div');
389
- let called = false;
390
- el.onload = () => { called = true; };
391
- el.dispatchEvent(new Event('load'));
392
- expect(called).toBe(true);
393
- });
394
-
395
- await it('onwheel property exists (Excalibur feature-detect)', async () => {
396
- const el = document.createElement('div');
397
- expect('onwheel' in el).toBe(true);
398
- expect(el.onwheel).toBeNull();
399
- });
400
-
401
- await it('both addEventListener and on* handler fire', async () => {
402
- const el = document.createElement('div');
403
- const calls: string[] = [];
404
- el.addEventListener('load', () => { calls.push('listener'); });
405
- el.onload = () => { calls.push('handler'); };
406
- el.dispatchEvent(new Event('load'));
407
- expect(calls.length).toBe(2);
408
- expect(calls).toContain('listener');
409
- expect(calls).toContain('handler');
410
- });
411
-
412
- await it('clearing on* handler stops it from firing', async () => {
413
- const el = document.createElement('div');
414
- let called = false;
415
- el.onload = () => { called = true; };
416
- el.onload = null;
417
- el.dispatchEvent(new Event('load'));
418
- expect(called).toBe(false);
419
- });
420
- });
421
-
422
- // -- Text / Comment / DocumentFragment --
423
-
424
- await describe('Text', async () => {
425
- await it('creates with data and TEXT_NODE type', async () => {
426
- const t = new Text('hello');
427
- expect(t.data).toBe('hello');
428
- expect(t.nodeType).toBe(Node.TEXT_NODE);
429
- expect(t.nodeName).toBe('#text');
430
- });
431
-
432
- await it('empty default', async () => {
433
- const t = new Text();
434
- expect(t.data).toBe('');
435
- });
436
-
437
- await it('splitText splits data', async () => {
438
- const parent = document.createElement('div');
439
- const t = new Text('hello world');
440
- parent.appendChild(t);
441
- const newNode = t.splitText(5);
442
- expect(t.data).toBe('hello');
443
- expect(newNode.data).toBe(' world');
444
- expect(parent.childNodes.length).toBe(2);
445
- });
446
-
447
- await it('wholeText joins adjacent text nodes', async () => {
448
- const parent = document.createElement('div');
449
- const t1 = new Text('hello');
450
- const t2 = new Text(' ');
451
- const t3 = new Text('world');
452
- parent.appendChild(t1);
453
- parent.appendChild(t2);
454
- parent.appendChild(t3);
455
- expect(t2.wholeText).toBe('hello world');
456
- });
457
- });
458
-
459
- await describe('Comment', async () => {
460
- await it('creates with data and COMMENT_NODE type', async () => {
461
- const c = new Comment('a comment');
462
- expect(c.data).toBe('a comment');
463
- expect(c.nodeType).toBe(Node.COMMENT_NODE);
464
- expect(c.nodeName).toBe('#comment');
465
- });
466
-
467
- await it('cloneNode', async () => {
468
- const c = new Comment('test');
469
- const clone = c.cloneNode() as Comment;
470
- expect(clone.data).toBe('test');
471
- expect(clone instanceof Comment).toBe(true);
472
- expect(clone).not.toBe(c);
473
- });
474
- });
475
-
476
- await describe('DocumentFragment', async () => {
477
- await it('has correct nodeType and nodeName', async () => {
478
- const frag = new DocumentFragment();
479
- expect(frag.nodeType).toBe(Node.DOCUMENT_FRAGMENT_NODE);
480
- expect(frag.nodeName).toBe('#document-fragment');
481
- });
482
-
483
- await it('tracks appended children', async () => {
484
- const frag = new DocumentFragment();
485
- const el = document.createElement('div');
486
- frag.appendChild(el);
487
- expect(frag.childNodes.length).toBe(1);
488
- expect(frag.children.length).toBe(1);
489
- expect(frag.firstElementChild).toBe(el);
490
- });
491
-
492
- await it('textContent concatenates text nodes', async () => {
493
- const frag = new DocumentFragment();
494
- frag.appendChild(new Text('hello'));
495
- frag.appendChild(new Text(' world'));
496
- expect(frag.textContent).toBe('hello world');
497
- });
498
- });
499
-
500
- // -- DOMMatrix --
501
-
502
- await describe('DOMMatrix', async () => {
503
- await it('identity by default', async () => {
504
- const m = new DOMMatrix();
505
- expect(m.a).toBe(1);
506
- expect(m.b).toBe(0);
507
- expect(m.c).toBe(0);
508
- expect(m.d).toBe(1);
509
- expect(m.e).toBe(0);
510
- expect(m.f).toBe(0);
511
- expect(m.is2D).toBe(true);
512
- expect(m.isIdentity).toBe(true);
513
- });
514
-
515
- await it('6-element 2D array initializer', async () => {
516
- const m = new DOMMatrix([1, 2, 3, 4, 5, 6]);
517
- expect(m.a).toBe(1);
518
- expect(m.b).toBe(2);
519
- expect(m.c).toBe(3);
520
- expect(m.d).toBe(4);
521
- expect(m.e).toBe(5);
522
- expect(m.f).toBe(6);
523
- expect(m.is2D).toBe(true);
524
- expect(m.m11).toBe(1);
525
- expect(m.m41).toBe(5);
526
- expect(m.m42).toBe(6);
527
- });
528
-
529
- await it('16-element 3D array sets is2D=false', async () => {
530
- const m = new DOMMatrix([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]);
531
- expect(m.m11).toBe(1);
532
- expect(m.m44).toBe(16);
533
- expect(m.is2D).toBe(false);
534
- });
535
-
536
- await it('isIdentity false for non-identity', async () => {
537
- const m = new DOMMatrix([2, 0, 0, 2, 0, 0]);
538
- expect(m.isIdentity).toBe(false);
539
- });
540
-
541
- await it('multiply: identity is neutral', async () => {
542
- const a = new DOMMatrix([2, 0, 0, 3, 10, 20]);
543
- const i = new DOMMatrix();
544
- const r = a.multiply(i);
545
- expect(r.a).toBe(2);
546
- expect(r.d).toBe(3);
547
- expect(r.e).toBe(10);
548
- expect(r.f).toBe(20);
549
- });
550
-
551
- await it('multiply: two scales compose', async () => {
552
- const a = new DOMMatrix([2, 0, 0, 3, 0, 0]);
553
- const b = new DOMMatrix([4, 0, 0, 5, 0, 0]);
554
- const r = a.multiply(b);
555
- expect(r.a).toBe(8);
556
- expect(r.d).toBe(15);
557
- });
558
-
559
- await it('multiply does not mutate receiver', async () => {
560
- const a = new DOMMatrix([2, 0, 0, 2, 0, 0]);
561
- const b = new DOMMatrix([3, 0, 0, 3, 0, 0]);
562
- a.multiply(b);
563
- expect(a.a).toBe(2);
564
- });
565
-
566
- await it('inverse of identity is identity', async () => {
567
- const m = new DOMMatrix().inverse();
568
- expect(m.a).toBe(1);
569
- expect(m.d).toBe(1);
570
- expect(m.e).toBe(0);
571
- expect(m.f).toBe(0);
572
- });
573
-
574
- await it('inverse of scale(2,2) is scale(0.5, 0.5)', async () => {
575
- const m = new DOMMatrix([2, 0, 0, 2, 0, 0]).inverse();
576
- expect(m.a).toBe(0.5);
577
- expect(m.d).toBe(0.5);
578
- });
579
-
580
- await it('inverse of translate(10,20) is translate(-10,-20)', async () => {
581
- const m = new DOMMatrix([1, 0, 0, 1, 10, 20]).inverse();
582
- expect(m.e).toBe(-10);
583
- expect(m.f).toBe(-20);
584
- });
585
-
586
- await it('translate helper', async () => {
587
- const m = new DOMMatrix().translate(5, 7);
588
- expect(m.e).toBe(5);
589
- expect(m.f).toBe(7);
590
- });
591
-
592
- await it('scale helper', async () => {
593
- const m = new DOMMatrix().scale(3, 4);
594
- expect(m.a).toBe(3);
595
- expect(m.d).toBe(4);
596
- });
597
- });
598
-
599
- // -- CSSStyleDeclaration (via element.style) --
600
-
601
- await describe('CSSStyleDeclaration (element.style)', async () => {
602
- await it('setProperty / getPropertyValue', async () => {
603
- const el = document.createElement('div');
604
- el.style.setProperty('--ex-pixel-ratio', '2');
605
- expect(el.style.getPropertyValue('--ex-pixel-ratio')).toBe('2');
606
- });
607
-
608
- await it('removeProperty returns and clears value', async () => {
609
- const el = document.createElement('div');
610
- el.style.setProperty('--test', 'hello');
611
- const removed = el.style.removeProperty('--test');
612
- expect(removed).toBe('hello');
613
- expect(el.style.getPropertyValue('--test')).toBe('');
614
- });
615
-
616
- await it('getPropertyValue returns empty for unknown', async () => {
617
- const el = document.createElement('div');
618
- expect(el.style.getPropertyValue('nonexistent')).toBe('');
619
- });
620
-
621
- await it('getPropertyPriority is empty without !important', async () => {
622
- const el = document.createElement('div');
623
- el.style.setProperty('color', 'red');
624
- expect(el.style.getPropertyPriority('color')).toBe('');
625
- });
626
-
627
- await it('cssText setter parses declarations', async () => {
628
- const el = document.createElement('div');
629
- el.style.cssText = 'background-color:rgba(135,100,100,.5)';
630
- const bg = el.style.getPropertyValue('background-color');
631
- expect(typeof bg).toBe('string');
632
- expect(bg.length).toBeGreaterThan(0);
633
- });
634
- });
635
-
636
- // -- FontFace --
637
-
638
- await describe('FontFace', async () => {
639
- await it('constructor sets family and status', async () => {
640
- const face = new FontFace('TestFont', 'url(nonexistent.ttf)');
641
- expect(face.family).toBe('TestFont');
642
- expect(face.status).toBe('unloaded');
643
- });
644
-
645
- await it('load() returns a Promise', async () => {
646
- const face = new FontFace('TestFont2', 'url(nonexistent.ttf)');
647
- const p = face.load();
648
- expect(p instanceof Promise).toBe(true);
649
- p.catch(() => {});
650
- });
651
- });
652
-
653
- // -- FontFaceSet (document.fonts) --
654
-
655
- await describe('document.fonts (FontFaceSet)', async () => {
656
- await it('add/has/size track added faces', async () => {
657
- const face = new FontFace('BrowserTestFont', 'url(nonexistent.ttf)');
658
- const before = document.fonts.size;
659
- document.fonts.add(face);
660
- expect(document.fonts.has(face)).toBe(true);
661
- expect(document.fonts.size).toBe(before + 1);
662
- document.fonts.delete(face);
663
- expect(document.fonts.has(face)).toBe(false);
664
- });
665
-
666
- await it('ready is a Promise', async () => {
667
- expect(document.fonts.ready instanceof Promise).toBe(true);
668
- });
669
- });
670
-
671
- // -- window.matchMedia --
672
-
673
- await describe('window.matchMedia', async () => {
674
- await it('returns MediaQueryList with media string', async () => {
675
- const mq = window.matchMedia('(min-width: 800px)');
676
- expect(mq.media).toBe('(min-width: 800px)');
677
- expect(typeof mq.matches).toBe('boolean');
678
- });
679
-
680
- await it('addEventListener is available on MediaQueryList', async () => {
681
- const mq = window.matchMedia('(min-width: 100px)');
682
- expect(typeof mq.addEventListener).toBe('function');
683
- });
684
- });
685
- },
686
- });