import { describe, it, expect, beforeAll } from "vitest"; import fs from "fs"; import ExcelJS from "exceljs"; import { getThemeColors, getUpcomingSheets, groupSheetsByDate, extractDaySchedule, } from "../scrape/parse/v3.js"; const XLSX_PATH = "tests/content/1.xlsx"; const TEACHERMAP_PATH = "tests/content/teachermap.json"; let workbook: ExcelJS.Workbook; let teachermap: Record; beforeAll(async () => { workbook = new ExcelJS.Workbook(); await workbook.xlsx.readFile(XLSX_PATH); teachermap = JSON.parse(fs.readFileSync(TEACHERMAP_PATH, "utf8")); }); describe("sheet filtering", () => { it("includes sheets on or after the injected date", () => { const injected = new Date(2026, 5, 2); // June 2, 2026 const sheets = getUpcomingSheets(workbook, injected); expect(sheets.length).toBeGreaterThanOrEqual(1); expect(sheets.map((s) => s.dateKey)).toContain("2026-06-02"); }); it("excludes sheets before the injected date", () => { const injected = new Date(2026, 5, 2); const sheets = getUpcomingSheets(workbook, injected); for (const s of sheets) { const [y, m, d] = s.dateKey.split("-").map(Number); expect(new Date(y, m - 1, d).getTime()).toBeGreaterThanOrEqual( injected.getTime(), ); } }); }); describe("full day parsing", () => { let result: ReturnType; let sheet: ExcelJS.Worksheet; let themeColors: Awaited>; beforeAll(async () => { const injected = new Date(2026, 5, 2); const upcoming = getUpcomingSheets(workbook, injected); const resolved = groupSheetsByDate(upcoming); const day = resolved.find((d) => d.dateKey === "2026-06-02")!; sheet = day.sheet; themeColors = await getThemeColors(XLSX_PATH); result = extractDaySchedule(sheet, teachermap, themeColors, []); }); describe("changes", () => { it("is a non-empty record of class → lessons", () => { const keys = Object.keys(result.changes); expect(keys.length).toBeGreaterThan(0); for (const [cls, lessons] of Object.entries(result.changes)) { expect(cls).toMatch(/^[AEC][0-4][a-c]?$/); expect(lessons).toHaveLength(10); for (const lesson of lessons) { if (lesson === null) continue; expect(lesson).toHaveProperty("text"); expect(typeof lesson.text).toBe("string"); expect(lesson).toHaveProperty("backgroundColor"); } } }); it("includes A1a with known lesson at hour 5", () => { const a1a = result.changes["A1a"]; expect(a1a).toBeDefined(); const hour5 = a1a[4]; expect(hour5).not.toBeNull(); expect(hour5!.text).toContain("ZE"); }); }); describe("absence", () => { it("is an array of parsed absence entries", () => { expect(Array.isArray(result.absence)).toBe(true); expect(result.absence.length).toBeGreaterThan(0); for (const entry of result.absence) { expect(entry).toHaveProperty("teacher"); expect(entry).toHaveProperty("teacherCode"); expect(entry).toHaveProperty("type"); expect(entry).toHaveProperty("hours"); } }); it("contains a known absence entry", () => { const su = result.absence.find((a: any) => a.teacherCode === "su"); expect(su).toBeDefined(); expect(su!.teacher).toContain("Studénková"); }); }); describe("takesPlace", () => { it("is a non-empty string", () => { expect(typeof result.takesPlace).toBe("string"); expect(result.takesPlace.length).toBeGreaterThan(0); }); }); describe("reservedRooms", () => { it("is an array of 10 entries", () => { expect(result.reservedRooms).toHaveLength(10); }); }); });