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": [ ``, `checkbox-checked`, ``, ``, `` ].join(''), "/assets/icons/checkbox.svg": [ ``, `checkbox`, ``, `` ].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} */ 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 (
{this.svgElement}
); } } let initialVSpec = 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([ ``, ``, ].join('')); await new Promise((resolve,reject)=>setTimeout(()=>resolve(),10)); await nextAnimationFrame(); expect( rendered.shadowRoot.innerHTML ).toBe([ ``, `
`, svgs["/assets/icons/checkbox.svg"], `
` ].join('')); let updatedVSpec = ; render(updatedVSpec, {host: rendered, old: initialVSpec}); await new Promise((resolve,reject)=>setTimeout(()=>resolve(),10)); await nextAnimationFrame(); expect( rendered.shadowRoot.innerHTML ).toBe([ ``, `
`, svgs["/assets/icons/checkbox-checked.svg"], `
` ].join('')); document.body.removeChild(container); }); });