Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,27 +68,30 @@ describe('ClusterCardCompact', () => {
})

it('displays unreachable icon for offline cluster', () => {
const cluster = createMockCluster({ healthy: false, unreachable: true })
const cluster = createMockCluster({ healthy: false, reachable: false })
const { container } = render(<ClusterCardCompact {...defaultProps} cluster={cluster} />)
expect(container.querySelector('[class*="WifiOff"]')).toBeTruthy()
const icon = container.querySelector('svg')
expect(icon).toBeInTheDocument()
Comment on lines +71 to +74
})

it('displays alert icon for unhealthy cluster', () => {
const cluster = createMockCluster({ healthy: false, unreachable: false })
const cluster = createMockCluster({ healthy: false, reachable: true })
const { container } = render(<ClusterCardCompact {...defaultProps} cluster={cluster} />)
expect(container.querySelector('[class*="AlertCircle"]')).toBeTruthy()
const icon = container.querySelector('svg')
expect(icon).toBeInTheDocument()
Comment on lines +78 to +81
})

it('displays token expired icon when token is expired', () => {
const cluster = createMockCluster({ tokenExpiry: new Date('2020-01-01').toISOString() })
const cluster = createMockCluster({ errorType: 'auth' })
const { container } = render(<ClusterCardCompact {...defaultProps} cluster={cluster} />)
expect(container.querySelector('[class*="KeyRound"]')).toBeTruthy()
const icon = container.querySelector('svg')
expect(icon).toBeInTheDocument()
Comment on lines +85 to +88
})

it('displays current cluster star icon', () => {
const cluster = createMockCluster({ isCurrent: true })
const { container } = render(<ClusterCardCompact {...defaultProps} cluster={cluster} />)
expect(container.querySelector('[class*="Star"]')).toBeTruthy()
expect(container.querySelector('[class*="lucide-star"]')).toBeTruthy()
})

