import '@testing-library/jest-dom/vitest'
import React from 'react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
import { Avatar } from './Avatar'
import { DropdownMenu } from './DropdownMenu'
import { IntegrationStatusCard } from './IntegrationStatusCard'
import { UserMenu } from './UserMenu'
afterEach(cleanup)
describe('Avatar', () => {
it('uses name initials as fallback and exposes a default accessible label', () => {
render()
expect(screen.getByRole('img', { name: '홍길동' })).toHaveTextContent('홍')
expect(screen.getByLabelText('online')).toBeInTheDocument()
})
it('falls back to initials when the profile image fails to load', () => {
render()
const image = screen.getByRole('img', { name: 'Jane Doe' })
fireEvent.error(image)
expect(screen.getByRole('img', { name: 'Jane Doe' })).toHaveTextContent('J')
})
})
describe('DropdownMenu', () => {
it('opens from the trigger and closes on outside click', () => {
render(
계정}>
프로필
)
fireEvent.click(screen.getByRole('button', { name: '계정' }))
expect(screen.getByRole('menu')).toBeInTheDocument()
fireEvent.mouseDown(screen.getByRole('button', { name: '외부' }))
expect(screen.queryByRole('menu')).not.toBeInTheDocument()
})
it('skips disabled items during keyboard navigation and returns focus to trigger after selection', () => {
const onSelect = vi.fn()
render(
액션}>
비활성
로그아웃
)
const trigger = screen.getByRole('button', { name: '액션' })
fireEvent.click(trigger)
fireEvent.keyDown(screen.getByRole('menu'), { key: 'ArrowDown' })
fireEvent.keyDown(screen.getByRole('menu'), { key: 'Enter' })
expect(onSelect).toHaveBeenCalledTimes(1)
expect(screen.queryByRole('menu')).not.toBeInTheDocument()
expect(trigger).toHaveFocus()
})
it('opens from the trigger with ArrowDown and focuses the first enabled item', () => {
render(
더보기}>
비활성
첫 액션
)
const trigger = screen.getByRole('button', { name: '더보기' })
fireEvent.keyDown(trigger, { key: 'ArrowDown' })
expect(screen.getByRole('menuitem', { name: '첫 액션' })).toHaveFocus()
})
})
describe('UserMenu', () => {
it('renders truncated user identity and calls account actions from the dropdown', () => {
const onSettingsClick = vi.fn()
const onLogout = vi.fn()
render(
)
expect(screen.getByText('홍길동')).toBeInTheDocument()
expect(screen.getByText('very.long.email.address@example-company.com')).toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: /계정 메뉴/ }))
fireEvent.click(screen.getByRole('menuitem', { name: /계정 설정/ }))
expect(onSettingsClick).toHaveBeenCalledTimes(1)
fireEvent.click(screen.getByRole('button', { name: /계정 메뉴/ }))
fireEvent.click(screen.getByRole('menuitem', { name: /로그아웃/ }))
expect(onLogout).toHaveBeenCalledTimes(1)
})
})
describe('IntegrationStatusCard', () => {
it('renders status metadata and invokes configured actions', () => {
const reconnect = vi.fn()
const disconnect = vi.fn()
render(
마지막 동기화 2분 전}
primaryAction={{ label: '다시 연결', onClick: reconnect }}
secondaryAction={{ label: '연결 해제', onClick: disconnect, tone: 'danger' }}
/>
)
expect(screen.getByText('다시 연결 필요')).toBeInTheDocument()
expect(screen.getByText('마지막 동기화 2분 전')).toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: '다시 연결' }))
fireEvent.click(screen.getByRole('button', { name: '연결 해제' }))
expect(reconnect).toHaveBeenCalledTimes(1)
expect(disconnect).toHaveBeenCalledTimes(1)
})
})