import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest' import { render, screen } from '@testing-library/react' import * as React from 'react' import { SmartTooltip } from './smart-tooltip' // Mock the useLayoutEffect hook for testing overflow scenarios vi.mock('react', async () => { const actual = await vi.importActual('react') return { ...actual, useLayoutEffect: (callback: () => void) => { callback() }, } }) // Setup timers for useLayoutEffect timeout beforeEach(() => { vi.useFakeTimers() }) afterEach(() => { vi.restoreAllMocks() vi.useRealTimers() }) describe('SmartTooltip', () => { const defaultProps = { title: 'Test Label', children: ({ ref }: { ref: React.Ref }) => (
} data-testid='test-child'> Content
), } test('renders correctly with child element', () => { render() const child = screen.getByTestId('test-child') expect(child).toBeTruthy() expect(child.textContent).toBe('Content') }) test('passes ref to children function', () => { const childrenSpy = vi .fn() .mockReturnValue(
Content
) render({childrenSpy}) expect(childrenSpy).toHaveBeenCalledTimes(1) // Just check that a ref was passed expect(childrenSpy).toHaveBeenCalled() }) test('handles undefined title', () => { render( {({ ref }) => (
} data-testid='test-child'> Content
)}
, ) const child = screen.getByTestId('test-child') expect(child).toBeTruthy() }) test('updates isOverflowing state when dependencies change', () => { const { rerender } = render( {({ ref }) => (
} data-testid='test-child'> Content
)}
, ) // Re-render with different dependencies to trigger useLayoutEffect rerender( {({ ref }) => (
} data-testid='test-child'> Content
)}
, ) expect(screen.getByTestId('test-child')).toBeTruthy() }) test('tooltip behavior with overflowing content', () => { // Mock the ref.current properties to simulate overflow vi.spyOn(React, 'useRef').mockReturnValue({ current: { scrollWidth: 100, clientWidth: 50, scrollHeight: 100, clientHeight: 50, }, } as React.RefObject) render() // Force the timeout in useLayoutEffect to execute vi.runAllTimers() // Verify the tooltip has the correct title const tooltipWrapper = screen.getByTestId('test-child') expect(tooltipWrapper).toBeTruthy() }) test('tooltip behavior with non-overflowing content', () => { // Mock the ref.current properties to simulate no overflow vi.spyOn(React, 'useRef').mockReturnValue({ current: { scrollWidth: 50, clientWidth: 100, scrollHeight: 50, clientHeight: 100, }, } as React.RefObject) render() // Force the timeout in useLayoutEffect to execute vi.runAllTimers() // Verify the tooltip doesn't have a title (since there's no overflow) const tooltipWrapper = screen.getByTestId('test-child') expect(tooltipWrapper).toBeTruthy() // Check that the title attribute is not set since content is not overflowing expect(tooltipWrapper?.getAttribute('title')).toBeFalsy() }) test('accepts custom timeout parameter', () => { const customTimeout = 1000 // Spy on setTimeout to verify it's called with the custom timeout const setTimeoutSpy = vi.spyOn(global, 'setTimeout') render() expect(setTimeoutSpy).toHaveBeenCalledWith( expect.any(Function), customTimeout, ) setTimeoutSpy.mockRestore() }) test('passes TooltipProps to the Tooltip component', () => { render( , ) const tooltipWrapper = screen.getByTestId('test-child') expect(tooltipWrapper).toBeTruthy() }) })