import { describe, it, expect, beforeEach, vi, afterEach } from "vitest"; import { render, screen, fireEvent } from "@testing-library/react"; import { OnboardingResumeCard } from "../OnboardingResumeCard"; // Mock the model-onboarding-state module vi.mock("../model-onboarding-state", () => ({ getOnboardingResumeStep: vi.fn(), })); const mockTrackOnboardingEvent = vi.fn(); vi.mock("../onboarding-events", () => ({ trackOnboardingEvent: (...args: unknown[]) => mockTrackOnboardingEvent(...args), getOnboardingSessionId: () => "test-session-id", })); import { getOnboardingResumeStep } from "../model-onboarding-state"; describe("OnboardingResumeCard", () => { const mockGetOnboardingResumeStep = getOnboardingResumeStep as ReturnType; beforeEach(() => { mockGetOnboardingResumeStep.mockReset(); mockTrackOnboardingEvent.mockReset(); mockGetOnboardingResumeStep.mockReturnValue(null); }); afterEach(() => { mockGetOnboardingResumeStep.mockReset(); mockTrackOnboardingEvent.mockReset(); }); describe("rendering", () => { it("renders nothing when no resumable state exists", () => { mockGetOnboardingResumeStep.mockReturnValue(null); const { container } = render(); expect(container.firstChild).toBeNull(); }); it("renders the resume card when resumable state exists", () => { mockGetOnboardingResumeStep.mockReturnValue({ currentStep: "ai-setup", label: "AI Setup", completedSteps: [], }); render(); expect(screen.getByRole("region", { name: "Resume onboarding" })).toBeInTheDocument(); }); it("displays the step label", () => { mockGetOnboardingResumeStep.mockReturnValue({ currentStep: "github", label: "GitHub", completedSteps: ["ai-setup"], }); render(); expect(screen.getByText("GitHub")).toBeInTheDocument(); }); it("displays the title", () => { mockGetOnboardingResumeStep.mockReturnValue({ currentStep: "first-task", label: "First Task", completedSteps: ["ai-setup", "github"], }); render(); expect(screen.getByText("Continue Setup")).toBeInTheDocument(); }); it("displays the continue button", () => { mockGetOnboardingResumeStep.mockReturnValue({ currentStep: "ai-setup", label: "AI Setup", completedSteps: [], }); render(); expect(screen.getByText("Continue onboarding")).toBeInTheDocument(); }); it("has accessible button with proper role", () => { mockGetOnboardingResumeStep.mockReturnValue({ currentStep: "ai-setup", label: "AI Setup", completedSteps: [], }); render(); const button = screen.getByRole("button", { name: "Continue onboarding" }); expect(button).toBeInTheDocument(); }); }); describe("interaction", () => { it("calls onResume when button is clicked", () => { mockGetOnboardingResumeStep.mockReturnValue({ currentStep: "ai-setup", label: "AI Setup", completedSteps: [], }); const onResume = vi.fn(); render(); const button = screen.getByRole("button", { name: "Continue onboarding" }); fireEvent.click(button); expect(mockTrackOnboardingEvent).toHaveBeenCalledWith( "onboarding:resumed", expect.objectContaining({ source: "resume-card" }), ); expect(onResume).toHaveBeenCalledTimes(1); }); it("button is keyboard accessible", () => { mockGetOnboardingResumeStep.mockReturnValue({ currentStep: "ai-setup", label: "AI Setup", completedSteps: [], }); const onResume = vi.fn(); render(); const button = screen.getByRole("button", { name: "Continue onboarding" }); // Click simulates both mouse and keyboard activation fireEvent.click(button); expect(onResume).toHaveBeenCalledTimes(1); }); }); describe("step context", () => { it("shows correct message for ai-setup step", () => { mockGetOnboardingResumeStep.mockReturnValue({ currentStep: "ai-setup", label: "AI Setup", completedSteps: [], }); render(); expect(screen.getByText(/AI Setup/)).toBeInTheDocument(); }); it("shows correct message for github step", () => { mockGetOnboardingResumeStep.mockReturnValue({ currentStep: "github", label: "GitHub", completedSteps: ["ai-setup"], }); render(); expect(screen.getByText(/GitHub/)).toBeInTheDocument(); }); it("shows correct message for first-task step", () => { mockGetOnboardingResumeStep.mockReturnValue({ currentStep: "first-task", label: "First Task", completedSteps: ["ai-setup", "github"], }); render(); expect(screen.getByText(/First Task/)).toBeInTheDocument(); }); }); describe("completed step count", () => { it("shows progress text without count when 0 steps completed", () => { mockGetOnboardingResumeStep.mockReturnValue({ currentStep: "ai-setup", label: "AI Setup", completedSteps: [], }); render(); // When 0 steps completed, text is just "You're on the