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
79 changes: 79 additions & 0 deletions web/src/components/missions/CardRequestDialog.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen } from '@testing-library/react'
import { CardRequestDialog } from './CardRequestDialog'

Comment on lines +1 to +4
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string, opts?: Record<string, unknown>) => {
const map: Record<string, string> = {
'orbit.cardRequest': `No card for ${opts?.project || 'project'}`,
'orbit.cardRequestAction': 'Request',
'orbit.cardRequestSending': 'Sending…',
'orbit.cardRequestRequested': 'Requested',
'orbit.cardRequestRetry': 'Retry',
}
return map[key] ?? key
},
}),
}))

vi.mock('../../lib/api', () => ({
api: {
post: vi.fn(),
},
}))

vi.mock('../../lib/analytics', () => ({
emitGroundControlCardRequestOpened: vi.fn(),
}))

vi.mock('../ui/Toast', () => ({
useToast: () => ({
showToast: vi.fn(),
}),
}))

describe('CardRequestDialog', () => {
beforeEach(() => {
vi.clearAllMocks()
})

it('renders nothing when missingProjects is empty', () => {
const { container } = render(
<CardRequestDialog missingProjects={[]} onClose={vi.fn()} />
)
expect(container.firstChild).toBeNull()
})

it('renders the dialog when there are missing projects', () => {
render(
<CardRequestDialog
missingProjects={['prometheus', 'grafana']}
onClose={vi.fn()}
/>
)
expect(screen.getByText('Missing monitoring cards')).toBeInTheDocument()
})

it('displays all missing projects', () => {
render(
<CardRequestDialog
missingProjects={['prometheus', 'grafana', 'jaeger']}
onClose={vi.fn()}
/>
)
expect(screen.getByText(/No card for prometheus/)).toBeInTheDocument()
expect(screen.getByText(/No card for grafana/)).toBeInTheDocument()
expect(screen.getByText(/No card for jaeger/)).toBeInTheDocument()
})

it('calls onClose when close button is clicked', () => {
const onClose = vi.fn()
render(
<CardRequestDialog missingProjects={['prometheus']} onClose={onClose} />
)
const closeButton = screen.getByRole('button', { name: '' })
closeButton.click()
expect(onClose).toHaveBeenCalledOnce()
})
})
131 changes: 131 additions & 0 deletions web/src/components/missions/FixerCard.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { describe, it, expect, vi } from 'vitest'
import { render, screen } from '@testing-library/react'
import { FixerCard } from './FixerCard'
import type { MissionExport } from '../../lib/missions/types'

vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string, opts?: Record<string, unknown>) => {
const map: Record<string, string> = {
'actions.import': 'Import',
'missions.browser.stepsCount': `${opts?.count || 0} steps`,
'feedback.share': 'Share',
'missions.browser.copyShareableLink': 'Copy shareable link',
'missions.browser.linkCopied': 'Link copied',
'missions.browser.copyLinkFailed': 'Failed to copy',
'missions.browser.copyFailed': 'Failed',
'missions.browser.copied': 'Copied',
}
return map[key] ?? key
},
}),
}))

const mockMission: MissionExport = {
title: 'Fix Kubernetes Pod Restart Loop',
description: 'Troubleshoot and fix pod restart loops in Kubernetes',
type: 'troubleshoot',
category: 'Kubernetes',
tags: ['kubernetes', 'pods', 'debugging'],
steps: [{ type: 'command', command: 'kubectl get pods' }],
version: '1.0.0',
}

