Files
headlamp-kube-vip-plugin/src/components/OverviewPage.test.tsx
T
DevContainer User 3b9d007e8b feat: initial kube-vip Headlamp plugin
Headlamp plugin providing visibility into kube-vip virtual IP and load
balancer deployments. Features:

- Overview dashboard with deployment status, VIP mode, leader election
- Services page with LoadBalancer VIP assignments and detail panels
- Nodes page showing kube-vip pod status and leader designation
- Configuration page with DaemonSet config, IP pools, leases
- Service detail section injected into native Headlamp Service views

Read-only plugin — no cluster write operations. Uses standard K8s
resources (no CRDs): Services, Nodes, Pods, DaemonSets, Leases,
ConfigMaps with kube-vip.io/* annotations.

74 tests across 7 test files. All tsc/lint/format/test checks pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 00:23:08 +00:00

125 lines
3.9 KiB
TypeScript

import { render, screen } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
vi.mock(
'@kinvolk/headlamp-plugin/lib/CommonComponents',
async () => await import('./__mocks__/commonComponents')
);
vi.mock('../api/KubeVipDataContext');
import { useKubeVipContext } from '../api/KubeVipDataContext';
import {
defaultContext,
makeSampleLease,
makeSampleNode,
makeSamplePod,
makeSampleService,
} from '../test-helpers';
import OverviewPage from './OverviewPage';
function mockContext(overrides?: Parameters<typeof defaultContext>[0]) {
vi.mocked(useKubeVipContext).mockReturnValue(defaultContext(overrides));
}
describe('OverviewPage', () => {
it('shows loader when loading', () => {
mockContext({ loading: true });
render(<OverviewPage />);
expect(screen.getByTestId('loader')).toHaveTextContent('Loading kube-vip data...');
});
it('shows error state', () => {
mockContext({ error: 'api error' });
render(<OverviewPage />);
expect(screen.getByText('api error')).toBeInTheDocument();
});
it('shows "not detected" when kube-vip is not installed', () => {
mockContext({ kubeVipInstalled: false });
render(<OverviewPage />);
expect(screen.getByText('kube-vip Not Detected')).toBeInTheDocument();
});
it('renders deployment info when installed', () => {
const pod = makeSamplePod();
mockContext({
kubeVipInstalled: true,
kubeVipPods: [pod],
kubeVipConfig: {
vip_arp: 'true',
cp_enable: 'true',
svc_enable: 'true',
address: '192.168.1.100',
},
});
render(<OverviewPage />);
expect(screen.getByText('Deployment')).toBeInTheDocument();
expect(screen.getByText('ARP')).toBeInTheDocument();
expect(screen.getByText('192.168.1.100')).toBeInTheDocument();
});
it('renders LoadBalancer services table', () => {
const svc = makeSampleService();
mockContext({
kubeVipInstalled: true,
kubeVipPods: [makeSamplePod()],
loadBalancerServices: [svc],
});
render(<OverviewPage />);
expect(screen.getByText('my-service')).toBeInTheDocument();
expect(screen.getByText('192.168.1.200')).toBeInTheDocument();
});
it('renders IP pools when available', () => {
mockContext({
kubeVipInstalled: true,
kubeVipPods: [makeSamplePod()],
ipPools: [
{ name: 'range-global', type: 'range', value: '10.0.0.100-10.0.0.200', scope: 'global' },
],
});
render(<OverviewPage />);
expect(screen.getByText('range-global')).toBeInTheDocument();
expect(screen.getByText('10.0.0.100-10.0.0.200')).toBeInTheDocument();
});
it('shows cluster summary with node counts', () => {
const node = makeSampleNode();
const workerNode = makeSampleNode({
metadata: { name: 'worker-1', labels: { 'kubernetes.io/hostname': 'worker-1' } },
});
mockContext({
kubeVipInstalled: true,
kubeVipPods: [makeSamplePod()],
nodes: [node, workerNode],
});
render(<OverviewPage />);
expect(screen.getByText('Cluster Summary')).toBeInTheDocument();
});
it('shows leader from leases', () => {
const lease = makeSampleLease();
mockContext({
kubeVipInstalled: true,
kubeVipPods: [makeSamplePod()],
leases: [lease],
kubeVipConfig: { vip_arp: 'true', cp_enable: 'true', svc_enable: 'true' },
});
render(<OverviewPage />);
// "node-1" appears in both the Leader row and the pod table Node column;
// verify it appears at least twice (leader + pod row)
expect(screen.getAllByText('node-1').length).toBeGreaterThanOrEqual(2);
});
it('detects BGP mode', () => {
mockContext({
kubeVipInstalled: true,
kubeVipPods: [makeSamplePod()],
kubeVipConfig: { bgp_enable: 'true', cp_enable: 'true', svc_enable: 'true' },
});
render(<OverviewPage />);
expect(screen.getByText('BGP')).toBeInTheDocument();
});
});