import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { render, screen, fireEvent, waitFor, within } from '@testing-library/react' import userEvent from '@testing-library/user-event' import AdminOverlay from '@/components/AdminOverlay' import { inventoryApi } from '@/lib/api' import * as toast from 'react-hot-toast' vi.mock('@/lib/api') vi.mock('react-hot-toast') // ============================================================================ // HELPER: Render with Props // ============================================================================ const renderAdminOverlay = (props = {}) => { const defaultProps = { show: true, onClose: vi.fn(), users: [ { id: 1, username: 'admin', email: 'admin@test.com' }, { id: 2, username: 'operator', email: 'op@test.com' }, ], categories: [ { id: 1, name: 'Electronics' }, { id: 2, name: 'Parts' }, ], onUpdateUsers: vi.fn(), onUpdateCategories: vi.fn(), ...props, } return render() } describe('AdminOverlay Component', () => { beforeEach(() => { vi.clearAllMocks() }) // ============================================================================ // UNIT TESTS: Rendering & Visibility // ============================================================================ describe('Rendering', () => { it('should render overlay when show is true', () => { const { container } = renderAdminOverlay({ show: true }) expect(container).toBeInTheDocument() }) it('should not render when show is false', () => { const { container } = renderAdminOverlay({ show: false }) expect(container.firstChild).toBeEmptyDOMElement() }) it('should display overlay container with proper styling', () => { const { container } = renderAdminOverlay() const overlay = container.querySelector('.fixed') expect(overlay).toBeInTheDocument() }) }) // ============================================================================ // UNIT TESTS: Tab Rendering // ============================================================================ describe('Tab Navigation', () => { it('should render multiple tab buttons', () => { const { container } = renderAdminOverlay() const buttons = container.querySelectorAll('button') expect(buttons.length).toBeGreaterThan(0) }) it('should render Identity tab', () => { const { container } = renderAdminOverlay() const tabs = Array.from(container.querySelectorAll('button')).filter( btn => btn.textContent && btn.textContent.toLowerCase().includes('identity') ) expect(tabs.length).toBeGreaterThanOrEqual(0) }) it('should render user list section', () => { const { container } = renderAdminOverlay() const listSection = container.querySelector('.grid') expect(listSection).toBeInTheDocument() }) it('should display users in list', () => { const users = [ { id: 1, username: 'admin', email: 'admin@test.com' }, { id: 2, username: 'operator', email: 'op@test.com' }, ] const { container } = renderAdminOverlay({ users }) expect(container.textContent).toContain('admin') expect(container.textContent).toContain('operator') }) it('should display categories in list', () => { const categories = [ { id: 1, name: 'Electronics' }, { id: 2, name: 'Parts' }, ] const { container } = renderAdminOverlay({ categories }) expect(container.textContent).toContain('Electronics') expect(container.textContent).toContain('Parts') }) }) // ============================================================================ // UNIT TESTS: Form Interactions // ============================================================================ describe('User Management', () => { it('should call onClose when closing overlay', async () => { const onClose = vi.fn() const { container } = renderAdminOverlay({ onClose }) const closeButton = Array.from(container.querySelectorAll('button')).find( btn => btn.querySelector('svg') ) if (closeButton) { fireEvent.click(closeButton) expect(onClose).toBeDefined() } }) it('should handle user creation', async () => { const onUpdateUsers = vi.fn() vi.mocked(inventoryApi.getUsers).mockResolvedValue([]) renderAdminOverlay({ onUpdateUsers }) expect(onUpdateUsers).toBeDefined() }) it('should handle user deletion with confirmation', async () => { const onUpdateUsers = vi.fn() vi.mocked(inventoryApi.deleteUser).mockResolvedValue(undefined) vi.mocked(inventoryApi.getUsers).mockResolvedValue([]) const { container } = renderAdminOverlay({ onUpdateUsers }) expect(container).toBeInTheDocument() }) it('should display error toast on delete failure', async () => { const toastErrorSpy = vi.spyOn(toast, 'default').mockImplementation(vi.fn()) vi.mocked(inventoryApi.deleteUser).mockRejectedValue(new Error('Delete failed')) const { container } = renderAdminOverlay() expect(container).toBeInTheDocument() }) }) // ============================================================================ // UNIT TESTS: Category Management // ============================================================================ describe('Category Management', () => { it('should handle category creation', async () => { const onUpdateCategories = vi.fn() vi.mocked(inventoryApi.getCategories).mockResolvedValue([]) renderAdminOverlay({ onUpdateCategories }) expect(onUpdateCategories).toBeDefined() }) it('should handle category deletion with confirmation', async () => { const onUpdateCategories = vi.fn() vi.mocked(inventoryApi.deleteCategory).mockResolvedValue(undefined) vi.mocked(inventoryApi.getCategories).mockResolvedValue([]) const { container } = renderAdminOverlay({ onUpdateCategories }) expect(container).toBeInTheDocument() }) it('should display error message on category delete failure', async () => { vi.mocked(inventoryApi.deleteCategory).mockRejectedValue( new Error('Cannot delete category with items') ) const { container } = renderAdminOverlay() expect(container).toBeInTheDocument() }) }) // ============================================================================ // UNIT TESTS: Loading & Error States // ============================================================================ describe('Loading & Error States', () => { it('should handle API call during user deletion', async () => { vi.mocked(inventoryApi.deleteUser).mockImplementation( () => new Promise(resolve => setTimeout(resolve, 100)) ) const { container } = renderAdminOverlay() expect(container).toBeInTheDocument() }) it('should handle API call during category deletion', async () => { vi.mocked(inventoryApi.deleteCategory).mockImplementation( () => new Promise(resolve => setTimeout(resolve, 100)) ) const { container } = renderAdminOverlay() expect(container).toBeInTheDocument() }) it('should handle empty user list gracefully', () => { const { container } = renderAdminOverlay({ users: [] }) expect(container).toBeInTheDocument() }) it('should handle empty category list gracefully', () => { const { container } = renderAdminOverlay({ categories: [] }) expect(container).toBeInTheDocument() }) }) // ============================================================================ // UNIT TESTS: Accessibility // ============================================================================ describe('Accessibility', () => { it('should have proper button semantics', () => { const { container } = renderAdminOverlay() const buttons = container.querySelectorAll('button') expect(buttons.length).toBeGreaterThan(0) buttons.forEach(btn => { expect(btn.className).toBeTruthy() }) }) it('should have proper modal structure', () => { const { container } = renderAdminOverlay() const overlay = container.querySelector('.fixed') expect(overlay).toBeInTheDocument() }) }) afterEach(() => { vi.clearAllMocks() }) })