import React from 'react'; import { render, fireEvent, act } from '@testing-library/react'; import { BackToTop } from '@/src/components/BackToTop'; // Mock window properties global.scrollTo = jest.fn(); Object.defineProperty(window, 'pageYOffset', { writable: true, configurable: true, value: 0, }); describe('BackToTop', () => { beforeEach(() => { jest.clearAllMocks(); window.pageYOffset = 0; }); it('does not render button when at top of page', () => { const { container } = render(); const button = container.querySelector('button'); expect(button).not.toBeInTheDocument(); }); it('renders button when scrolled down', () => { const { container } = render(); // Simulate scroll down act(() => { window.pageYOffset = 400; fireEvent.scroll(window); }); const button = container.querySelector('button'); expect(button).toBeInTheDocument(); }); it('hides button when scrolled back up', () => { const { container } = render(); // Scroll down first act(() => { window.pageYOffset = 400; fireEvent.scroll(window); }); expect(container.querySelector('button')).toBeInTheDocument(); // Scroll back up act(() => { window.pageYOffset = 100; fireEvent.scroll(window); }); expect(container.querySelector('button')).not.toBeInTheDocument(); }); it('scrolls to top when clicked', () => { const { container } = render(); // Make button visible act(() => { window.pageYOffset = 400; fireEvent.scroll(window); }); const button = container.querySelector('button'); fireEvent.click(button!); expect(global.scrollTo).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' }); }); it('has correct styling when visible', () => { const { container } = render(); // Make button visible act(() => { window.pageYOffset = 400; fireEvent.scroll(window); }); const button = container.querySelector('button'); expect(button).toHaveClass('fixed'); expect(button).toHaveClass('bottom-8'); expect(button).toHaveClass('right-8'); expect(button).toHaveClass('bg-blue-600'); expect(button).toHaveClass('text-white'); expect(button).toHaveClass('rounded-full'); expect(button).toHaveClass('shadow-lg'); }); it('has hover effect', () => { const { container } = render(); // Make button visible act(() => { window.pageYOffset = 400; fireEvent.scroll(window); }); const button = container.querySelector('button'); expect(button).toHaveClass('hover:bg-blue-700'); expect(button).toHaveClass('hover:scale-110'); }); it('contains arrow icon', () => { const { container } = render(); // Make button visible act(() => { window.pageYOffset = 400; fireEvent.scroll(window); }); const svg = container.querySelector('svg'); expect(svg).toBeInTheDocument(); expect(svg).toHaveClass('w-6'); expect(svg).toHaveClass('h-6'); }); it('has aria-label for accessibility', () => { const { container } = render(); // Make button visible act(() => { window.pageYOffset = 400; fireEvent.scroll(window); }); const button = container.querySelector('button'); expect(button).toHaveAttribute('aria-label', 'Back to top'); }); it('cleans up scroll listener on unmount', () => { const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener'); const { unmount } = render(); unmount(); expect(removeEventListenerSpy).toHaveBeenCalledWith('scroll', expect.any(Function)); removeEventListenerSpy.mockRestore(); }); });