Files
driver.js/packages/driver/tests/overlay.test.ts
Kamran Ahmed 75edd1b4bc Restructure as a Turborepo monorepo
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.
2026-07-16 19:45:23 +01:00

83 lines
3.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from "vitest";
import { createDriver, nextFrame, SAMPLE_STEPS, useDriverHarness } from "./utils";
useDriverHarness();
// The overlay SVG is mounted inside the rAF loop, so every assertion waits a
// frame before reading the rendered path.
const overlayPath = () => document.querySelector<SVGPathElement>(".driver-overlay path");
describe("overlay configuration", () => {
it("paints the overlay with the configured colour", async () => {
const d = createDriver({ animate: false, overlayColor: "rgb(255, 0, 0)", steps: SAMPLE_STEPS });
d.drive();
await nextFrame();
expect(overlayPath()?.style.fill).toBe("rgb(255, 0, 0)");
});
it("falls back to the default black overlay colour", async () => {
const d = createDriver({ animate: false, steps: SAMPLE_STEPS });
d.drive();
await nextFrame();
// jsdom normalises the "#000" default to rgb form.
expect(overlayPath()?.style.fill).toBe("rgb(0, 0, 0)");
});
it("applies the configured overlay opacity", async () => {
const d = createDriver({ animate: false, overlayOpacity: 0.4, steps: SAMPLE_STEPS });
d.drive();
await nextFrame();
expect(overlayPath()?.style.opacity).toBe("0.4");
});
it("rounds the cutout corners by the configured stage radius", async () => {
const d = createDriver({ animate: false, stageRadius: 8, steps: SAMPLE_STEPS });
d.drive();
await nextFrame();
// The rounded-corner arcs in the path use the normalised radius.
expect(overlayPath()?.getAttribute("d")).toContain("a8,8");
});
it("insets the cutout by the configured stage padding", async () => {
// Element box is 0×0 in jsdom, so with padding 20 and the default radius 5
// the cutout's leading corner sits at (-20 + 5, -20) = (-15, -20).
const d = createDriver({ animate: false, stagePadding: 20, steps: SAMPLE_STEPS });
d.drive();
await nextFrame();
expect(overlayPath()?.getAttribute("d")).toContain("M-15,-20");
});
it("falls back to a solid black fill when overlayColor is empty", async () => {
const d = createDriver({ animate: false, overlayColor: "", steps: SAMPLE_STEPS });
d.drive();
await nextFrame();
expect(overlayPath()?.style.fill).toBe("rgb(0, 0, 0)");
});
it("draws square corners with no inset when padding and radius are zero", async () => {
const d = createDriver({ animate: false, stagePadding: 0, stageRadius: 0, steps: SAMPLE_STEPS });
d.drive();
await nextFrame();
// Zero radius removes the rounded-corner arcs and the cutout starts at the origin.
expect(overlayPath()?.getAttribute("d")).toContain("M0,0");
expect(overlayPath()?.getAttribute("d")).not.toContain("a5,5");
});
it("does not close the tour when the backdrop outside the cutout path is clicked", async () => {
const d = createDriver({ animate: false, steps: SAMPLE_STEPS });
d.drive();
await nextFrame();
document.querySelector(".driver-overlay")?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
expect(d.isActive()).toBe(true);
});
});