89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { step } from "../src/lib/grid";
|
|
import type { Rect } from "../src/lib/grid";
|
|
|
|
/** Three cards per row, 100 wide and 40 tall, the way the tray wraps them. */
|
|
function tray(count: number): { id: number; rect: Rect }[] {
|
|
return Array.from({ length: count }, (_, index) => ({
|
|
id: index,
|
|
rect: {
|
|
left: (index % 3) * 100,
|
|
top: Math.floor(index / 3) * 40,
|
|
width: 96,
|
|
height: 36,
|
|
},
|
|
}));
|
|
}
|
|
|
|
const rectOf = (item: { rect: Rect }): Rect => item.rect;
|
|
const walk = (
|
|
items: ReturnType<typeof tray>,
|
|
from: number,
|
|
direction: Parameters<typeof step>[2],
|
|
): number | null => step(items, items[from], direction, rectOf)?.id ?? null;
|
|
|
|
describe("step", () => {
|
|
it("moves along a row", () => {
|
|
const items = tray(6);
|
|
expect(walk(items, 0, "right")).toBe(1);
|
|
expect(walk(items, 1, "left")).toBe(0);
|
|
});
|
|
|
|
it("moves down a column, not just to the next card", () => {
|
|
const items = tray(6);
|
|
expect(walk(items, 1, "down")).toBe(4);
|
|
expect(walk(items, 4, "up")).toBe(1);
|
|
});
|
|
|
|
it("keeps the column when the last row is short", () => {
|
|
const items = tray(5);
|
|
expect(walk(items, 1, "down")).toBe(4);
|
|
expect(walk(items, 2, "down")).toBe(4);
|
|
});
|
|
|
|
it("carries on to the next row at the end of one", () => {
|
|
const items = tray(6);
|
|
expect(walk(items, 2, "right")).toBe(3);
|
|
expect(walk(items, 3, "left")).toBe(2);
|
|
});
|
|
|
|
it("stops at the top and the bottom", () => {
|
|
const items = tray(6);
|
|
expect(walk(items, 1, "up")).toBeNull();
|
|
expect(walk(items, 4, "down")).toBeNull();
|
|
});
|
|
|
|
it("stops at the very ends of the run", () => {
|
|
const items = tray(6);
|
|
expect(walk(items, 0, "left")).toBeNull();
|
|
expect(walk(items, 5, "right")).toBeNull();
|
|
});
|
|
|
|
it("falls back to the first card when the cursor is off the run", () => {
|
|
const items = tray(3);
|
|
const stray = { id: 99, rect: { left: 0, top: 0, width: 1, height: 1 } };
|
|
expect(step(items, stray, "right", rectOf)?.id).toBe(0);
|
|
});
|
|
|
|
it("reads a row by the band each card fills, not by its centre", () => {
|
|
// Top-aligned cards of different heights still sit on one row.
|
|
const items = [
|
|
{ id: 0, rect: { left: 0, top: 0, width: 96, height: 67 } },
|
|
{ id: 1, rect: { left: 100, top: 0, width: 96, height: 67 } },
|
|
{ id: 2, rect: { left: 200, top: 0, width: 96, height: 51 } },
|
|
{ id: 3, rect: { left: 0, top: 73, width: 96, height: 51 } },
|
|
];
|
|
expect(step(items, items[0], "up", rectOf)).toBeNull();
|
|
expect(step(items, items[0], "right", rectOf)?.id).toBe(1);
|
|
expect(step(items, items[2], "left", rectOf)?.id).toBe(1);
|
|
expect(step(items, items[0], "down", rectOf)?.id).toBe(3);
|
|
expect(step(items, items[3], "up", rectOf)?.id).toBe(0);
|
|
});
|
|
|
|
it("handles a single card without moving", () => {
|
|
const items = tray(1);
|
|
expect(walk(items, 0, "right")).toBeNull();
|
|
expect(walk(items, 0, "down")).toBeNull();
|
|
});
|
|
});
|