@joist/element
Version:
Intelligently apply styles to WebComponents
195 lines (149 loc) • 4.38 kB
text/typescript
import { assert, expect } from "chai";
import { attr } from "./attr.js";
import { element } from "./element.js";
import { css, html } from "./tags.js";
it("should write default value to attribute", async () => {
({
tagName: "element-1",
})
class MyElement extends HTMLElement {
()
accessor value1 = "hello"; // no attribute
()
accessor value2 = 0; // number
()
accessor value3 = true; // boolean
({ reflect: false })
accessor value4 = "foo";
}
const el = new MyElement();
document.body.append(el);
expect(el.getAttribute("value1")).to.equal("hello");
expect(el.getAttribute("value2")).to.equal("0");
expect(el.getAttribute("value3")).to.equal("");
expect(el.getAttribute("value4")).to.equal(null);
el.remove();
});
it("should register attributes", async () => {
const observedAttrs: string[] = [];
({
tagName: "element-2",
})
class MyElement extends HTMLElement {
()
accessor value1 = "hello";
()
accessor value2 = 0;
()
accessor value3 = true;
({ observed: false })
accessor value4 = "hello world";
attributeChangedCallback(name: string) {
observedAttrs.push(name);
}
}
const el = new MyElement();
el.setAttribute("value1", "foo");
el.setAttribute("value2", "1");
el.setAttribute("value3", "false");
el.setAttribute("value4", "bar");
expect(observedAttrs).to.deep.equal(["value1", "value2", "value3"]);
});
it("should attach shadow root when the shadow property exists", async () => {
({
tagName: "element-3",
shadowDom: [],
})
class MyElement extends HTMLElement {}
const el = new MyElement();
expect(el.shadowRoot).to.be.instanceOf(ShadowRoot);
});
it("should apply html and css", async () => {
({
tagName: "element-4",
shadowDom: [
css`
:host {
display: contents;
}
`,
html`<slot></slot>`,
{
apply(el) {
const div = document.createElement("div");
div.innerHTML = "hello world";
el.append(div);
},
},
],
})
class MyElement extends HTMLElement {}
const el = new MyElement();
expect(el.shadowRoot?.adoptedStyleSheets.length).to.equal(1);
expect(el.shadowRoot?.innerHTML).to.equal("<slot></slot>");
expect(el.innerHTML).to.equal("<div>hello world</div>");
});
it("should the correct shadow dom mode", async () => {
({
tagName: "element-5",
shadowDom: [],
shadowDomOpts: {
mode: "closed",
},
})
class MyElement extends HTMLElement {}
const el = new MyElement();
assert.equal(el.shadowRoot, null);
});
it("should wait to register itself until all elements it depends on are also registered", async () => {
({
tagName: "element-6",
dependsOn: ["element-7", "element-8"],
})
// @ts-ignore
class MyElement6 extends HTMLElement {}
assert.isUndefined(customElements.get("element-6"));
customElements.define("element-7", class extends HTMLElement {});
customElements.define("element-8", class extends HTMLElement {});
await Promise.all([
customElements.whenDefined("element-7"),
customElements.whenDefined("element-8"),
]);
assert.equal(customElements.get("element-6"), MyElement6);
});
it("should wait to register itself until the custom dependsOn function runs", async () => {
let resolver: Function;
({
tagName: "element-9",
dependsOn() {
return new Promise((resolve) => {
resolver = resolve;
});
},
})
// @ts-ignore
class MyElement extends HTMLElement {}
assert.isUndefined(customElements.get("element-9"));
resolver!();
await Promise.resolve();
assert.equal(customElements.get("element-9"), MyElement);
});
it("should call disconnectedCallback when element is removed from DOM", async () => {
let disconnectedCalled = false;
({
tagName: "element-10",
})
class MyElement extends HTMLElement {
disconnectedCallback() {
disconnectedCalled = true;
}
}
const el = new MyElement();
document.body.append(el);
// Verify element is connected
expect(disconnectedCalled).to.be.false;
// Remove element from DOM
el.remove();
// Verify disconnectedCallback was called
expect(disconnectedCalled).to.be.true;
});