import { render, screen, fireEvent } from '@testing-library/react'; import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from './input-otp'; import { OTPInputContext } from 'input-otp'; import React from 'react'; describe('InputOTP', () => { // input-otp schedules internal setTimeout(0/10/50) calls on mount that it // never cancels on unmount. Under real timers those fire after this file's // jsdom environment is torn down, throwing `window is not defined` as an // unhandled error in later test files. Fake timers keep them from ever // firing for real. beforeEach(() => { vi.useFakeTimers(); }); afterEach(() => { vi.useRealTimers(); }); it('renders children correctly', () => { render( ); expect(screen.getByText('A')).toBeInTheDocument(); }); it('renders correctly with different sizes', () => { const { rerender, container } = render( ); expect(container.querySelector('[data-slot="input-otp-slot"]')).toHaveClass('h-8', 'w-8'); rerender( ); expect(container.querySelector('[data-slot="input-otp-slot"]')).toHaveClass('h-10', 'w-10'); rerender( ); expect(container.querySelector('[data-slot="input-otp-slot"]')).toHaveClass('h-12', 'w-12'); }); it('renders correctly', () => { const { container } = render( ); expect(container.querySelector('[data-slot="input-otp"]')).toBeInTheDocument(); expect(container.querySelectorAll('[data-slot="input-otp-slot"]')).toHaveLength(4); expect(container.querySelector('[data-slot="input-otp-separator"]')).toBeInTheDocument(); }); it('updates value on typing', () => { render( ); const input = screen.getByRole('textbox'); fireEvent.change(input, { target: { value: '1234' } }); expect(input).toHaveValue('1234'); }); });