import { createElementFromAttrs, createElementFromHTML, queryElemChildren, querySingleVisibleElem, protectMorphElements, recoverMorphElements, toggleElem, morphElementWithProtection, } from './dom.ts'; test('createElementFromHTML', () => { expect(createElementFromHTML('foobar').outerHTML).toEqual('foobar'); expect(createElementFromHTML('foo').outerHTML).toEqual('foo'); expect(createElementFromHTML('foo').outerHTML).toEqual('foo'); expect(createElementFromHTML('').outerHTML).toEqual(''); }); test('createElementFromAttrs', () => { const el = createElementFromAttrs('button', { id: 'the-id', class: 'cls-1 cls-2', disabled: true, checked: false, required: null, tabindex: 0, 'data-foo': 'the-data', }, 'txt', createElementFromHTML('inner')); expect(el.outerHTML).toEqual(''); }); test('querySingleVisibleElem', () => { const el = document.createElement('div'); document.body.append(el); // layout, and thus visibility, is only computed in the document expect(querySingleVisibleElem(el, 'span')).toBeNull(); el.innerHTML = 'foo'; expect(querySingleVisibleElem(el, 'span')!.textContent).toEqual('foo'); el.innerHTML = 'foobar'; expect(querySingleVisibleElem(el, 'span')!.textContent).toEqual('bar'); el.innerHTML = 'foobar'; expect(querySingleVisibleElem(el, 'span')!.textContent).toEqual('bar'); el.innerHTML = 'foobar'; expect(() => querySingleVisibleElem(el, 'span')).toThrow('Expected exactly one visible element'); }); test('queryElemChildren', () => { const el = createElementFromHTML('
ab
'); const children = queryElemChildren(el, '.a'); expect(children.length).toEqual(1); }); test('toggleElem', () => { const el = createElementFromHTML('
a
b
'); toggleElem(el.children); expect(el.outerHTML).toEqual('
a
b
'); toggleElem(el.children, false); expect(el.outerHTML).toEqual('
a
b
'); toggleElem(el.children, true); expect(el.outerHTML).toEqual('
a
b
'); }); test('protectMorphElements', () => { const el = createElementFromHTML('
foo
'); const protectedElems = protectMorphElements(el); const span = el.querySelector('span')!; const spanMorphProtectId = span.getAttribute('data-morph-protect'); expect(spanMorphProtectId).toBeTruthy(); expect(el.outerHTML).toEqual(`
foo
`); span.textContent = 'bar'; span.classList.add('new-class'); expect(el.outerHTML).toEqual(`
bar
`); recoverMorphElements(el, protectedElems); expect(el.outerHTML).toEqual('
foo
'); }); describe('morphElementWithProtection', () => { const newElHtml = '
new
'; it('morph normal', () => { const el = createElementFromHTML('
old
'); const newEl = createElementFromHTML(newElHtml); morphElementWithProtection(el, newEl, {morphStyle: 'outerHTML'}); // span is changed, but dropdown is skipped because it is active expect(el.outerHTML).toEqual('
new
'); }); it('morph whole', () => { const el = createElementFromHTML('
old
'); const newEl = createElementFromHTML(newElHtml); morphElementWithProtection(el, newEl, {morphStyle: 'outerHTML'}); // span is not changed, because the parent div is marked as data-morph-whole and there is an active dropdown, so it is skipped expect(el.outerHTML).toEqual('
old
'); }); it('morph protection', () => { const el = createElementFromHTML('
'); const newEl = createElementFromHTML('
new
'); const elSpanOld = el.querySelector('span'); const elDropdownOld = el.querySelector('.ui.dropdown'); const morphedEl = morphElementWithProtection(el, newEl, {morphStyle: 'outerHTML'}); expect(el.outerHTML).toEqual('
new
'); const elSpanNew = morphedEl.querySelector('span'); const elDropdownNew = morphedEl.querySelector('.ui.dropdown'); expect(elSpanNew).toBe(elSpanOld); // span is morphed in place, so it is the same element expect(elDropdownNew).not.toBe(elDropdownOld); // dropdown is protected and fully replaced, so it is a new element }); });