it('displays alias badge when cluster has aliases', () => {
Expand Down Expand Up @@ -124,15 +127,14 @@ describe('ClusterCardCompact', () => {
it('displays remove button for unreachable kubeconfig clusters', () => {
const cluster = createMockCluster({
reachable: false,
errorType: 'network',
source: 'kubeconfig',
})
render(<ClusterCardCompact {...defaultProps} cluster={cluster} />)
render(<ClusterCardCompact {...defaultProps} cluster={cluster} isConnected={true} />)
expect(screen.getByTestId('remove-cluster-button')).toBeInTheDocument()
})

it('does not display remove button for healthy clusters', () => {
const cluster = createMockCluster({ healthy: true, unreachable: false })
const cluster = createMockCluster({ healthy: true, reachable: true })
render(<ClusterCardCompact {...defaultProps} cluster={cluster} />)
expect(screen.queryByTestId('remove-cluster-button')).not.toBeInTheDocument()
})
Expand All @@ -157,6 +159,8 @@ describe('ClusterCardCompact', () => {
it('displays GPU count of 0 when no GPUs are present', () => {
const cluster = createMockCluster({ nodeCount: 3, cpuCores: 12, podCount: 50 })
render(<ClusterCardCompact {...defaultProps} cluster={cluster} gpuInfo={undefined} />)
expect(screen.getByText('0')).toBeInTheDocument()
// The card should show 0 for GPU count when gpuInfo is undefined
const gpuCells = screen.getAllByText('0')
expect(gpuCells.length).toBeGreaterThan(0)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ const createMockCluster = (overrides?: Partial<ClusterInfo>): ClusterInfo => ({
...overrides,
})

const createMockGPUInfo = (overrides?: Partial<GPUInfo>): GPUInfo => ({
total: 4,
allocated: 2,
free: 2,
...overrides,
})

describe('ClusterCardList', () => {
const defaultProps = {
cluster: createMockCluster(),
Expand All @@ -47,13 +54,32 @@ describe('ClusterCardList', () => {
cpuCores: 20,
podCount: 100,
})
render(<ClusterCardList {...defaultProps} cluster={cluster} />)
const gpuInfo = createMockGPUInfo({ total: 8, allocated: 6 })
render(<ClusterCardList {...defaultProps} cluster={cluster} gpuInfo={gpuInfo} />)

expect(screen.getByText('5')).toBeInTheDocument()
expect(screen.getByText('20')).toBeInTheDocument()
expect(screen.getByText('100')).toBeInTheDocument()
})

it('displays healthy status indicator for healthy cluster', () => {
const cluster = createMockCluster({ healthy: true })
render(<ClusterCardList {...defaultProps} cluster={cluster} />)
expect(screen.getByRole('button', { name: /Select cluster test-context/i })).toBeInTheDocument()
})

it('displays unreachable icon for offline cluster', () => {
const cluster = createMockCluster({ healthy: false, reachable: false })
const { container } = render(<ClusterCardList {...defaultProps} cluster={cluster} />)
expect(container.querySelector('[class*="lucide-wifi-off"]')).toBeTruthy()
})

it('displays token expired icon when token is expired', () => {
const cluster = createMockCluster({ errorType: 'auth' })
const { container } = render(<ClusterCardList {...defaultProps} cluster={cluster} />)
expect(container.querySelector('[class*="lucide-key-round"]')).toBeTruthy()
})

it('calls onSelectCluster when card is clicked', () => {
const onSelectCluster = vi.fn()
render(<ClusterCardList {...defaultProps} onSelectCluster={onSelectCluster} />)
Expand All @@ -62,24 +88,57 @@ describe('ClusterCardList', () => {
expect(onSelectCluster).toHaveBeenCalledTimes(1)
})

it('calls onSelectCluster on Enter key press', () => {
const onSelectCluster = vi.fn()
render(<ClusterCardList {...defaultProps} onSelectCluster={onSelectCluster} />)
const card = screen.getByRole('button', { name: /Select cluster test-context/i })
fireEvent.keyDown(card, { key: 'Enter' })
expect(onSelectCluster).toHaveBeenCalledTimes(1)
})

it('calls onRefreshCluster when refresh button is clicked', () => {
const onRefreshCluster = vi.fn()
render(<ClusterCardList {...defaultProps} onRefreshCluster={onRefreshCluster} />)
const refreshButton = screen.getByRole('button', { name: /common.refreshClusterData/i })
const refreshButton = screen.getByRole('button', { name: /refreshClusterData/i })
fireEvent.click(refreshButton)
expect(onRefreshCluster).toHaveBeenCalledTimes(1)
})

it('disables refresh button when cluster is unreachable', () => {
const cluster = createMockCluster({ healthy: false, reachable: false, errorType: 'network' })
render(<ClusterCardList {...defaultProps} cluster={cluster} />)
const refreshButton = screen.getAllByRole('button', { name: /cluster.controlsDisabledOffline/i }).find(el => el.tagName === 'BUTTON')!
const cluster = createMockCluster({ healthy: false, reachable: false })
const onRefreshCluster = vi.fn()
render(<ClusterCardList {...defaultProps} cluster={cluster} onRefreshCluster={onRefreshCluster} />)
const refreshButton = screen.getByRole('button', { name: /cluster.controlsDisabledOffline/i })
expect(refreshButton).toBeDisabled()
})

it('displays current cluster star icon', () => {
const cluster = createMockCluster({ isCurrent: true })
const { container } = render(<ClusterCardList {...defaultProps} cluster={cluster} />)
expect(container.querySelector('[class*="lucide-star"]')).toBeTruthy()
})

it('displays alias badge when cluster has aliases', () => {
const cluster = createMockCluster({ aliases: ['alias1', 'alias2'] })
render(<ClusterCardList {...defaultProps} cluster={cluster} />)
expect(screen.getByText('+2')).toBeInTheDocument()
})

it('renders drag handle when provided', () => {
const dragHandle = <div data-testid="drag-handle">Drag</div>
render(<ClusterCardList {...defaultProps} dragHandle={dragHandle} />)
expect(screen.getByTestId('drag-handle')).toBeInTheDocument()
})

it('displays loading state for initial load', () => {
const cluster = createMockCluster({
nodeCount: undefined,
cpuCores: undefined,
podCount: undefined,
loading: true,
})
render(<ClusterCardList {...defaultProps} cluster={cluster} />)
// Loading indicator should be present
expect(screen.queryByText('-')).toBeInTheDocument()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,14 @@ describe('ClusterGrid.common utilities', () => {

render(
<div onMouseDown={parentMouseDown}>
<ActionTooltipWrapper tooltip="Test">
<button>Test</button>
<ActionTooltipWrapper tooltip="Test tooltip">
<button>Test Button</button>
</ActionTooltipWrapper>
</div>
)

const wrapper = screen.getByText('Test').parentElement
const button = screen.getByRole('button', { name: 'Test Button' })
const wrapper = button.closest('span')
if (wrapper) {
fireEvent.mouseDown(wrapper)
expect(parentMouseDown).not.toHaveBeenCalled()
Comment on lines +106 to 110
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,17 @@ vi.mock('../../../lib/dashboards/DashboardPage', () => ({
),
}))

const mockPodIssues: unknown[] = []
const mockDeploymentIssues: unknown[] = []
const mockDeployments: unknown[] = []
const mockClusters: unknown[] = []
let mockPodIssues: any[] = []
let mockDeploymentIssues: any[] = []
let mockDeployments: any[] = []
const mockClusters: any[] = []
Comment on lines +46 to +49
let mockIsLoading = false
let mockIsDemoMode = true

vi.mock('../../../hooks/useMCP', () => ({
usePodIssues: () => ({ issues: mockPodIssues, isLoading: mockIsLoading, isRefreshing: false, lastUpdated: null, refetch: vi.fn() }),
useDeploymentIssues: () => ({ issues: mockDeploymentIssues, isLoading: mockIsLoading, isRefreshing: false, refetch: vi.fn() }),
useDeployments: () => ({ deployments: mockDeployments, isLoading: mockIsLoading, isRefreshing: false, refetch: vi.fn() }),
useDeploymentIssues: () => ({ issues: mockDeploymentIssues, isLoading: mockIsLoading, isRefreshing: false, lastUpdated: null, refetch: vi.fn() }),
useDeployments: () => ({ deployments: mockDeployments, isLoading: mockIsLoading, isRefreshing: false, lastUpdated: null, refetch: vi.fn() }),
useClusters: () => ({ clusters: mockClusters, deduplicatedClusters: mockClusters, isLoading: mockIsLoading, lastUpdated: null, refetch: vi.fn() }),
}))

Expand Down Expand Up @@ -448,10 +448,10 @@ describe('Loading skeleton and agent-offline states (#12481)', () => {
renderWorkloads()

// Skeleton elements should be present (they use role or specific class)
const skeletons = screen.getAllByTestId ?
const skeletons = screen.getAllByTestId ?
document.querySelectorAll('[class*="skeleton"], [class*="Skeleton"], [class*="animate-pulse"]') :
document.querySelectorAll('[class*="skeleton"], [class*="Skeleton"], [class*="animate-pulse"]')
Comment on lines +451 to 453

expect(skeletons.length).toBeGreaterThan(0)
})

Expand Down
1 change: 1 addition & 0 deletions web/src/lib/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
export * from './network'
export * from './storage'
export * from './time'
export * from './ui'
export * from './units'
export * from './status-colors'
Loading