Files
sencho/frontend/src/components/dashboard/__tests__/useMeshDataPlane.test.tsx
T
Anso 0cd03c6f87 chore(ui): hide Mesh, Fleet Secrets, and Host Console behind experimental discovery (#1624)
Gate Routing, Secrets, Host Console, and Mesh dashboard/settings surfaces on the existing useExperimental readiness flag so immature operator surfaces stay out of the default UI while paid and admin backend gates remain unchanged.
2026-07-13 11:55:50 -04:00

122 lines
4.4 KiB
TypeScript

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { renderHook, act } from '@testing-library/react';
const apiFetchMock = vi.fn();
vi.mock('@/lib/api', () => ({
apiFetch: (...args: unknown[]) => apiFetchMock(...args),
}));
const useLicenseMock = vi.fn();
vi.mock('@/context/LicenseContext', () => ({
useLicense: () => useLicenseMock(),
}));
const useExperimentalMock = vi.fn(() => ({ experimental: true, experimentalReady: true }));
vi.mock('@/hooks/useExperimental', () => ({
useExperimental: () => useExperimentalMock(),
}));
vi.mock('@/lib/utils', async () => {
const actual = await vi.importActual<typeof import('@/lib/utils')>('@/lib/utils');
return {
...actual,
visibilityInterval: () => () => {},
};
});
import { useMeshDataPlane } from '../useMeshDataPlane';
function okJson(payload: unknown): Response {
return new Response(JSON.stringify(payload), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
}
function statusJson(status: number, payload: unknown = {}): Response {
return new Response(JSON.stringify(payload), {
status,
headers: { 'Content-Type': 'application/json' },
});
}
beforeEach(() => {
apiFetchMock.mockReset();
useLicenseMock.mockReset();
useExperimentalMock.mockReset();
useExperimentalMock.mockReturnValue({ experimental: true, experimentalReady: true });
});
afterEach(() => {
vi.clearAllMocks();
});
describe('useMeshDataPlane', () => {
it('does not fetch /mesh/status when the session is on the free tier', async () => {
useLicenseMock.mockReturnValue({ isPaid: false });
const { result } = renderHook(() => useMeshDataPlane());
await act(async () => { await Promise.resolve(); await Promise.resolve(); });
expect(apiFetchMock).not.toHaveBeenCalled();
expect(result.current.status).toBeNull();
expect(result.current.loading).toBe(false);
});
it('fetches once on mount and surfaces the localDataPlane payload for a paid tier', async () => {
useLicenseMock.mockReturnValue({ isPaid: true });
apiFetchMock.mockResolvedValue(okJson({
localDataPlane: { ok: true, reason: null, lastChecked: 1000 },
}));
const { result } = renderHook(() => useMeshDataPlane());
await act(async () => { await Promise.resolve(); await Promise.resolve(); });
expect(apiFetchMock).toHaveBeenCalledWith('/mesh/status', expect.objectContaining({ localOnly: true }));
expect(result.current.status).toEqual({ ok: true, reason: null, lastChecked: 1000 });
expect(result.current.loading).toBe(false);
});
it('keeps status null on a 403 response without raising an error', async () => {
useLicenseMock.mockReturnValue({ isPaid: true });
apiFetchMock.mockResolvedValue(statusJson(403, { error: 'forbidden' }));
const { result } = renderHook(() => useMeshDataPlane());
await act(async () => { await Promise.resolve(); await Promise.resolve(); });
expect(result.current.status).toBeNull();
expect(result.current.loading).toBe(false);
});
it('falls back to null when the response omits localDataPlane', async () => {
useLicenseMock.mockReturnValue({ isPaid: true });
apiFetchMock.mockResolvedValue(okJson({ nodes: [] }));
const { result } = renderHook(() => useMeshDataPlane());
await act(async () => { await Promise.resolve(); await Promise.resolve(); });
expect(result.current.status).toBeNull();
expect(result.current.loading).toBe(false);
});
it('does not fetch when paid but experimental discovery is off', async () => {
useLicenseMock.mockReturnValue({ isPaid: true });
useExperimentalMock.mockReturnValue({ experimental: false, experimentalReady: true });
const { result } = renderHook(() => useMeshDataPlane());
await act(async () => { await Promise.resolve(); await Promise.resolve(); });
expect(apiFetchMock).not.toHaveBeenCalled();
expect(result.current.status).toBeNull();
expect(result.current.loading).toBe(false);
});
it('does not fetch while experimental metadata is still loading', async () => {
useLicenseMock.mockReturnValue({ isPaid: true });
useExperimentalMock.mockReturnValue({ experimental: false, experimentalReady: false });
const { result } = renderHook(() => useMeshDataPlane());
await act(async () => { await Promise.resolve(); await Promise.resolve(); });
expect(apiFetchMock).not.toHaveBeenCalled();
expect(result.current.status).toBeNull();
});
});