9d9bc5f22f
- Fix handleRotate bug ignoring Result from rotateSealedSecret() - Fix dead code branch in useControllerHealth - Replace all `any` types with `unknown` + type guards - Delete unused functions/exports (452 lines removed) - Add 18 new test files covering all hooks, libs, and components - 233 tests passing, zero tsc errors, zero lint issues Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
188 lines
4.5 KiB
TypeScript
188 lines
4.5 KiB
TypeScript
/**
|
|
* Unit tests for useControllerHealth hook
|
|
*/
|
|
|
|
import { act, renderHook } from '@testing-library/react';
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
// Mock controller module
|
|
vi.mock('../lib/controller', () => ({
|
|
checkControllerHealth: vi.fn(),
|
|
getPluginConfig: vi.fn().mockReturnValue({
|
|
controllerName: 'sealed-secrets-controller',
|
|
controllerNamespace: 'kube-system',
|
|
controllerPort: 8080,
|
|
}),
|
|
}));
|
|
|
|
import { checkControllerHealth } from '../lib/controller';
|
|
import { useControllerHealth } from './useControllerHealth';
|
|
|
|
const mockCheckHealth = vi.mocked(checkControllerHealth);
|
|
|
|
describe('useControllerHealth', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
it('should start in loading state', () => {
|
|
mockCheckHealth.mockReturnValue(new Promise(() => {}));
|
|
|
|
const { result } = renderHook(() => useControllerHealth());
|
|
|
|
expect(result.current.loading).toBe(true);
|
|
expect(result.current.health).toBe(null);
|
|
});
|
|
|
|
it('should fetch health on mount', async () => {
|
|
mockCheckHealth.mockResolvedValue({
|
|
ok: true,
|
|
value: {
|
|
healthy: true,
|
|
reachable: true,
|
|
version: '0.24.0',
|
|
latencyMs: 42,
|
|
},
|
|
});
|
|
|
|
const { result } = renderHook(() => useControllerHealth());
|
|
|
|
await act(async () => {
|
|
await vi.runAllTimersAsync();
|
|
});
|
|
|
|
expect(result.current.loading).toBe(false);
|
|
expect(result.current.health).toEqual({
|
|
healthy: true,
|
|
reachable: true,
|
|
version: '0.24.0',
|
|
latencyMs: 42,
|
|
});
|
|
});
|
|
|
|
it('should handle error result', async () => {
|
|
mockCheckHealth.mockResolvedValue({
|
|
ok: false,
|
|
error: 'Controller unreachable',
|
|
});
|
|
|
|
const { result } = renderHook(() => useControllerHealth());
|
|
|
|
await act(async () => {
|
|
await vi.runAllTimersAsync();
|
|
});
|
|
|
|
expect(result.current.loading).toBe(false);
|
|
expect(result.current.health).toEqual({
|
|
healthy: false,
|
|
reachable: false,
|
|
error: 'Controller unreachable',
|
|
});
|
|
});
|
|
|
|
it('should auto-refresh at specified interval', async () => {
|
|
mockCheckHealth.mockResolvedValue({
|
|
ok: true,
|
|
value: { healthy: true, reachable: true },
|
|
});
|
|
|
|
renderHook(() => useControllerHealth(true, 10000));
|
|
|
|
// Initial call
|
|
await act(async () => {
|
|
await vi.advanceTimersByTimeAsync(1);
|
|
});
|
|
|
|
expect(mockCheckHealth).toHaveBeenCalledTimes(1);
|
|
|
|
// Advance timer by refresh interval
|
|
await act(async () => {
|
|
await vi.advanceTimersByTimeAsync(10000);
|
|
});
|
|
|
|
expect(mockCheckHealth).toHaveBeenCalledTimes(2);
|
|
|
|
// Another interval
|
|
await act(async () => {
|
|
await vi.advanceTimersByTimeAsync(10000);
|
|
});
|
|
|
|
expect(mockCheckHealth).toHaveBeenCalledTimes(3);
|
|
});
|
|
|
|
it('should not auto-refresh by default', async () => {
|
|
mockCheckHealth.mockResolvedValue({
|
|
ok: true,
|
|
value: { healthy: true, reachable: true },
|
|
});
|
|
|
|
renderHook(() => useControllerHealth());
|
|
|
|
await act(async () => {
|
|
await vi.runAllTimersAsync();
|
|
});
|
|
|
|
expect(mockCheckHealth).toHaveBeenCalledTimes(1);
|
|
|
|
await act(async () => {
|
|
vi.advanceTimersByTime(60000);
|
|
await vi.runAllTimersAsync();
|
|
});
|
|
|
|
// Still just 1 call - no auto-refresh
|
|
expect(mockCheckHealth).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should provide manual refresh function', async () => {
|
|
mockCheckHealth.mockResolvedValue({
|
|
ok: true,
|
|
value: { healthy: true, reachable: true },
|
|
});
|
|
|
|
const { result } = renderHook(() => useControllerHealth());
|
|
|
|
await act(async () => {
|
|
await vi.runAllTimersAsync();
|
|
});
|
|
|
|
expect(mockCheckHealth).toHaveBeenCalledTimes(1);
|
|
|
|
// Manual refresh
|
|
await act(async () => {
|
|
result.current.refresh();
|
|
await vi.runAllTimersAsync();
|
|
});
|
|
|
|
expect(mockCheckHealth).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it('should cleanup interval on unmount', async () => {
|
|
mockCheckHealth.mockResolvedValue({
|
|
ok: true,
|
|
value: { healthy: true, reachable: true },
|
|
});
|
|
|
|
const { unmount } = renderHook(() => useControllerHealth(true, 5000));
|
|
|
|
await act(async () => {
|
|
await vi.advanceTimersByTimeAsync(1);
|
|
});
|
|
|
|
expect(mockCheckHealth).toHaveBeenCalledTimes(1);
|
|
|
|
unmount();
|
|
|
|
// Advance time - no more calls after unmount
|
|
await act(async () => {
|
|
await vi.advanceTimersByTimeAsync(15000);
|
|
});
|
|
|
|
expect(mockCheckHealth).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|