// Generated, do not edit. sha256:23dd50a7ad5448e3230fa33ba9e025d2fdfec896be66303dade6c4b550502fa8 import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { installDom, parseSelector } from '../helpers/mini-dom.mjs'; const dom = installDom(); const html = s => { const el = dom.host(); el.innerHTML = s; return el; }; describe('mini-dom: parsing and serialising', () => { it('builds elements, text and attributes, and decodes what esc() writes', () => { const el = html('
x < y
'); const d = el.querySelector('div'); assert.equal(d.getAttribute('data-x'), '1 & 2'); assert.equal(d.title, `"q" 's'`); assert.equal(d.textContent, 'x < y'); assert.equal(el.innerHTML, '
x < y
'); }); it('knows void elements, self-closing svg and a raw textarea', () => { const el = html('na'); assert.equal(el.children.length, 4); assert.equal(el.querySelector('svg').children[0].localName, 'line'); assert.equal(el.querySelector('textarea').value, 'a & c'); assert.equal(el.querySelector('span').textContent, 'na'); }); it('a > inside a quoted attribute does not end the tag', () => { const el = html(''); assert.equal(el.querySelector('button').title, 'a > b'); assert.equal(el.querySelector('button').textContent, 'x'); }); it('a stray closing tag is ignored, and replacing innerHTML detaches the old nodes', () => { const el = html('

ab

'); assert.equal(el.querySelector('p').textContent, 'ab'); const p = el.querySelector('p'); el.innerHTML = 'new'; assert.equal(p.isConnected, false); assert.equal(el.querySelector('i').isConnected, true); }); }); describe('mini-dom: selectors', () => { const el = html(`
1
drawer
`); it('tag, id, class, attribute with and without value, and :not', () => { assert.equal(el.querySelectorAll('tr').length, 3); assert.equal(el.querySelectorAll('tr[data-row-id]').length, 2); assert.equal(el.querySelector('tr[data-row-id="2"]').dataset.rowId, '2'); assert.equal(el.querySelector('tr.row-expansion[data-exp-id="1"] td').textContent, 'drawer'); assert.equal(el.querySelectorAll('.table-wrap.has-exp').length, 1); const free = el.querySelectorAll('input:not([disabled]):not([type="hidden"]), select:not([disabled])'); assert.deepEqual(free.map(i => i.dataset.field), ['c']); }); it('descendant and child combinators are not the same', () => { assert.equal(el.querySelectorAll('tbody td').length, 3); assert.equal(el.querySelectorAll('table > td').length, 0); assert.equal(el.querySelectorAll('tr > td').length, 3); }); it('closest walks up and includes the element itself; matches tests one element', () => { const td = el.querySelector('tr[data-row-id="1"] td'); assert.equal(td.closest('tr[data-row-id]').dataset.rowId, '1'); assert.equal(td.closest('td'), td); assert.equal(td.closest('[data-save]'), null); assert.equal(td.matches('.num'), true); }); it('a selector it does not understand throws instead of matching nothing', () => { assert.throws(() => parseSelector('tr:first-child'), /unsupported/); assert.throws(() => parseSelector('a ~ b'), /unsupported/); assert.throws(() => parseSelector('[x'), /unclosed/); }); }); describe('mini-dom: form state', () => { it('a select reads the selected option, then what was set', () => { const el = html(''); const [s1, s2] = el.querySelectorAll('select'); assert.equal(s1.value, 'b'); assert.equal(s2.value, 'x'); s1.value = 'a'; assert.equal(s1.value, 'a'); }); it('an input reads its attribute until a value is set; a checkbox its checked', () => { const el = html(''); const [t, c1, c2] = el.querySelectorAll('input'); assert.equal(t.value, '1'); t.value = '2'; assert.equal(t.value, '2'); assert.equal(t.getAttribute('value'), '1'); assert.equal(c1.checked, true); assert.equal(c2.checked, false); assert.equal(c1.type, 'checkbox'); assert.equal(t.type, 'text'); }); it('there is a head for scripts, and getComputedStyle reads the inline style', () => { assert.equal(dom.document.head.parentNode, dom.document.documentElement); dom.document.documentElement.style.setProperty('--accent', '#ff6b00'); assert.equal(getComputedStyle(dom.document.documentElement).getPropertyValue('--accent'), '#ff6b00'); }); it('focus moves activeElement, and contains sees it', () => { const el = html(''); el.querySelector('input').focus(); assert.equal(dom.document.activeElement, el.querySelector('input')); assert.equal(el.contains(dom.document.activeElement), true); }); }); describe('mini-dom: events', () => { it('bubbles through on-properties and listeners, and stopPropagation stops it', () => { const el = html('
'); const log = []; el.querySelector('#outer').onclick = () => log.push('outer'); el.querySelector('#inner').addEventListener('click', e => { log.push('inner'); e.stopPropagation(); }); dom.click(el.querySelector('button')); assert.deepEqual(log, ['inner']); }); it('a capture listener on the document runs first, and target is the clicked element', () => { const el = html('x'); const log = []; const cap = e => log.push(['doc', e.target.localName]); dom.document.addEventListener('click', cap, true); el.onclick = () => log.push(['host']); dom.click(el.querySelector('span')); dom.document.removeEventListener('click', cap, true); assert.deepEqual(log, [['doc', 'span'], ['host']]); }); it('dispatchEvent with a platform Event works, and keydown carries key and modifiers', () => { const el = html(''); let got = null; el.oninput = e => { got = e.type; }; el.querySelector('input').dispatchEvent(new Event('input', { bubbles: true })); assert.equal(got, 'input'); let k = null; el.onkeydown = e => { k = [e.key, e.ctrlKey]; e.preventDefault(); }; assert.equal(dom.key(el.querySelector('input'), 'Enter', { ctrlKey: true }), false); assert.deepEqual(k, ['Enter', true]); }); it('the document dispatches too, and a CustomEvent keeps its detail', () => { let got = null; const fn = e => { got = e.detail; }; dom.document.addEventListener('blur-changed', fn); dom.document.dispatchEvent(new CustomEvent('blur-changed', { detail: { on: true } })); dom.document.removeEventListener('blur-changed', fn); assert.deepEqual(got, { on: true }); }); it('append adds several children in order', () => { const el = html(''); el.append(dom.document.createElement('b'), dom.document.createElement('i')); assert.deepEqual(el.children.map(c => c.localName), ['b', 'i']); }); it('animation frames wait until they are flushed', () => { let ran = false; requestAnimationFrame(() => { ran = true; }); assert.equal(ran, false); dom.flushFrames(); assert.equal(ran, true); }); });