/** * Tests for PathManager start/pause/resume functionality */ import { describe, it, expect, beforeEach } from "vitest"; import { PathManager } from "../../src/impl/PathManager.js"; describe("PathManager - Start/Pause/Resume/GetActivePath", () => { let pathManager; let mockPaths; beforeEach(() => { // Clear localStorage before each test localStorage.clear(); // Create mock paths mockPaths = [ { id: "css-fundamentals", title: "CSS Fundamentals", modules: [ { id: "basic-selectors", lessons: [{}, {}, {}] } ], estimatedTime: 60 }, { id: "flexbox-master", title: "Flexbox Master", modules: [ { id: "flex-basics", lessons: [{}, {}] } ], estimatedTime: 90 } ]; // Create fresh PathManager instance pathManager = new PathManager(); pathManager.setPaths(mockPaths); }); describe("getActivePath()", () => { it("should return null when no path is active", () => { const result = pathManager.getActivePath(); expect(result).toBeNull(); }); it("should return the active path object after starting a path", () => { pathManager.startPath("css-fundamentals"); const result = pathManager.getActivePath(); expect(result).not.toBeNull(); expect(result.id).toBe("css-fundamentals"); expect(result.title).toBe("CSS Fundamentals"); }); it("should return null after pausing", () => { pathManager.startPath("css-fundamentals"); pathManager.pausePath(); const result = pathManager.getActivePath(); expect(result).toBeNull(); }); }); describe("startPath(pathId)", () => { it("should activate a path and return true", () => { const result = pathManager.startPath("css-fundamentals"); expect(result).toBe(true); expect(pathManager.getActivePath()).not.toBeNull(); }); it("should return false for non-existent path", () => { const result = pathManager.startPath("non-existent"); expect(result).toBe(false); expect(pathManager.getActivePath()).toBeNull(); }); it("should initialize progress for new path", () => { pathManager.startPath("css-fundamentals"); const progress = pathManager.getPathProgress("css-fundamentals"); expect(progress.startTimestamp).not.toBeNull(); expect(progress.isStarted).toBe(true); }); it("should switch active path when starting a different path", () => { pathManager.startPath("css-fundamentals"); expect(pathManager.getActivePath().id).toBe("css-fundamentals"); pathManager.startPath("flexbox-master"); expect(pathManager.getActivePath().id).toBe("flexbox-master"); }); it("should persist active path to localStorage", () => { pathManager.startPath("css-fundamentals"); const saved = JSON.parse(localStorage.getItem("codeCrispies.pathProgress")); expect(saved.activePathId).toBe("css-fundamentals"); }); }); describe("pausePath()", () => { it("should deactivate the current path and return true", () => { pathManager.startPath("css-fundamentals"); const result = pathManager.pausePath(); expect(result).toBe(true); expect(pathManager.getActivePath()).toBeNull(); }); it("should return false when no path is active", () => { const result = pathManager.pausePath(); expect(result).toBe(false); }); it("should update lastActivityTimestamp before pausing", () => { pathManager.startPath("css-fundamentals"); const progressBefore = pathManager.getPathProgress("css-fundamentals"); const timestampBefore = progressBefore.lastActivityTimestamp; // Small delay to ensure timestamp changes const now = new Date().toISOString(); pathManager.pausePath(); const progressAfter = pathManager.getPathProgress("css-fundamentals"); expect(progressAfter.lastActivityTimestamp).toBeTruthy(); }); it("should persist inactive state to localStorage", () => { pathManager.startPath("css-fundamentals"); pathManager.pausePath(); const saved = JSON.parse(localStorage.getItem("codeCrispies.pathProgress")); expect(saved.activePathId).toBeNull(); }); }); describe("resumePath(pathId)", () => { it("should reactivate a previously started path and return true", () => { pathManager.startPath("css-fundamentals"); pathManager.pausePath(); const result = pathManager.resumePath("css-fundamentals"); expect(result).toBe(true); expect(pathManager.getActivePath().id).toBe("css-fundamentals"); }); it("should return false for a path that was never started", () => { const result = pathManager.resumePath("flexbox-master"); expect(result).toBe(false); }); it("should return false for non-existent path", () => { const result = pathManager.resumePath("non-existent"); expect(result).toBe(false); }); it("should update lastActivityTimestamp when resuming", () => { pathManager.startPath("css-fundamentals"); const timestampBefore = pathManager.getPathProgress("css-fundamentals").lastActivityTimestamp; pathManager.pausePath(); pathManager.resumePath("css-fundamentals"); const timestampAfter = pathManager.getPathProgress("css-fundamentals").lastActivityTimestamp; expect(timestampAfter).toBeTruthy(); }); it("should persist resumed state to localStorage", () => { pathManager.startPath("css-fundamentals"); pathManager.pausePath(); pathManager.resumePath("css-fundamentals"); const saved = JSON.parse(localStorage.getItem("codeCrispies.pathProgress")); expect(saved.activePathId).toBe("css-fundamentals"); }); }); describe("Active path state - Only one path active at a time", () => { it("should only allow one active path at a time", () => { pathManager.startPath("css-fundamentals"); expect(pathManager.getActivePath().id).toBe("css-fundamentals"); pathManager.startPath("flexbox-master"); expect(pathManager.getActivePath().id).toBe("flexbox-master"); // Only flexbox-master should be active const activePath = pathManager.getActivePath(); expect(activePath.id).toBe("flexbox-master"); }); it("should store active path state separately from progress", () => { pathManager.startPath("css-fundamentals"); const saved = JSON.parse(localStorage.getItem("codeCrispies.pathProgress")); // Active path ID stored separately expect(saved).toHaveProperty("activePathId"); expect(saved.activePathId).toBe("css-fundamentals"); // Progress data stored separately expect(saved).toHaveProperty("pathProgress"); expect(saved.pathProgress).toHaveProperty("css-fundamentals"); }); }); });