@schukai/monster
Version:
Monster is a simple library for creating fast, robust and lightweight websites.
292 lines (247 loc) • 7.51 kB
JavaScript
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();
});
}