UNPKG

@schukai/monster

Version:

Monster is a simple library for creating fast, robust and lightweight websites.

292 lines (247 loc) 7.51 kB
import * as chai from "chai"; import { chaiDom } from "../../../util/chai-dom.mjs"; import { initJSDOM } from "../../../util/jsdom.mjs"; let expect = chai.expect; chai.use(chaiDom); let PopperButton; describe("PopperButton", function () { before(function (done) { initJSDOM() .then(() => { return import("../../../../source/components/form/popper-button.mjs"); }) .then((m) => { PopperButton = m["PopperButton"]; done(); }) .catch((e) => done(e)); }); afterEach(() => { let mocks = document.getElementById("mocks"); mocks.innerHTML = ""; }); it("should instance of popper-button", function () { expect(document.createElement("monster-popper-button")).is.instanceof( PopperButton, ); }); it("should apply content overflow mode to the rendered content wrapper", function (done) { let mocks = document.getElementById("mocks"); const button = document.createElement("monster-popper-button"); mocks.appendChild(button); setTimeout(() => { try { const content = button.shadowRoot.querySelector('[part="content"]'); expect(content).to.exist; expect(content.getAttribute("data-monster-overflow-mode")).to.equal( "both", ); button.setOption("popper.contentOverflow", "horizontal"); setTimeout(() => { try { expect( content.getAttribute("data-monster-overflow-mode"), ).to.equal("horizontal"); done(); } catch (e) { done(e); } }, 0); } catch (e) { done(e); } }, 0); }); it("should resolve nested overlay content to horizontal overflow by default", function (done) { let mocks = document.getElementById("mocks"); const button = document.createElement("monster-popper-button"); mocks.appendChild(button); setTimeout(() => { try { const content = button.shadowRoot.querySelector('[part="content"]'); expect(content).to.exist; button.setOption( "content", "<div><monster-select></monster-select></div>", ); setTimeout(() => { try { expect( content.getAttribute("data-monster-overflow-mode"), ).to.equal("horizontal"); done(); } catch (e) { done(e); } }, 0); } catch (e) { done(e); } }, 0); }); it("should apply visible content overflow mode to the rendered content wrapper", function (done) { let mocks = document.getElementById("mocks"); const button = document.createElement("monster-popper-button"); mocks.appendChild(button); setTimeout(() => { try { const content = button.shadowRoot.querySelector('[part="content"]'); expect(content).to.exist; button.setOption("popper.contentOverflow", "visible"); setTimeout(() => { try { expect( button.getOption("popper.contentOverflow"), ).to.equal("visible"); expect( content.getAttribute("data-monster-overflow-mode"), ).to.equal("visible"); done(); } catch (e) { done(e); } }, 0); } catch (e) { done(e); } }, 0); }); it("should apply content overflow mode from the HTML attribute", function (done) { let mocks = document.getElementById("mocks"); mocks.innerHTML = ` <monster-popper-button data-monster-option-popper-content-overflow="horizontal" ></monster-popper-button> `; setTimeout(() => { try { const button = mocks.querySelector("monster-popper-button"); const content = button.shadowRoot.querySelector('[part="content"]'); expect(button.getOption("popper.contentOverflow")).to.equal( "horizontal", ); expect(content.getAttribute("data-monster-overflow-mode")).to.equal( "horizontal", ); done(); } catch (e) { done(e); } }, 0); }); it("should apply visible content overflow mode from the HTML attribute", function (done) { let mocks = document.getElementById("mocks"); mocks.innerHTML = ` <monster-popper-button data-monster-option-popper-content-overflow="visible" ></monster-popper-button> `; setTimeout(() => { try { const button = mocks.querySelector("monster-popper-button"); const content = button.shadowRoot.querySelector('[part="content"]'); expect(button.getOption("popper.contentOverflow")).to.equal( "visible", ); expect(content.getAttribute("data-monster-overflow-mode")).to.equal( "visible", ); done(); } catch (e) { done(e); } }, 0); }); it("should use absolute positioning by default", function (done) { let mocks = document.getElementById("mocks"); const button = document.createElement("monster-popper-button"); mocks.appendChild(button); setTimeout(() => { try { button.showDialog(); const popper = button.shadowRoot.querySelector( '[data-monster-role="popper"]', ); expect(popper).to.exist; expect(popper.style.position).to.equal("absolute"); done(); } catch (e) { done(e); } }, 0); }); it("should move the popper through the opening appearance states", async function () { let mocks = document.getElementById("mocks"); const button = document.createElement("monster-popper-button"); mocks.appendChild(button); await waitForTimeout(); button.showDialog(); const popper = button.shadowRoot.querySelector( '[data-monster-role="popper"]', ); expect(popper).to.exist; expect(popper.dataset.monsterAppearance).to.equal("opening"); await waitForCondition(() => { return popper.dataset.monsterAppearance === "open"; }); expect(popper.dataset.monsterAppearance).to.equal("open"); button.hideDialog(); await waitForCondition(() => { return !popper.hasAttribute("data-monster-appearance"); }); expect(popper.hasAttribute("data-monster-appearance")).to.equal(false); }); it("should finish the opening appearance state when requestAnimationFrame stalls", async function () { let mocks = document.getElementById("mocks"); const button = document.createElement("monster-popper-button"); const originalRequestAnimationFrame = globalThis.requestAnimationFrame; const originalCancelAnimationFrame = globalThis.cancelAnimationFrame; try { globalThis.requestAnimationFrame = () => 1; globalThis.cancelAnimationFrame = () => {}; mocks.appendChild(button); await waitForTimeout(); button.showDialog(); const popper = button.shadowRoot.querySelector( '[data-monster-role="popper"]', ); expect(popper).to.exist; expect(popper.dataset.monsterAppearance).to.equal("opening"); await waitForCondition(() => { return popper.dataset.monsterAppearance === "open"; }); expect(popper.dataset.monsterAppearance).to.equal("open"); button.hideDialog(); } finally { globalThis.requestAnimationFrame = originalRequestAnimationFrame; globalThis.cancelAnimationFrame = originalCancelAnimationFrame; } }); }); function waitForTimeout(timeout = 0) { return new Promise((resolve) => setTimeout(resolve, timeout)); } function waitForCondition(check, { timeout = 1000, interval = 10 } = {}) { const deadline = Date.now() + timeout; return new Promise((resolve, reject) => { const tick = () => { let done = false; try { done = check(); } catch (e) { reject(e); return; } if (done) { resolve(); return; } if (Date.now() >= deadline) { reject(new Error("Timed out waiting for condition.")); return; } setTimeout(tick, interval); }; tick(); }); }