Landscape images (imported video frames, slide pages) would lose most of the picture in a 3:4 crop, so the tile keeps its monogram; portrait and near-square images (w/h <= 1.05) fade in over it, cropped from the centre. The header nav follows the mockup's segmented-control style: muted text, no underline, the current area raised in accent. Co-Authored-By: Claude Opus 5.5 <[email protected]>
32 lines
1.5 KiB
TypeScript
32 lines
1.5 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { renderToString } from "react-dom/server";
|
|
import { CourseCover, ProgressBar, SegmentedToggle } from "../src";
|
|
|
|
test("ProgressBar exposes aria-valuenow as a percentage", () => {
|
|
const html = renderToString(<ProgressBar value={0.4} label="Course progress" />);
|
|
expect(html).toContain('role="progressbar"');
|
|
expect(html).toContain('aria-valuenow="40"');
|
|
});
|
|
|
|
test("CourseCover without an image shows a two-letter monogram", () => {
|
|
expect(renderToString(<CourseCover title="Pure Snake" />)).toContain(">PS<");
|
|
expect(renderToString(<CourseCover title="Docker" />)).toContain(">DO<");
|
|
});
|
|
|
|
test("SegmentedToggle marks the active option", () => {
|
|
const html = renderToString(<SegmentedToggle label="Look" value="b" onChange={() => {}} options={[{ value: "a", label: "A" }, { value: "b", label: "B" }]} />);
|
|
expect(html).toMatch(/aria-pressed="true"[^>]*>B</);
|
|
});
|
|
|
|
test("CourseCover keeps the monogram under an image, shown only if the image suits a 3:4 tile", async () => {
|
|
const { coverFits } = await import("../src");
|
|
const html = renderToString(<CourseCover title="Mastering Docker" image="/api/courses/x/cover" />);
|
|
expect(html).toContain(">MD<");
|
|
expect(html).toContain('src="/api/courses/x/cover"');
|
|
expect(html).not.toContain("data-shown"); // hidden until loaded and measured
|
|
expect(coverFits(600, 800)).toBe(true); // portrait
|
|
expect(coverFits(500, 500)).toBe(true); // square
|
|
expect(coverFits(640, 360)).toBe(false); // a 16:9 video frame keeps the monogram
|
|
expect(coverFits(0, 0)).toBe(false);
|
|
});
|