Files
headlamp-kube-vip-plugin/src/components/ServicesPage.test.tsx
T
DevContainer User f26d1414b2 fix: resolve bugs in ServicesPage, NodesPage, and k8s helpers
- Add missing useEffect dependency array and useCallback for closePanel
- Fix invalid StatusLabel status="" to "info" for non-kube-vip services
- Add ARIA dialog attributes to service detail panel
- Use phaseToStatus() in NodesPage instead of hardcoded Running check
- Remove dead code in getNodeVipLabel (label keys never contain =)
- Simplify redundant lease lookup in OverviewPage
- Fix 46 ESLint indentation warnings
- Add CHANGELOG.md

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

119 lines
3.9 KiB
TypeScript

import { fireEvent, render, screen } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
vi.mock(
'@kinvolk/headlamp-plugin/lib/CommonComponents',
async () => await import('./__mocks__/commonComponents')
);
let mockHash = '';
const mockPush = vi.fn();
vi.mock('react-router-dom', () => ({
useLocation: () => ({ pathname: '/kube-vip/services', hash: mockHash }),
useHistory: () => ({ push: mockPush }),
}));
vi.mock('../api/KubeVipDataContext');
import { useKubeVipContext } from '../api/KubeVipDataContext';
import { defaultContext, makeSampleService } from '../test-helpers';
import ServicesPage from './ServicesPage';
function mockContext(overrides?: Parameters<typeof defaultContext>[0]) {
vi.mocked(useKubeVipContext).mockReturnValue(defaultContext(overrides));
}
describe('ServicesPage', () => {
beforeEach(() => {
mockPush.mockClear();
mockHash = '';
});
it('shows loader when loading', () => {
mockContext({ loading: true });
render(<ServicesPage />);
expect(screen.getByTestId('loader')).toHaveTextContent('Loading services...');
});
it('shows error state', () => {
mockContext({ error: 'fetch failed' });
render(<ServicesPage />);
expect(screen.getByText('fetch failed')).toBeInTheDocument();
});
it('shows empty message when no services', () => {
mockContext({ loadBalancerServices: [] });
render(<ServicesPage />);
expect(screen.getByText('No LoadBalancer services found.')).toBeInTheDocument();
});
it('renders services table', () => {
const svc = makeSampleService();
mockContext({ loadBalancerServices: [svc] });
render(<ServicesPage />);
expect(screen.getByText('my-service')).toBeInTheDocument();
expect(screen.getByText('192.168.1.200')).toBeInTheDocument();
});
it('opens detail panel when clicking service name', () => {
const svc = makeSampleService();
mockContext({ loadBalancerServices: [svc] });
render(<ServicesPage />);
fireEvent.click(screen.getByText('my-service'));
expect(mockPush).toHaveBeenCalledWith('/kube-vip/services#default/my-service');
});
it('renders detail panel when hash is set', () => {
mockHash = '#default/my-service';
const svc = makeSampleService();
mockContext({ loadBalancerServices: [svc] });
render(<ServicesPage />);
expect(screen.getByText('Service Details')).toBeInTheDocument();
});
it('closes panel via backdrop click', () => {
mockHash = '#default/my-service';
const svc = makeSampleService();
mockContext({ loadBalancerServices: [svc] });
render(<ServicesPage />);
fireEvent.click(screen.getByTestId('panel-backdrop'));
expect(mockPush).toHaveBeenCalledWith('/kube-vip/services');
});
it('closes panel on Escape key', () => {
mockHash = '#default/my-service';
const svc = makeSampleService();
mockContext({ loadBalancerServices: [svc] });
render(<ServicesPage />);
fireEvent.keyDown(window, { key: 'Escape' });
expect(mockPush).toHaveBeenCalledWith('/kube-vip/services');
});
it('shows kube-vip annotations in detail panel', () => {
mockHash = '#default/my-service';
const svc = makeSampleService();
mockContext({ loadBalancerServices: [svc] });
render(<ServicesPage />);
expect(screen.getByText('kube-vip Annotations')).toBeInTheDocument();
expect(screen.getByText('loadbalancerIPs')).toBeInTheDocument();
});
it('shows egress column for egress-enabled service', () => {
const svc = makeSampleService({
metadata: {
name: 'egress-svc',
namespace: 'default',
annotations: {
'kube-vip.io/loadbalancerIPs': '10.0.0.1',
'kube-vip.io/egress': 'true',
},
},
});
mockContext({ loadBalancerServices: [svc] });
render(<ServicesPage />);
// The "Yes" text appears in the Egress column
const cells = screen.getAllByRole('cell');
expect(cells.some(c => c.textContent === 'Yes')).toBe(true);
});
});