describe('FixerCard', () => {
it('renders the mission title', () => {
render(
<FixerCard
mission={mockMission}
onImport={vi.fn()}
onSelect={vi.fn()}
/>
)
expect(screen.getByText('Fix Kubernetes Pod Restart Loop')).toBeInTheDocument()
})

it('renders the mission description', () => {
render(
<FixerCard
mission={mockMission}
onImport={vi.fn()}
onSelect={vi.fn()}
/>
)
expect(screen.getByText(/Troubleshoot and fix pod restart loops/)).toBeInTheDocument()
})

it('renders the mission type badge', () => {
render(
<FixerCard
mission={mockMission}
onImport={vi.fn()}
onSelect={vi.fn()}
/>
)
expect(screen.getByText('troubleshoot')).toBeInTheDocument()
})

it('renders the import button', () => {
render(
<FixerCard
mission={mockMission}
onImport={vi.fn()}
onSelect={vi.fn()}
/>
)
expect(screen.getByRole('button', { name: /Import/i })).toBeInTheDocument()
})

it('renders in compact mode', () => {
render(
<FixerCard
mission={mockMission}
onImport={vi.fn()}
onSelect={vi.fn()}
compact
/>
)
expect(screen.getByText('Fix Kubernetes Pod Restart Loop')).toBeInTheDocument()
expect(screen.getByText('troubleshoot')).toBeInTheDocument()
})

it('calls onSelect when card is clicked', () => {
const onSelect = vi.fn()
render(
<FixerCard
mission={mockMission}
onImport={vi.fn()}
onSelect={onSelect}
/>
)
const card = screen.getByText('Fix Kubernetes Pod Restart Loop').closest('div')
card?.click()
expect(onSelect).toHaveBeenCalledOnce()
Comment on lines +101 to +103
})

it('calls onImport when import button is clicked', () => {
const onImport = vi.fn()
render(
<FixerCard
mission={mockMission}
onImport={onImport}
onSelect={vi.fn()}
/>
)
screen.getByRole('button', { name: /Import/i }).click()
expect(onImport).toHaveBeenCalledOnce()
})

it('renders tags', () => {
render(
<FixerCard
mission={mockMission}
onImport={vi.fn()}
onSelect={vi.fn()}
/>
)
expect(screen.getByText('kubernetes')).toBeInTheDocument()
expect(screen.getByText('pods')).toBeInTheDocument()
expect(screen.getByText('debugging')).toBeInTheDocument()
})
})
91 changes: 91 additions & 0 deletions web/src/components/missions/InstallerCard.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { describe, it, expect, vi } from 'vitest'
import { render, screen } from '@testing-library/react'
import { InstallerCard } from './InstallerCard'
import type { MissionExport } from '../../lib/missions/types'

vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string, opts?: Record<string, unknown>) => {
const map: Record<string, string> = {
'actions.import': 'Import',
'missions.browser.stepsCount': `${opts?.count || 0} steps`,
'missions.browser.copyShareableLink': 'Copy shareable link',
}
return map[key] ?? key
},
}),
}))

const mockInstaller: MissionExport = {
title: 'Install Prometheus',
description: 'Deploy Prometheus to your cluster',
type: 'install',
cncfProject: 'prometheus',
cncfMaturity: 'graduated',
difficulty: 'beginner',
installMethods: ['helm', 'kubectl'],
steps: [{ type: 'command', command: 'helm install prometheus' }],
version: '1.0.0',
}

describe('InstallerCard', () => {
it('renders the mission title', () => {
render(
<InstallerCard
mission={mockInstaller}
onImport={vi.fn()}
onSelect={vi.fn()}
/>
)
expect(screen.getByText('Install Prometheus')).toBeInTheDocument()
})

it('renders the mission description', () => {
render(
<InstallerCard
mission={mockInstaller}
onImport={vi.fn()}
onSelect={vi.fn()}
/>
)
expect(screen.getByText(/Deploy Prometheus/)).toBeInTheDocument()
})

it('renders the import button', () => {
render(
<InstallerCard
mission={mockInstaller}
onImport={vi.fn()}
onSelect={vi.fn()}
/>
)
expect(screen.getByRole('button', { name: /Import/i })).toBeInTheDocument()
})

it('calls onSelect when card is clicked', () => {
const onSelect = vi.fn()
render(
<InstallerCard
mission={mockInstaller}
onImport={vi.fn()}
onSelect={onSelect}
/>
)
const card = screen.getByText('Install Prometheus').closest('div')
card?.click()
expect(onSelect).toHaveBeenCalledOnce()
Comment on lines +74 to +76
})

it('calls onImport when import button is clicked', () => {
const onImport = vi.fn()
render(
<InstallerCard
mission={mockInstaller}
onImport={onImport}
onSelect={vi.fn()}
/>
)
screen.getByRole('button', { name: /Import/i }).click()
expect(onImport).toHaveBeenCalledOnce()
})
})
Loading
Loading