// @vitest-environment jsdom import { render, fireEvent, act } from '@testing-library/react'; import { FancyCursor } from './FancyCursor'; import { describe, it, expect, vi, beforeAll, afterAll, beforeEach } from 'vitest'; import React from 'react'; describe('FancyCursor', () => { beforeAll(() => { // Mock elementFromPoint for JSDOM // @ts-ignore document.elementFromPoint = vi.fn((x, y) => null); // Mock requestAnimationFrame vi.useFakeTimers(); }); afterAll(() => { vi.useRealTimers(); // @ts-ignore delete document.elementFromPoint; }); beforeEach(() => { vi.clearAllMocks(); // Ensure we are not seen as a touch device Object.defineProperty(navigator, 'maxTouchPoints', { value: 0, writable: true }); // @ts-ignore delete window.ontouchstart; // console.log('Test Setup:', { ontouchstart: 'ontouchstart' in window, maxTouchPoints: navigator.maxTouchPoints }); }); it('renders and updates position on mousemove', () => { const { container } = render(); // Using firstElementChild because querySelector seems flaky in this test environment const cursor = container.firstElementChild as HTMLElement; expect(cursor).toBeTruthy(); expect(cursor.id).toBe('fancy-cursor'); fireEvent.mouseMove(window, { clientX: 100, clientY: 100 }); act(() => { vi.runAllTimers(); }); // Check transform expect(cursor.style.transform).toContain('translate3d(100px, 100px, 0)'); }); it('toggles link-hover class when hovering a link', () => { // We need to attach the link to the document body because FancyCursor uses global event listeners // and checks the document structure via events or elementFromPoint. const link = document.createElement('a'); link.href = '#'; link.id = 'test-link'; link.textContent = 'Link'; document.body.appendChild(link); const { container } = render(); const cursor = container.firstElementChild as HTMLElement; expect(cursor).toBeTruthy(); // Simulate mouse over the link. // Important: in our optimized code, we rely on 'mouseover' event to set 'hoveredElement'. fireEvent.mouseOver(link); // Then mouseMove triggers the update loop fireEvent.mouseMove(window, { clientX: 50, clientY: 50 }); act(() => { vi.runAllTimers(); }); expect(cursor.classList.contains('link-hover')).toBe(true); // Move away to body fireEvent.mouseOver(document.body); fireEvent.mouseMove(window, { clientX: 200, clientY: 200 }); act(() => { vi.runAllTimers(); }); expect(cursor.classList.contains('link-hover')).toBe(false); document.body.removeChild(link); }); it('does not call elementFromPoint on mousemove', () => { // Reset elementFromPoint mock const mockElementFromPoint = vi.fn(); // @ts-ignore document.elementFromPoint = mockElementFromPoint; render(); // Trigger mousemove fireEvent.mouseMove(window, { clientX: 10, clientY: 10 }); act(() => { vi.runAllTimers(); }); // Should NOT be called in the optimized version expect(mockElementFromPoint).not.toHaveBeenCalled(); }); });