import { describe, it, expect, vi } from 'vitest' import { render, screen, fireEvent } from '@testing-library/react' import { PendingDeviceModal, type PendingDevice } from '../PendingDeviceModal' function makeDevice(overrides: Partial = {}): PendingDevice { return { id: 'dev-1', ip: '192.168.1.100', mac: 'aa:bb:cc:dd:ee:ff', hostname: 'pve.local', os: 'Linux', services: [], suggested_type: 'server', status: 'pending', discovered_at: '2024-01-15T10:30:00Z', ...overrides, } } describe('PendingDeviceModal', () => { // ── Visibility ──────────────────────────────────────────────────────────── it('renders nothing when device is null', () => { const { container } = render( ) expect(container.querySelector('[role="dialog"]')).toBeNull() }) it('renders dialog when device is provided', () => { render( ) expect(screen.getByRole('dialog')).toBeDefined() }) // ── Device info display ─────────────────────────────────────────────────── it('shows hostname as title when available', () => { render( ) // hostname appears in both title and info row — check at least one match expect(screen.getAllByText('myserver.local').length).toBeGreaterThan(0) }) it('falls back to IP as title when hostname is null', () => { render( ) // IP appears in both title and info row when hostname is absent expect(screen.getAllByText('192.168.1.100').length).toBeGreaterThan(0) }) it('shows IP address', () => { render( ) expect(screen.getByText('192.168.1.100')).toBeDefined() }) it('shows MAC address when present', () => { render( ) expect(screen.getByText('aa:bb:cc:dd:ee:ff')).toBeDefined() }) it('shows OS when present', () => { render( ) expect(screen.getByText('Linux')).toBeDefined() }) it('does not show hostname row when hostname is null', () => { render( ) // "Hostname" label should not appear in the info rows expect(screen.queryByText('Hostname')).toBeNull() }) it('shows suggested type when present', () => { render( ) expect(screen.getByText('proxmox')).toBeDefined() }) // ── Services ────────────────────────────────────────────────────────────── it('shows "No services detected" when services list is empty', () => { render( ) expect(screen.getByText('No services detected')).toBeDefined() }) it('shows service count and details', () => { const device = makeDevice({ services: [ { port: 80, protocol: 'tcp', service_name: 'HTTP', category: 'web' }, { port: 443, protocol: 'tcp', service_name: 'HTTPS', category: 'web' }, ], }) render( ) expect(screen.getByText('Services found (2)')).toBeDefined() expect(screen.getByText('HTTP')).toBeDefined() expect(screen.getByText('HTTPS')).toBeDefined() expect(screen.getByText('80')).toBeDefined() expect(screen.getByText('443')).toBeDefined() }) it('shows service category when present', () => { const device = makeDevice({ services: [{ port: 8006, protocol: 'tcp', service_name: 'Proxmox Web', category: 'hypervisor' }], }) render( ) expect(screen.getByText('hypervisor')).toBeDefined() }) // ── Actions ─────────────────────────────────────────────────────────────── it('calls onApprove with the device when Approve is clicked (parent controls close on success)', () => { const device = makeDevice() const onApprove = vi.fn() const onClose = vi.fn() render( ) fireEvent.click(screen.getByRole('button', { name: 'Approve' })) expect(onApprove).toHaveBeenCalledWith(device) expect(onClose).not.toHaveBeenCalled() }) it('calls onHide with the device and onClose when Hide is clicked', () => { const device = makeDevice() const onHide = vi.fn() const onClose = vi.fn() render( ) fireEvent.click(screen.getByRole('button', { name: 'Hide' })) expect(onHide).toHaveBeenCalledWith(device) expect(onClose).toHaveBeenCalledOnce() }) it('calls onIgnore with the device and onClose when Delete is clicked', () => { const device = makeDevice() const onIgnore = vi.fn() const onClose = vi.fn() render( ) fireEvent.click(screen.getByRole('button', { name: 'Delete' })) expect(onIgnore).toHaveBeenCalledWith(device) expect(onClose).toHaveBeenCalledOnce() }) })