feat(tests): add comprehensive tests for ProxyHosts and Uptime components

- Introduced isolated coverage tests for ProxyHosts with various scenarios including rendering, bulk apply, and link behavior.
- Enhanced existing ProxyHosts coverage tests to include additional assertions and error handling.
- Added tests for Uptime component to verify rendering and monitoring toggling functionality.
- Created utility functions for setting labels and help texts related to proxy host settings.
- Implemented bulk settings application logic with progress tracking and error handling.
- Added toast utility tests to ensure callback functionality and ID incrementing.
- Improved type safety in test files by using appropriate TypeScript types.
This commit is contained in:
GitHub Actions
2025-11-30 15:17:38 +00:00
parent d80f545a6e
commit 224a53975d
38 changed files with 1821 additions and 233 deletions
@@ -0,0 +1,34 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import client from '../../api/client'
import { getBackups, createBackup, restoreBackup, deleteBackup } from '../backups'
describe('backups api', () => {
beforeEach(() => {
vi.restoreAllMocks()
})
it('getBackups returns list', async () => {
const mockData = [{ filename: 'b1.zip', size: 123, time: '2025-01-01T00:00:00Z' }]
vi.spyOn(client, 'get').mockResolvedValueOnce({ data: mockData })
const res = await getBackups()
expect(res).toEqual(mockData)
})
it('createBackup returns filename', async () => {
vi.spyOn(client, 'post').mockResolvedValueOnce({ data: { filename: 'b2.zip' } })
const res = await createBackup()
expect(res).toEqual({ filename: 'b2.zip' })
})
it('restoreBackup posts to restore endpoint', async () => {
const spy = vi.spyOn(client, 'post').mockResolvedValueOnce({})
await restoreBackup('b3.zip')
expect(spy).toHaveBeenCalledWith('/backups/b3.zip/restore')
})
it('deleteBackup deletes backup', async () => {
const spy = vi.spyOn(client, 'delete').mockResolvedValueOnce({})
await deleteBackup('b3.zip')
expect(spy).toHaveBeenCalledWith('/backups/b3.zip')
})
})
+2 -2
View File
@@ -15,12 +15,12 @@ describe('featureFlags API', () => {
it('fetches feature flags', async () => {
const flags = await getFeatureFlags()
expect(flags['feature.global.enabled']).toBe(true)
expect((client.get as any)).toHaveBeenCalled()
expect(vi.mocked(client.get)).toHaveBeenCalled()
})
it('updates feature flags', async () => {
const resp = await updateFeatureFlags({ 'feature.global.enabled': false })
expect(resp).toEqual({ status: 'ok' })
expect((client.put as any)).toHaveBeenCalledWith('/feature-flags', { 'feature.global.enabled': false })
expect(vi.mocked(client.put)).toHaveBeenCalledWith('/feature-flags', { 'feature.global.enabled': false })
})
})
+10 -5
View File
@@ -40,12 +40,17 @@ export const testProvider = async (provider: Partial<NotificationProvider>) => {
};
export const getTemplates = async () => {
const response = await client.get('/notifications/templates');
const response = await client.get<NotificationTemplate[]>('/notifications/templates');
return response.data;
};
export const previewProvider = async (provider: Partial<NotificationProvider>, data?: Record<string, any>) => {
const payload: any = { ...provider };
export interface NotificationTemplate {
id: string;
name: string;
}
export const previewProvider = async (provider: Partial<NotificationProvider>, data?: Record<string, unknown>) => {
const payload: Record<string, unknown> = { ...provider } as Record<string, unknown>;
if (data) payload.data = data;
const response = await client.post('/notifications/providers/preview', payload);
return response.data;
@@ -80,8 +85,8 @@ export const deleteExternalTemplate = async (id: string) => {
await client.delete(`/notifications/external-templates/${id}`);
};
export const previewExternalTemplate = async (templateId?: string, template?: string, data?: Record<string, any>) => {
const payload: any = {};
export const previewExternalTemplate = async (templateId?: string, template?: string, data?: Record<string, unknown>) => {
const payload: Record<string, unknown> = {};
if (templateId) payload.template_id = templateId;
if (template) payload.template = template;
if (data) payload.data = data;
+3 -2
View File
@@ -64,8 +64,9 @@ export const updateProxyHost = async (uuid: string, host: Partial<ProxyHost>): P
return data;
};
export const deleteProxyHost = async (uuid: string): Promise<void> => {
await client.delete(`/proxy-hosts/${uuid}`);
export const deleteProxyHost = async (uuid: string, deleteUptime?: boolean): Promise<void> => {
const url = `/proxy-hosts/${uuid}${deleteUptime ? '?delete_uptime=true' : ''}`
await client.delete(url);
};
export const testProxyHostConnection = async (host: string, port: number): Promise<void> => {
+12 -1
View File
@@ -2,6 +2,7 @@ import client from './client';
export interface UptimeMonitor {
id: string;
upstream_host?: string;
proxy_host_id?: number;
remote_server_id?: number;
name: string;
@@ -10,7 +11,7 @@ export interface UptimeMonitor {
interval: number;
enabled: boolean;
status: string;
last_check: string;
last_check?: string | null;
latency: number;
max_retries: number;
}
@@ -38,3 +39,13 @@ export const updateMonitor = async (id: string, data: Partial<UptimeMonitor>) =>
const response = await client.put<UptimeMonitor>(`/uptime/monitors/${id}`, data);
return response.data;
};
export const deleteMonitor = async (id: string) => {
const response = await client.delete<void>(`/uptime/monitors/${id}`);
return response.data;
};
export async function syncMonitors(body?: { interval?: number; max_retries?: number }) {
const res = await client.post('/uptime/sync', body || {});
return res.data;
}