Something went wrong on our end
Select Git revision
customelement.mjs
-
Volker Schukai authoredVolker Schukai authored
customelement.mjs 20.61 KiB
'use strict';
import * as chai from 'chai';
import {internalSymbol} from "../../../source/constants.mjs";
import {getDocument} from "../../../source/dom/util.mjs";
import {ProxyObserver} from "../../../source/types/proxyobserver.mjs";
import {chaiDom} from "../../util/chai-dom.mjs";
import {initJSDOM} from "../../util/jsdom.mjs";
let expect = chai.expect;
chai.use(chaiDom);
let html1 = `
<div id="test1">
</div>
`;
let html2 = `
<input data-monster-bind="path:a" id="test2" data-monster-attributes="value path:a">
`;
// defined in constants.mjs
const updaterSymbolKey = "@schukai/monster/dom/custom-element@@options-updater-link"
const updaterSymbolSymbol = Symbol.for(updaterSymbolKey);
describe('DOM', function () {
let CustomElement, registerCustomElement, TestComponent, document, TestComponent2, assignUpdaterToElement,
addObjectWithUpdaterToElement;
describe("assignUpdaterToElement", function () {
before(function (done) {
const options = {};
initJSDOM(options).then(() => {
import("../../../source/dom/updater.mjs").then((yy) => {
addObjectWithUpdaterToElement = yy['addObjectWithUpdaterToElement'];
import("../../../source/dom/customelement.mjs").then((m) => {
try {
CustomElement = m['CustomElement'];
assignUpdaterToElement = function (elements, object) {
return addObjectWithUpdaterToElement.call(this, elements, updaterSymbolSymbol, object);
}
document = getDocument();
done()
} catch (e) {
done(e);
}
}).catch((e) => {
done(e);
});
}).catch((e) => {
done(e);
});
});
})
beforeEach(() => {
let mocks = document.getElementById('mocks');
mocks.innerHTML = html2;
})
afterEach(() => {
let mocks = document.getElementById('mocks');
mocks.innerHTML = "";
})
/**
* this test try to simulate the bug that was found in the assignUpdaterToElement function.
* The bug was that the updater was not assigned to the element when the element was created.
*
* unfortunately, this test does not reproduce the bug.
*/
it("should assign an updater to an element", function (done) {
let element = document.getElementById('test2');
expect(document.getElementById("mocks").innerHTML).to.equal(html2);
const a = {a: 1};
const b = {b: 2};
const ap = new ProxyObserver(a);
const bp = new ProxyObserver(b);
const x = ap.getSubject()
const y = bp.getSubject()
const set = new Set();
set.add(element);
assignUpdaterToElement.call(element, set, ap);
assignUpdaterToElement.call(element, set, bp);
expect(JSON.stringify(x)).to.equal('{"a":1}');
expect(JSON.stringify(y)).to.equal('{"b":2}');
const sy = updaterSymbolSymbol;
let v = element.getAttribute("data-monster-objectlink");
expect(v).to.equal('Symbol(' + updaterSymbolKey + ')');
const updater = element[sy];
for (const v of updater) {
for (const u of v) {
u.run().then(() => {
u.enableEventProcessing();
});
}
}
expect(updater).to.be.an.instanceof(Set);
expect(updater).to.be.a("Set");
x.a = 3;
bp.getSubject().b = 4;
setTimeout(() => {
let mockHTML = document.getElementById("mocks");
// html expexted:
// <input data-monster-bind="path:a" id="test2" data-monster-attributes="value path:a" data-monster-objectlink="Symbol(@schukai/monster/dom/@@object-updater-link)" value="3">
expect(mockHTML.querySelector("#test2")).to.have.value('3')
expect(mockHTML.querySelector("#test2")).to.have.attribute('data-monster-objectlink', 'Symbol(' + updaterSymbolKey + ')')
//expect(mockHTML).to.have.html(resultHTML);
expect(element.value).to.equal("3");
expect(JSON.stringify(ap.getRealSubject())).to.equal('{"a":3}');
expect(JSON.stringify(bp.getRealSubject())).to.equal('{"b":4}');
done()
}, 50)
})
})
describe('CustomElement()', function () {
before(function (done) {
initJSDOM({}).then(() => {
import("../../../source/dom/customelement.mjs").then((m) => {
try {
CustomElement = m['CustomElement'];
registerCustomElement = m['registerCustomElement'];
TestComponent = class extends CustomElement {
static getTag() {
return "monster-testclass"
}
}
registerCustomElement(TestComponent)
TestComponent2 = class extends CustomElement {
static getTag() {
return "monster-testclass2"
}
/**
*
* @return {Object}
*/
get defaults() {
return Object.assign({}, super.defaults, {
demotest: undefined,
templates: {
main: '<h1></h1><article><p>test</p><div id="container"></div></article>'
},
})
}
}
registerCustomElement(TestComponent2)
document = getDocument();
done()
} catch (e) {
done(e);
}
});
});
})
beforeEach(() => {
let mocks = document.getElementById('mocks');
mocks.innerHTML = html1;
})
afterEach(() => {
let mocks = document.getElementById('mocks');
mocks.innerHTML = "";
})
describe('CustomElement() with Config', function () {
it('should read config from tag', function () {
let mocks = document.getElementById('mocks');
mocks.innerHTML = `
<script id="config1" type="application/json">
{
"demotest":1425
}
</script>
<monster-testclass2 id="thisisatest" data-monster-options-selector="#config1">
</monster-testclass2>
`;
let monster = document.getElementById('thisisatest');
expect(monster.getOption('demotest')).is.eql(1425);
});
});
describe('create', function () {
it('should return custom-element object', function () {
let d = new TestComponent();
expect(typeof d).is.equal('object');
});
});
describe('connect empty element', function () {
it('document should contain monster-testclass', function () {
let d = document.createElement('monster-testclass');
document.getElementById('test1').appendChild(d);
expect(document.getElementsByTagName('monster-testclass').length).is.equal(1);
// no data-monster-objectlink="Symbol(monsterUpdater)" because it has nothing to update
// but data-monster-error="Error: html is not set."
expect(document.getElementById('test1')).contain.html('<monster-testclass data-monster-error="html is not set."></monster-testclass>');
});
});
describe('connect element with html', function () {
it('document should contain monster-testclass2', function (done) {
let d = document.createElement('monster-testclass2');
document.getElementById('test1').appendChild(d);
// insert DOM run in extra process via setTimeout!
setTimeout(function () {
try {
expect(document.getElementsByTagName('monster-testclass2').length).is.equal(1);
expect(document.getElementsByTagName('monster-testclass2').item(0).shadowRoot.innerHTML).is.equal('<h1></h1><article><p>test</p><div id="container"></div></article>');
expect(document.getElementById('test1')).contain.html('<monster-testclass2 data-monster-objectlink="Symbol(' + updaterSymbolKey + ')"></monster-testclass2>');
return done();
} catch (e) {
done(e);
}
}, 10);
});
});
describe('Options change', function () {
it('delegatesFocus should change from true to false', function () {
let element = document.createElement('monster-testclass')
const o = element[internalSymbol].realSubject;
expect(Object.is(element[internalSymbol].realSubject, o)).to.be.true;
expect(element[internalSymbol].realSubject.options.delegatesFocus).to.be.true;
expect(element[internalSymbol].subject.options.delegatesFocus).to.be.true;
expect(element.getOption('delegatesFocus')).to.be.true;
expect(Object.is(element[internalSymbol].realSubject, o)).to.be.true;
// element.setAttribute(ATTRIBUTE_OPTIONS, JSON.stringify({delegatesFocus: false}));
// expect(Object.is(element[internalSymbol].realSubject, o)).to.be.true;
//
// expect(element.getOption('delegatesFocus')).to.be.false;
// expect(element[internalSymbol].realSubject.options.delegatesFocus).to.be.false;
// expect(Object.is(element[internalSymbol].realSubject, o)).to.be.true;
})
})
describe('setOptions()', function () {
[
['shadowMode', 'x1'],
['templates.main', 'x2'], // is explicitly set to undefined
['delegatesFocus', 'x4'],
].forEach(function (data) {
let key = data.shift()
let newValue = data.shift()
let text = key + ' should return ' + newValue;
if (newValue !== undefined) {
text = key + ' was not set, therefore default ' + newValue;
}
it(text, function () {
let d = document.createElement('monster-testclass');
expect(d.getOption(key)).to.be.not.equal(newValue);
let x = d.setOption(key, newValue);
expect(d.getOption(key)).to.be.equal(newValue);
})
})
});
describe('getOptions()', function () {
[
['shadowMode', 'open'],
['templates.main', undefined], // is explicitly set to undefined
['delegatesFocus', true],
['x.y.z', true, true], // x.y.z isnt set, defaultValue is used
['x', true, true] // x isnt set, defaultValue is used
].forEach(function (data) {
let key = data.shift()
let value = data.shift()
let defaultValue = data.shift()
let text = key + ' should return ' + value;
if (defaultValue !== undefined) {
text = key + ' was not set, therefore default ' + defaultValue;
}
it(text, function () {
let d = document.createElement('monster-testclass');
let x = d.getOption(key, defaultValue);
expect(x).to.be.equal(value);
})
})
})
/**
* @link https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/113
*/
describe('Assign CSSStyle as Array with wrong type', function () {
const htmlTAG = 'monster-testclass-x1';
let mocks, TestComponentX1;
beforeEach(() => {
mocks = document.getElementById('mocks');
mocks.innerHTML = html1;
TestComponentX1 = class extends CustomElement {
static getTag() {
return htmlTAG
}
static getCSSStyleSheet() {
return [true];
}
/**
* @return {Object}
*/
get defaults() {
return Object.assign({}, super.defaults, {
templates: {
main: '<h1>test</h1>'
},
})
}
}
registerCustomElement(TestComponentX1)
})
it(htmlTAG + " should throw Exception", function (done) {
let d = document.createElement(htmlTAG);
let div = document.getElementById('test1');
div.append(d);
expect(div).contain.html('data-monster-error="value is not an instance of CSSStyleSheet"');
done();
})
})
/**
* @link https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/113
*/
describe('Assign CSSStyle as Array and CSSStylesheet', function () {
const htmlTAG = 'monster-testclass-x113-2';
let mocks, TestComponentX113X2;
beforeEach(() => {
mocks = document.getElementById('mocks');
mocks.innerHTML = html1;
TestComponentX113X2 = class extends CustomElement {
static getTag() {
return htmlTAG
}
/**
* @return {Object}
*/
get defaults() {
return Object.assign({}, super.defaults, {
templates: {main: '<h1>test</h1>'},
})
}
static getCSSStyleSheet() {
const s = (new CSSStyleSheet())
s.insertRule('a { color : red}');
return [s];
}
}
registerCustomElement(TestComponentX113X2)
})
it(htmlTAG + " should throw Exception 2", function (done) {
let d = document.createElement(htmlTAG);
let div = document.getElementById('test1');
div.append(d);
expect(d.shadowRoot.innerHTML).is.eq('<h1>test</h1>');
done();
})
})
/**
* @link https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/113
*/
describe('Assign CSSStyle as Array and CSS as string', function () {
const htmlTAG = 'monster-testclass-x113-21';
let mocks, TestComponentX113X22;
beforeEach(() => {
mocks = document.getElementById('mocks');
mocks.innerHTML = html1;
TestComponentX113X22 = class extends CustomElement {
static getTag() {
return htmlTAG
}
/**
* @return {Object}
*/
get defaults() {
return Object.assign({}, super.defaults, {
templates: {main: '<h1>test</h1>'},
})
}
static getCSSStyleSheet() {
return 'a { color:red }';
}
}
registerCustomElement(TestComponentX113X22)
})
it(htmlTAG + " should eq <style>a { color:red }</style><h1>test</h1>", function (done) {
let d = document.createElement(htmlTAG);
let div = document.getElementById('test1');
div.append(d);
expect(d.shadowRoot.innerHTML).is.eq('<style>a { color:red }</style><h1>test</h1>');
done();
})
})
/**
* @link https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/113
*/
describe('Assign CSSStyle as Array and CSS as string', function () {
const htmlTAG = 'monster-testclass-x113-22';
let mocks, TestComponentX113X223;
beforeEach(() => {
mocks = document.getElementById('mocks');
mocks.innerHTML = html1;
TestComponentX113X223 = class extends CustomElement {
static getTag() {
return htmlTAG
}
/**
* @return {Object}
*/
get defaults() {
return Object.assign({}, super.defaults, {
templates: {main: '<h1>test</h1>'},
})
}
static getCSSStyleSheet() {
return ['a { color:red }'];
}
}
registerCustomElement(TestComponentX113X223)
})
it(htmlTAG + " should eq <style>a { color:red }</style><h1>test</h1>", function (done) {
let d = document.createElement(htmlTAG);
let div = document.getElementById('test1');
div.append(d);
expect(d.shadowRoot.innerHTML).is.eq('<style>a { color:red }</style><h1>test</h1>');
done();
})
})
describe('hasNode()', function () {
let mocks;
beforeEach(() => {
mocks = document.getElementById('mocks');
mocks.innerHTML = html1;
})
it("hasNode monster-testclass should return ...", function () {
let d = document.createElement('monster-testclass');
let p1 = document.createElement('p');
let t1 = document.createTextNode('test1');
p1.appendChild(t1);
let p = document.createElement('div');
let t = document.createTextNode('test');
p.appendChild(p1);
p.appendChild(t);
d.appendChild(p);
let div = document.getElementById('test1');
div.append(d);
let n1 = document.createElement('p');
expect(d.hasNode(n1)).to.be.false;
expect(d.hasNode(t)).to.be.true;
expect(d.hasNode(p)).to.be.true;
expect(d.hasNode(p1)).to.be.true;
expect(d.hasNode(t1)).to.be.true;
})
it("hasNode monster-testclass2 should return ...", function () {
let d = document.createElement('monster-testclass2');
let p1 = document.createElement('p');
let t1 = document.createTextNode('test1');
p1.appendChild(t1);
let p = document.createElement('div');
let t = document.createTextNode('test');
p.appendChild(p1);
p.appendChild(t);
let div = document.getElementById('test1');
div.append(d);
let a = d.shadowRoot.getElementById('container');
d.shadowRoot.getElementById('container').appendChild(p);
let n1 = document.createElement('p');
expect(d.hasNode(n1)).to.be.false;
expect(d.hasNode(t)).to.be.true;
expect(d.hasNode(p)).to.be.true;
expect(d.hasNode(p1)).to.be.true;
expect(d.hasNode(t1)).to.be.true;
})
})
});
})