import { cleanup, fireEvent, render, screen } from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { QuestionField } from "@/lib/schema-adapter"; import { mapBackendQuestionToFrontend } from "@/lib/schema-adapter"; import { QuestionSlider } from "./question-slider"; let answerValue: any = null; const setAnswerValueMock = vi.fn(); vi.mock("@/translations/provider", () => ({ useI18n: () => ({ locale: "en", dictionary: { From: "From", To: "To" }, }), })); vi.mock("./question-answer-storage", () => ({ useQuestionAnswers: () => ({ getAnswerValue: () => answerValue, setAnswerValue: setAnswerValueMock, }), })); describe("QuestionSlider", () => { beforeEach(() => { answerValue = null; setAnswerValueMock.mockClear(); }); afterEach(() => { cleanup(); }); it("extracts range correctly from backend validation schema", () => { const backendQuestion = { id: "appearance_health_activity.height_in_centimeters", title: "Height in Centimeters", type: "scale", order: 1, required: true, is_required: true, show_guardian_notice: false, validation: { min: 100, max: 230 }, ui_config: { placeholder_en: "175", private: true }, logic: null, is_visible: true, options: [], description: "", tooltip: "", placeholder: "175", }; const frontendQ = mapBackendQuestionToFrontend(backendQuestion as any, 0); expect(frontendQ.extras.range).toEqual([100, 230]); }); it("renders scale marks correctly across the range", () => { const heightQuestion = { id: "appearance_health_activity.height_in_centimeters", title: "Height in Centimeters", type: "scale", order: 1, required: true, baseRequired: true, isVisible: true, description: "", tooltip: "", extras: { placeHolder: "175", range: [100, 230], options: [] }, options: [], validation: { min: 100, max: 230 }, } as QuestionField; answerValue = 178; render(); const slider = screen.getByRole("slider") as HTMLInputElement; expect(slider.min).toBe("100"); expect(slider.max).toBe("230"); expect(slider.value).toBe("178"); // The value badge shows 178 expect(screen.getByText("178")).toBeDefined(); // Scale marks should be rendered with multiple ticks (100, 120, ..., 230) expect(screen.getByText("100")).toBeDefined(); expect(screen.getByText("230")).toBeDefined(); expect(screen.queryByText("0")).toBeNull(); }); it("updates answer value when slider changes", () => { const weightQuestion = { id: "appearance_health_activity.weight_in_kilograms", title: "Weight in Kilograms", type: "scale", order: 2, required: true, baseRequired: true, isVisible: true, description: "", tooltip: "", extras: { placeHolder: "70", range: [40, 180], options: [] }, options: [], validation: { min: 40, max: 180 }, } as QuestionField; render(); const slider = screen.getByRole("slider"); fireEvent.change(slider, { target: { value: "85" } }); expect(setAnswerValueMock).toHaveBeenCalledWith(weightQuestion, 85); }); it("falls back gracefully when range is not in extras but in validation", () => { const customQuestion = { id: "custom_scale", title: "Satisfaction", type: "scale", order: 3, required: true, baseRequired: true, isVisible: true, description: "", tooltip: "", extras: { placeHolder: "5", range: [0, 0], options: [] }, options: [], validation: { min: 1, max: 10 }, } as QuestionField; render(); const slider = screen.getByRole("slider") as HTMLInputElement; expect(slider.min).toBe("1"); expect(slider.max).toBe("10"); expect(screen.getByText("1")).toBeDefined(); expect(screen.getByText("10")).toBeDefined(); }); });