mirror of
https://github.com/kamranahmedse/driver.js.git
synced 2026-11-01 05:07:12 +08:00
packages/driver is the library (still published as driver.js, with repository.directory set); playground and docs move to apps/. One root pnpm workspace and lockfile replace the three standalone projects, with turbo orchestrating build/test/lint:package (apps depend on the library build; local + CI caching via .turbo). Apps keep importing the library from source for HMR — the aliases now point at ../../packages/driver/src and each app gains a workspace:* dependency so the task graph knows the edge. The dev-server fs scope widens to the repo root accordingly. Releases run from packages/driver (root `pnpm release` delegates). The changelog still lives in the docs app, so the release scripts reach it via ../../../apps/docs and the after:bump hook stages it explicitly — release-it no longer sits above both directories. The merged workspace settings keep sharp unbuilt on purpose (prebuilt binaries; building from source needs node-gyp and fails) — the docs app had this right and the playground setting was the accident. postcss and postcss-scss were unreferenced devDependencies and are dropped; prettier moves to the root as the only shared tool.
101 lines
3.4 KiB
TypeScript
101 lines
3.4 KiB
TypeScript
import { readFileSync } from "fs";
|
|
import { resolve } from "path";
|
|
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
|
import { createDriver, navButton, SAMPLE_STEPS, useDriverHarness } from "./utils";
|
|
|
|
useDriverHarness();
|
|
|
|
// The footer button styling lives in src/popover.css (shared with the hints
|
|
// entry). jsdom resolves the selectors below through getComputedStyle but does
|
|
// not follow driver.css's @import, so we inject the popover stylesheet directly.
|
|
// The harness only resets <body>, so it survives each test.
|
|
beforeAll(() => {
|
|
const style = document.createElement("style");
|
|
style.textContent = readFileSync(resolve(process.cwd(), "src/popover.css"), "utf8");
|
|
document.head.appendChild(style);
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
function addCustomFooterButton(opts: { keepDefaultStyle: boolean }): {
|
|
button: HTMLButtonElement;
|
|
onClick: ReturnType<typeof vi.fn>;
|
|
} {
|
|
const onClick = vi.fn();
|
|
const button = document.createElement("button");
|
|
button.id = "custom-footer-btn";
|
|
button.innerText = "Custom";
|
|
if (opts.keepDefaultStyle) {
|
|
button.classList.add("driver-popover-footer-btn");
|
|
}
|
|
button.addEventListener("click", onClick);
|
|
|
|
const d = createDriver({
|
|
animate: false,
|
|
steps: SAMPLE_STEPS,
|
|
onPopoverRender: popover => {
|
|
popover.footerButtons.appendChild(button);
|
|
},
|
|
});
|
|
d.drive();
|
|
|
|
return { button, onClick };
|
|
}
|
|
|
|
describe("footer button styling", () => {
|
|
it("styles the built-in navigation buttons through the footer button class", () => {
|
|
const d = createDriver({ animate: false, steps: SAMPLE_STEPS });
|
|
d.drive();
|
|
|
|
const next = navButton("next")!;
|
|
expect(next.classList.contains("driver-popover-footer-btn")).toBe(true);
|
|
expect(navButton("prev")!.classList.contains("driver-popover-footer-btn")).toBe(true);
|
|
|
|
const styles = getComputedStyle(next);
|
|
expect(styles.padding).toBe("3px 7px");
|
|
expect(styles.borderRadius).toBe("3px");
|
|
});
|
|
|
|
it("lets a custom footer button opt out of the default button styling", () => {
|
|
const { button } = addCustomFooterButton({ keepDefaultStyle: false });
|
|
|
|
const styles = getComputedStyle(button);
|
|
expect(styles.padding).not.toBe("3px 7px");
|
|
expect(styles.borderRadius).not.toBe("3px");
|
|
});
|
|
|
|
it("lets a custom footer button opt in to the default button styling", () => {
|
|
const { button } = addCustomFooterButton({ keepDefaultStyle: true });
|
|
|
|
const styles = getComputedStyle(button);
|
|
expect(styles.padding).toBe("3px 7px");
|
|
expect(styles.borderRadius).toBe("3px");
|
|
});
|
|
});
|
|
|
|
describe("custom footer button click handling", () => {
|
|
it("does not swallow clicks on a custom footer button that opted in to the style", () => {
|
|
const { button, onClick } = addCustomFooterButton({ keepDefaultStyle: true });
|
|
|
|
const event = new MouseEvent("click", { bubbles: true, cancelable: true });
|
|
button.dispatchEvent(event);
|
|
|
|
expect(onClick).toHaveBeenCalledTimes(1);
|
|
expect(event.defaultPrevented).toBe(false);
|
|
});
|
|
|
|
it("still intercepts clicks on the built-in navigation buttons", () => {
|
|
const onNextClick = vi.fn();
|
|
const d = createDriver({ animate: false, steps: SAMPLE_STEPS, onNextClick });
|
|
d.drive();
|
|
|
|
const event = new MouseEvent("click", { bubbles: true, cancelable: true });
|
|
navButton("next")!.dispatchEvent(event);
|
|
|
|
expect(onNextClick).toHaveBeenCalledTimes(1);
|
|
expect(event.defaultPrevented).toBe(true);
|
|
});
|
|
});
|