159 lines
9.9 KiB
JavaScript
159 lines
9.9 KiB
JavaScript
import { render, CustomElement, Host, ShadowDOM, defineElement, state, prop } from "@cerxes/csx";
|
|
import { testContainer } from "../utils/test-container";
|
|
import { nextAnimationFrame } from "../utils/next-animation-frame";
|
|
|
|
|
|
const svgs = {
|
|
"/assets/icons/checkbox-checked.svg": [
|
|
`<svg fill="currentcolor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">`,
|
|
`<title>checkbox-checked</title>`,
|
|
`<g><path d="M401.7,411.8c-38,0-76.1,0-114.1,0c-55.6,0-111.2,0-166.8,0c-6.3,0-12.6,0-19,0c-1.1,0-2.3,0-3.4,0 c-0.5,0-1.1,0-1.5,0c-4.5,0.1,4.2,1.3,0,0c-0.9-0.3-2.2-0.8-3.2-0.9c-2.3-0.2,4,2.4,0.6,0.2c-0.2-0.1-3.4-1.9-3.3-2 c0.1-0.2,3.5,3.2,0.1-0.2c-0.6-0.6-1.2-1.2-1.7-1.9c1.8,2.4,2.1,2.7,0.8,0.9c-0.1-0.2-2-3.3-1.9-3.4c0.7-0.4,1.2,4.6,0.4,0.5 c-0.1-0.3-0.9-3.2-0.8-3.2c0.1,0.9,0.2,1.8,0.4,2.6c-0.1-0.9-0.1-1.8-0.1-2.7c0-0.2,0-0.5,0-0.7c0-1.5,0-3.1,0-4.6 c0-7.2,0-14.5,0-21.7c0-56.3,0-112.6,0-168.9c0-25.9,0-51.9,0-77.8c0-7.6,0-15.3,0-22.9c0-1.8,0-3.6,0-5.4c0-0.4,0-0.7,0-1.1 c0-0.5,0-1.1,0-1.5c0-3.3,0.5,1.4-0.3,1.3c0,0,1.1-5.2,1.4-5.1c0.1,0-2.2,4.2,0.2,0.1c2.4-4.1,0,0-0.2-0.2 c-0.1-0.1,2.5-2.6,2.7-2.8c2.9-3.1-3.7,2,0,0c0.7-0.4,1.5-0.9,2.2-1.3c3.6-2.3-4.2,1,0,0c0.3-0.1,3.8-1.1,3.9-1 c-3.1,0.4-3.5,0.4-1.3,0.3c0.5,0,0.9,0,1.4,0c0.9,0,1.8,0,2.6,0c5.9,0,11.8,0,17.7,0c24,0,48,0,72,0c58.1,0,116.3,0,174.4,0 c12.2,0,24.4-0.2,36.6,0c0.5,0,1.2,0,1.4,0c4.5-0.1-4.2-1.3,0,0c0.3,0.1,3.8,0.9,3.8,1.1c0,0.1-4.2-2.2-0.1,0.2 c4.1,2.4,0,0,0.2-0.2c0.1-0.1,2.1,2,2.3,2.2c3.5,3.1-1.2-2.7,0.5,0.5c0.1,0.2,2,3.3,1.9,3.4c-0.3,0.1-1.5-4.5-0.2,0.1 c0.1,0.4,0.2,0.9,0.3,1.3c0.4,2.2,0.4,1.7-0.1-1.3c0.1,0,0.1,2.7,0.1,2.7c0,0.2,0,0.5,0,0.7c0,4.5,0,9.1,0,13.7 c0,53.1,0,106.2,0,159.2c0,42.9,0.2,85.8,0,128.7c0,0.3,0,0.7,0,1c0,0.5,0,1.1,0,1.5c0.1,4.5,1.3-4.2,0,0 c-0.1,0.3-0.9,3.8-1.1,3.8c-0.1,0,2.2-4.2-0.2-0.1c-0.2,0.3-1.3,2.2-1.4,2.2c-0.2-0.1,3.2-3.5-0.2-0.1c-3.3,3.3,0,0,0.1,0.2 c0.1,0.2-3.1,1.9-3.3,2c-3.6,2.3,4.2-1,0,0c-0.3,0.1-3.8,1.1-3.9,1c0.9-0.1,1.8-0.2,2.6-0.4C403.5,411.7,402.6,411.8,401.7,411.8 c-10.5,0.2-20.5,9-20,20c0.5,10.6,8.8,20.3,20,20c27.8-0.6,49.6-22.6,50.1-50.3c0.1-4.1,0-8.3,0-12.4c0-22.3,0-44.6,0-67 c0-60,0-120.1,0-180.1c0-14.4,0.2-28.8,0-43.2c-0.3-23.1-16.1-44.8-39.4-49.4c-6.3-1.3-12.3-1.2-18.7-1.2 c-51.3,0-102.5,0-153.8,0c-46.5,0-93,0-139.5,0c-17.6,0-33,7.3-43.3,21.6c-7,9.7-9,21.1-9,32.8c0,18.3,0,36.6,0,54.8 c0,60.9,0,121.8,0,182.8c0,18.8,0,37.6,0,56.5c0,10.2,1.3,20,6.2,29.2c8.9,16.8,27,25.9,45.6,25.9c45.4,0.1,90.7,0,136.1,0 c52.2,0,104.4,0,156.7,0c3,0,6,0,9,0c10.5,0,20.5-9.2,20-20C421.2,420.9,412.9,411.8,401.7,411.8z"></path></g>`,
|
|
`<g><path d="M136.9,276.6c20,18,40,36,60.1,54.1c8.1,7.3,20.2,7.8,28.3,0c15.6-15,31.1-30,46.7-45.1 c24.7-23.8,49.4-47.7,74.1-71.5c5.7-5.5,11.4-11,17.2-16.6c7.5-7.3,7.9-21.1,0-28.3c-8.1-7.4-20.2-7.8-28.3,0 c-15.6,15-31.1,30-46.7,45.1c-24.7,23.8-49.4,47.7-74.1,71.5c-5.7,5.5-11.4,11-17.2,16.6c9.4,0,18.9,0,28.3,0 c-20-18-40-36-60.1-54.1c-7.8-7-20.7-8.2-28.3,0C129.9,256,128.6,269.2,136.9,276.6L136.9,276.6z"></path></g>`,
|
|
`</svg>`
|
|
].join(''),
|
|
"/assets/icons/checkbox.svg": [
|
|
`<svg fill="currentcolor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">`,
|
|
`<title>checkbox</title>`,
|
|
`<g><path d="M401.7,411.8c-38,0-76.1,0-114.1,0c-55.6,0-111.2,0-166.8,0c-6.3,0-12.6,0-19,0c-1.1,0-2.3,0-3.4,0 c-0.5,0-1.1,0-1.5,0c-4.5,0.1,4.2,1.3,0,0c-0.9-0.3-2.2-0.8-3.2-0.9c-2.3-0.2,4,2.4,0.6,0.2c-0.2-0.1-3.4-1.9-3.3-2 c0.1-0.2,3.5,3.2,0.1-0.2c-0.6-0.6-1.2-1.2-1.7-1.9c1.8,2.4,2.1,2.7,0.8,0.9c-0.1-0.2-2-3.3-1.9-3.4c0.7-0.4,1.2,4.6,0.4,0.5 c-0.1-0.3-0.9-3.2-0.8-3.2c0.1,0.9,0.2,1.8,0.4,2.6c-0.1-0.9-0.1-1.8-0.1-2.7c0-0.2,0-0.5,0-0.7c0-1.5,0-3.1,0-4.6 c0-7.2,0-14.5,0-21.7c0-56.3,0-112.6,0-168.9c0-25.9,0-51.9,0-77.8c0-7.6,0-15.3,0-22.9c0-1.8,0-3.6,0-5.4c0-0.4,0-0.7,0-1.1 c0-0.5,0-1.1,0-1.5c0-3.3,0.5,1.4-0.3,1.3c0,0,1.1-5.2,1.4-5.1c0.1,0-2.2,4.2,0.2,0.1c2.4-4.1,0,0-0.2-0.2 c-0.1-0.1,2.5-2.6,2.7-2.8c2.9-3.1-3.7,2,0,0c0.7-0.4,1.5-0.9,2.2-1.3c3.6-2.3-4.2,1,0,0c0.3-0.1,3.8-1.1,3.9-1 c-3.1,0.4-3.5,0.4-1.3,0.3c0.5,0,0.9,0,1.4,0c0.9,0,1.8,0,2.6,0c5.9,0,11.8,0,17.7,0c24,0,48,0,72,0c58.1,0,116.3,0,174.4,0 c12.2,0,24.4-0.2,36.6,0c0.5,0,1.2,0,1.4,0c4.5-0.1-4.2-1.3,0,0c0.3,0.1,3.8,0.9,3.8,1.1c0,0.1-4.2-2.2-0.1,0.2 c4.1,2.4,0,0,0.2-0.2c0.1-0.1,2.1,2,2.3,2.2c3.5,3.1-1.2-2.7,0.5,0.5c0.1,0.2,2,3.3,1.9,3.4c-0.3,0.1-1.5-4.5-0.2,0.1 c0.1,0.4,0.2,0.9,0.3,1.3c0.4,2.2,0.4,1.7-0.1-1.3c0.1,0,0.1,2.7,0.1,2.7c0,0.2,0,0.5,0,0.7c0,4.5,0,9.1,0,13.7 c0,53.1,0,106.2,0,159.2c0,42.9,0.2,85.8,0,128.7c0,0.3,0,0.7,0,1c0,0.5,0,1.1,0,1.5c0.1,4.5,1.3-4.2,0,0 c-0.1,0.3-0.9,3.8-1.1,3.8c-0.1,0,2.2-4.2-0.2-0.1c-0.2,0.3-1.3,2.2-1.4,2.2c-0.2-0.1,3.2-3.5-0.2-0.1c-3.3,3.3,0,0,0.1,0.2 c0.1,0.2-3.1,1.9-3.3,2c-3.6,2.3,4.2-1,0,0c-0.3,0.1-3.8,1.1-3.9,1c0.9-0.1,1.8-0.2,2.6-0.4C403.5,411.7,402.6,411.8,401.7,411.8 c-10.5,0.2-20.5,9-20,20c0.5,10.6,8.8,20.3,20,20c27.8-0.6,49.6-22.6,50.1-50.3c0.1-4.1,0-8.3,0-12.4c0-22.3,0-44.6,0-67 c0-60,0-120.1,0-180.1c0-14.4,0.2-28.8,0-43.2c-0.3-23.1-16.1-44.8-39.4-49.4c-6.3-1.3-12.3-1.2-18.7-1.2c-51.3,0-102.5,0-153.8,0 c-46.5,0-93,0-139.5,0c-17.6,0-33,7.3-43.3,21.6c-7,9.7-9,21.1-9,32.8c0,18.3,0,36.6,0,54.8c0,60.9,0,121.8,0,182.8 c0,18.8,0,37.6,0,56.5c0,10.2,1.3,20,6.2,29.2c8.9,16.8,27,25.9,45.6,25.9c45.4,0.1,90.7,0,136.1,0c52.2,0,104.4,0,156.7,0 c3,0,6,0,9,0c10.5,0,20.5-9.2,20-20C421.2,420.9,412.9,411.8,401.7,411.8z"></path></g>`,
|
|
`</svg>`
|
|
].join('')
|
|
};
|
|
|
|
const iconStyle = `:host { display: inline-block; }`;// The rest is left out
|
|
|
|
|
|
describe("SVG Component tests", () => {
|
|
/**
|
|
* Assert that a basic component renders as expected
|
|
*/
|
|
test("Simple example-component", async () => {
|
|
|
|
let svgCache = new Map();
|
|
async function fetchSvg(svgUrl){
|
|
// Fake timer
|
|
await new Promise((resolve,reject)=>setTimeout(()=>resolve(), 1));
|
|
let svg = svgs[svgUrl];
|
|
if(svg){
|
|
return {
|
|
text: ()=>svg
|
|
}
|
|
}else{
|
|
throw new Error("Not found");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} svgUrl
|
|
* @returns {Promise<Element>}
|
|
*/
|
|
async function loadSvg(svgUrl) {
|
|
const response = await fetchSvg(svgUrl);
|
|
const svgResource = await response.text();
|
|
const parser = new DOMParser();
|
|
const svgDocument = parser.parseFromString(svgResource, "image/svg+xml");
|
|
let svgElement = svgDocument.firstElementChild;
|
|
if (svgElement.hasAttribute("fill")) {
|
|
svgElement.setAttribute("fill", "currentcolor")
|
|
}
|
|
svgCache.set(svgUrl, svgElement);
|
|
return svgElement;
|
|
}
|
|
|
|
@defineElement("test-icon")
|
|
class Icon extends CustomElement {
|
|
// Again JEST fucks this up in that these magically become read-only (probably not using our CSX-version of babel!)
|
|
@state()
|
|
set svgElement(value){ this.#svgElement = value};
|
|
get svgElement(){ return this.#svgElement};
|
|
#svgElement;
|
|
|
|
|
|
/**
|
|
* @param {string} icon
|
|
*/
|
|
@prop() set icon(icon) {
|
|
if(icon !== this.#icon) {
|
|
this.#icon = icon;
|
|
|
|
this.updateIcon();
|
|
}
|
|
};
|
|
get icon(){
|
|
return this.#icon;
|
|
}
|
|
#icon;
|
|
|
|
updateIcon(){
|
|
let icon = this.#icon;
|
|
const svgUrl = `/assets/icons/${icon}.svg`;
|
|
let cached = svgCache.get(svgUrl);
|
|
if(cached){
|
|
// Use from cache (without passing by async functions, to optimize rendering loop!)
|
|
this.svgElement = cached.cloneNode(true);
|
|
}else{
|
|
loadSvg(svgUrl).then(svgEl=> {
|
|
if(icon===this.#icon) {
|
|
// If this is still the desired icon, load it
|
|
this.svgElement = svgEl.cloneNode(true);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<Host>
|
|
<ShadowDOM>
|
|
<style>{iconStyle}</style>
|
|
<div className="icon">
|
|
{this.svgElement}
|
|
</div>
|
|
</ShadowDOM>
|
|
</Host>
|
|
);
|
|
}
|
|
}
|
|
|
|
let initialVSpec = <Icon icon={'checkbox'}/>
|
|
let rendered = render(initialVSpec);
|
|
let container = testContainer(rendered);
|
|
|
|
document.body.appendChild(container);// Components need to be added to the DOM or their connectecCallback will not be called
|
|
|
|
expect(
|
|
container.innerHTML
|
|
).toBe([
|
|
`<test-icon>`,
|
|
`</test-icon>`,
|
|
].join(''));
|
|
|
|
await new Promise((resolve,reject)=>setTimeout(()=>resolve(),10));
|
|
await nextAnimationFrame();
|
|
|
|
expect(
|
|
rendered.shadowRoot.innerHTML
|
|
).toBe([
|
|
`<style>${iconStyle}</style>`,
|
|
`<div class="icon">`,
|
|
svgs["/assets/icons/checkbox.svg"],
|
|
`</div>`
|
|
].join(''));
|
|
|
|
let updatedVSpec = <Icon icon={'checkbox-checked'}/>;
|
|
render(updatedVSpec, {host: rendered, old: initialVSpec});
|
|
|
|
await new Promise((resolve,reject)=>setTimeout(()=>resolve(),10));
|
|
await nextAnimationFrame();
|
|
|
|
expect(
|
|
rendered.shadowRoot.innerHTML
|
|
).toBe([
|
|
`<style>${iconStyle}</style>`,
|
|
`<div class="icon">`,
|
|
svgs["/assets/icons/checkbox-checked.svg"],
|
|
`</div>`
|
|
].join(''));
|
|
|
|
document.body.removeChild(container);
|
|
});
|
|
}); |