import { fireEvent, render } from '@testing-library/react'; import { act } from 'react'; import '@testing-library/jest-dom'; import { type Mock, afterEach, beforeEach, describe, expect, it, vi, } from 'vitest'; import { pressable } from '../../styles/theme'; import { DELAY_MS, QuantitySelector } from './QuantitySelector'; describe('QuantitySelector component', () => { let mockOnChange: Mock; beforeEach(() => { vi.useFakeTimers(); mockOnChange = vi.fn(); }); afterEach(() => { vi.useRealTimers(); }); it('should render', () => { const { getByTestId } = render( , ); const input = getByTestId('ockQuantitySelector'); expect(input).toBeInTheDocument(); }); it('should render disabled', () => { const { getByTestId } = render( , ); const decrementButton = getByTestId('ockQuantitySelector_decrement'); const input = getByTestId('ockTextInput_Input'); const incrementButton = getByTestId('ockQuantitySelector_increment'); expect(decrementButton).toHaveClass(pressable.disabled); expect(input).toHaveClass(pressable.disabled); expect(incrementButton).toHaveClass(pressable.disabled); }); it('should render default value', () => { const { getByTestId } = render( , ); const input = getByTestId('ockTextInput_Input'); expect(input).toHaveValue('1'); }); it('should increment value', () => { const { getByTestId } = render( , ); const incrementButton = getByTestId('ockQuantitySelector_increment'); act(() => { incrementButton.click(); }); const input = getByTestId('ockTextInput_Input'); expect(input).toHaveValue('2'); expect(mockOnChange).toHaveBeenCalledWith('2'); }); it('should not increment above maxQuantity', () => { const { getByTestId } = render( , ); const incrementButton = getByTestId('ockQuantitySelector_increment'); act(() => { incrementButton.click(); }); const input = getByTestId('ockTextInput_Input'); expect(input).toHaveValue('1'); expect(mockOnChange).toHaveBeenCalledWith('1'); }); it('should decrement value', () => { const { getByTestId } = render( , ); const input = getByTestId('ockTextInput_Input'); const incrementButton = getByTestId('ockQuantitySelector_increment'); const decrementButton = getByTestId('ockQuantitySelector_decrement'); act(() => { incrementButton.click(); }); expect(input).toHaveValue('2'); act(() => { decrementButton.click(); }); expect(input).toHaveValue('1'); expect(mockOnChange).toHaveBeenCalledWith('1'); }); it('should not decrement below minQuantity', () => { const { getByTestId } = render( , ); const decrementButton = getByTestId('ockQuantitySelector_decrement'); act(() => { decrementButton.click(); }); const input = getByTestId('ockTextInput_Input'); expect(input).toHaveValue('1'); expect(mockOnChange).toHaveBeenCalledWith('1'); }); it('should not fire onChange on empty string', () => { const { getByTestId } = render( , ); const input = getByTestId('ockTextInput_Input'); act(() => { fireEvent.change(input, { target: { value: '' } }); }); vi.advanceTimersByTime(DELAY_MS); expect(mockOnChange).not.toHaveBeenCalled(); }); it('should not fire onChange if value is not a number', () => { const { getByTestId } = render( , ); const input = getByTestId('ockTextInput_Input'); act(() => { fireEvent.change(input, { target: { value: 'a' } }); }); vi.advanceTimersByTime(DELAY_MS); expect(mockOnChange).not.toHaveBeenCalled(); }); it('should not fire onChange if value < minQuantity', () => { const { getByTestId } = render( , ); const input = getByTestId('ockTextInput_Input'); act(() => { fireEvent.change(input, { target: { value: '4' } }); }); vi.advanceTimersByTime(DELAY_MS); expect(mockOnChange).not.toHaveBeenCalled(); }); it('should not fire onChange if value > maxQuantity', () => { const { getByTestId } = render( , ); const input = getByTestId('ockTextInput_Input'); act(() => { fireEvent.change(input, { target: { value: '6' } }); }); vi.advanceTimersByTime(DELAY_MS); expect(mockOnChange).not.toHaveBeenCalled(); }); it('should fire onChange on valid value', () => { const { getByTestId } = render( , ); const input = getByTestId('ockTextInput_Input'); act(() => { fireEvent.change(input, { target: { value: '2' } }); }); vi.advanceTimersByTime(DELAY_MS); expect(mockOnChange).toHaveBeenCalledWith('2'); }); it('should reset to minQuantity on blur if no value', () => { const { getByTestId } = render( , ); const input = getByTestId('ockTextInput_Input'); act(() => { input.focus(); fireEvent.change(input, { target: { value: '' } }); input.blur(); }); expect(input).toHaveValue('1'); expect(mockOnChange).toHaveBeenCalledWith('1'); }); });