import { render } from "@solidjs/testing-library"; import { userEvent } from "@testing-library/user-event"; import { describe, it, expect, vi, beforeEach } from "vitest"; import { ScrollToTop } from "../../../../src/ts/components/layout/footer/ScrollToTop"; import * as CoreSignals from "../../../../src/ts/states/core"; describe("ScrollToTop", () => { const getActivePageMock = vi.spyOn(CoreSignals, "getActivePage"); beforeEach(() => { getActivePageMock.mockClear().mockReturnValue("account"); Object.defineProperty(window, "scrollY", { value: 0, writable: true }); }); function renderElement(): { container: HTMLElement; button: HTMLButtonElement; } { const { container } = render(() => ); return { // oxlint-disable-next-line no-non-null-assertion container: container.children[0]! as HTMLElement, // oxlint-disable-next-line no-non-null-assertion button: container.querySelector("button")!, }; } it("renders with correct classes and structure", () => { const { container, button } = renderElement(); expect(container).toHaveClass("content-grid", "ScrollToTop"); expect(button).toHaveClass("breakout"); expect(button.querySelector("i")).toHaveClass("fas", "fa-angle-double-up"); }); it("renders invisible when scrollY is 0", () => { const { button } = renderElement(); expect(button).toHaveClass("opacity-0"); }); it("becomes visible when scrollY > 100 on non-test pages", () => { const { button } = renderElement(); scrollTo(150); expect(button).not.toHaveClass("opacity-0"); }); it("stays invisible on test page at scroll 0", () => { getActivePageMock.mockReturnValue("test"); const { button } = renderElement(); expect(button).toHaveClass("opacity-0"); }); it("stays invisible on test page even with scroll > 100", () => { getActivePageMock.mockReturnValue("test"); const { button } = renderElement(); scrollTo(150); expect(button).toHaveClass("opacity-0"); }); it("becomes invisible when scroll < 100 on non-test pages", () => { const { button } = renderElement(); scrollTo(150); expect(button).not.toHaveClass("opacity-0"); scrollTo(50); expect(button).toHaveClass("opacity-0"); }); it("scrolls to top and hides button on click", async () => { const scrollToSpy = vi.fn(); window.scrollTo = scrollToSpy; const { button } = renderElement(); scrollTo(150); await userEvent.click(button); expect(scrollToSpy).toHaveBeenCalledWith({ top: 0, behavior: "smooth", }); expect(button).toHaveClass("opacity-0"); }); it("cleans up scroll listener on unmount", () => { const removeEventListenerSpy = vi.spyOn(window, "removeEventListener"); const { unmount } = render(() => ); unmount(); expect(removeEventListenerSpy).toHaveBeenCalledWith( "scroll", expect.any(Function), ); }); function scrollTo(value: number): void { Object.defineProperty(window, "scrollY", { value, writable: true }); window.dispatchEvent(new Event("scroll")); } });