mirror of
https://github.com/Since-3/Kuma.git
synced 2026-10-12 21:41:17 +00:00
added floor plan to rooms
This commit is contained in:
parent
9fa335ea40
commit
a8db32bf24
33 changed files with 2695 additions and 61 deletions
154
tests/courses/course-spots.test.ts
Normal file
154
tests/courses/course-spots.test.ts
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import {
|
||||
assignSpot,
|
||||
getCourseSpots,
|
||||
holdSpot,
|
||||
spotHolderKey,
|
||||
} from "@/src/modules/courses/lib/course-spots";
|
||||
import type { FloorPlanItem } from "@/src/modules/rooms/lib/floor-plan";
|
||||
|
||||
const db = {
|
||||
room: { findUnique: vi.fn() },
|
||||
courseBooking: { findMany: vi.fn(), findFirst: vi.fn() },
|
||||
courseSpotHold: { findMany: vi.fn(), deleteMany: vi.fn(), create: vi.fn() },
|
||||
};
|
||||
|
||||
const spot = (id: string, label: string): FloorPlanItem => ({
|
||||
id,
|
||||
type: "reformer",
|
||||
x: 1,
|
||||
y: 1.5,
|
||||
rotation: 0,
|
||||
label,
|
||||
});
|
||||
const spots = [spot("s1", "1"), spot("s2", "2"), spot("s3", "3")];
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
db.courseBooking.findMany.mockResolvedValue([]);
|
||||
db.courseBooking.findFirst.mockResolvedValue(null);
|
||||
db.courseSpotHold.findMany.mockResolvedValue([]);
|
||||
db.courseSpotHold.deleteMany.mockResolvedValue({ count: 0 });
|
||||
db.courseSpotHold.create.mockResolvedValue({ id: "hold-1" });
|
||||
});
|
||||
|
||||
describe("getCourseSpots", () => {
|
||||
it("liest den Raum gar nicht erst, wenn der Kurs keine Platzwahl hat", async () => {
|
||||
expect(await getCourseSpots(db as never, { spotBooking: false, room: "room-1" })).toBeNull();
|
||||
expect(db.room.findUnique).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("behandelt einen Raum ohne Geräte wie einen Kurs ohne Platzwahl", async () => {
|
||||
db.room.findUnique.mockResolvedValue({ floorPlan: null });
|
||||
expect(await getCourseSpots(db as never, { spotBooking: true, room: "room-1" })).toBeNull();
|
||||
});
|
||||
|
||||
it("liefert die buchbaren Geräte des Raums", async () => {
|
||||
db.room.findUnique.mockResolvedValue({
|
||||
floorPlan: { width: 8, depth: 6, items: [spot("s2", "2"), spot("s1", "1")] },
|
||||
});
|
||||
const result = await getCourseSpots(db as never, { spotBooking: true, room: "room-1" });
|
||||
expect(result?.map((s) => s.id)).toEqual(["s1", "s2"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("assignSpot", () => {
|
||||
it("gibt den Wunschplatz, wenn er frei ist", async () => {
|
||||
const result = await assignSpot(db as never, {
|
||||
courseId: "c1",
|
||||
spots,
|
||||
requestedSpotId: "s2",
|
||||
holdId: "hold-1",
|
||||
});
|
||||
expect(result).toEqual({ spotId: "s2", spotLabel: "Reformer 2", changed: false });
|
||||
});
|
||||
|
||||
it("weicht auf einen freien Platz aus, den niemand gerade im Checkout hält", async () => {
|
||||
db.courseBooking.findMany.mockResolvedValue([{ spotId: "s1" }]);
|
||||
db.courseSpotHold.findMany.mockResolvedValue([{ spotId: "s2" }]);
|
||||
|
||||
const result = await assignSpot(db as never, {
|
||||
courseId: "c1",
|
||||
spots,
|
||||
requestedSpotId: "s1",
|
||||
holdId: "hold-1",
|
||||
});
|
||||
|
||||
expect(result).toEqual({ spotId: "s3", spotLabel: "Reformer 3", changed: true });
|
||||
// Der eigene Hold zählt nicht als "von jemand anderem gehalten".
|
||||
expect(db.courseSpotHold.findMany.mock.calls[0][0].where.id).toEqual({ not: "hold-1" });
|
||||
});
|
||||
|
||||
it("nimmt notfalls einen gehaltenen Platz - bezahlt schlägt Checkout", async () => {
|
||||
db.courseBooking.findMany.mockResolvedValue([{ spotId: "s1" }, { spotId: "s3" }]);
|
||||
db.courseSpotHold.findMany.mockResolvedValue([{ spotId: "s2" }]);
|
||||
|
||||
const result = await assignSpot(db as never, {
|
||||
courseId: "c1",
|
||||
spots,
|
||||
requestedSpotId: "s1",
|
||||
holdId: null,
|
||||
});
|
||||
expect(result?.spotId).toBe("s2");
|
||||
});
|
||||
|
||||
it("liefert null, wenn alle Plätze bezahlt sind", async () => {
|
||||
db.courseBooking.findMany.mockResolvedValue(spots.map((s) => ({ spotId: s.id })));
|
||||
const result = await assignSpot(db as never, {
|
||||
courseId: "c1",
|
||||
spots,
|
||||
requestedSpotId: "s1",
|
||||
holdId: null,
|
||||
});
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("weist bei alten Sessions ohne Wunschplatz den ersten freien zu", async () => {
|
||||
const result = await assignSpot(db as never, {
|
||||
courseId: "c1",
|
||||
spots,
|
||||
requestedSpotId: null,
|
||||
holdId: null,
|
||||
});
|
||||
expect(result).toEqual({ spotId: "s1", spotLabel: "Reformer 1", changed: false });
|
||||
});
|
||||
});
|
||||
|
||||
describe("holdSpot", () => {
|
||||
const params = {
|
||||
courseId: "c1",
|
||||
spotId: "s1",
|
||||
holderKey: spotHolderKey({ userId: "u1" }),
|
||||
expiresAt: new Date(Date.now() + 30 * 60_000),
|
||||
};
|
||||
|
||||
it("räumt abgelaufene und eigene alte Holds weg, bevor es hält", async () => {
|
||||
const result = await holdSpot(db as never, params);
|
||||
|
||||
expect(result).toEqual({ held: true, holdId: "hold-1" });
|
||||
const where = db.courseSpotHold.deleteMany.mock.calls[0][0].where;
|
||||
expect(where.courseId).toBe("c1");
|
||||
expect(where.OR).toContainEqual({ holderKey: "user:u1" });
|
||||
});
|
||||
|
||||
it("hält keinen Platz, der schon bezahlt ist", async () => {
|
||||
db.courseBooking.findFirst.mockResolvedValue({ id: "b1" });
|
||||
const result = await holdSpot(db as never, params);
|
||||
expect(result.held).toBe(false);
|
||||
expect(db.courseSpotHold.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("verliert gegen einen gleichzeitigen Checkout für denselben Platz", async () => {
|
||||
db.courseSpotHold.create.mockRejectedValue(
|
||||
Object.assign(new Error("Unique constraint failed"), { code: "P2002" })
|
||||
);
|
||||
const result = await holdSpot(db as never, params);
|
||||
expect(result).toMatchObject({ held: false });
|
||||
});
|
||||
});
|
||||
|
||||
describe("spotHolderKey", () => {
|
||||
it("normalisiert Gast-E-Mails, damit derselbe Gast seinen alten Hold ersetzt", () => {
|
||||
expect(spotHolderKey({ guestEmail: " Gast@Example.com " })).toBe("guest:gast@example.com");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue