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('txtinner ');
});
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 = 'foo bar ';
expect(querySingleVisibleElem(el, 'span')!.textContent).toEqual('bar');
el.innerHTML = 'foo bar ';
expect(querySingleVisibleElem(el, 'span')!.textContent).toEqual('bar');
el.innerHTML = 'foo bar ';
expect(() => querySingleVisibleElem(el, 'span')).toThrow('Expected exactly one visible element');
});
test('queryElemChildren', () => {
const el = createElementFromHTML('a b
');
const children = queryElemChildren(el, '.a');
expect(children.length).toEqual(1);
});
test('toggleElem', () => {
const el = createElementFromHTML('');
toggleElem(el.children);
expect(el.outerHTML).toEqual('');
toggleElem(el.children, false);
expect(el.outerHTML).toEqual('');
toggleElem(el.children, true);
expect(el.outerHTML).toEqual('');
});
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 = '';
it('morph normal', () => {
const el = createElementFromHTML('');
const newEl = createElementFromHTML(newElHtml);
morphElementWithProtection(el, newEl, {morphStyle: 'outerHTML'});
// span is changed, but dropdown is skipped because it is active
expect(el.outerHTML).toEqual('');
});
it('morph whole', () => {
const el = createElementFromHTML('');
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('');
});
it('morph protection', () => {
const el = createElementFromHTML('');
const newEl = createElementFromHTML('');
const elSpanOld = el.querySelector('span');
const elDropdownOld = el.querySelector('.ui.dropdown');
const morphedEl = morphElementWithProtection(el, newEl, {morphStyle: 'outerHTML'});
expect(el.outerHTML).toEqual('');
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
});
});