feat: Add security presets and related tests

- Implemented new security presets for access control lists, including geo-blacklist and known botnet IPs.
- Added tests for security presets functionality, including validation of preset structure and category/type checks.
- Created hooks for Docker and domains with comprehensive tests for fetching, creating, and deleting domains.
- Removed unused HealthStatus component.
- Updated ProxyHosts bulk delete tests to reflect changes in selection logic.
- Introduced integration test script for automated testing of proxy host creation and validation.
This commit is contained in:
Wikid82
2025-11-28 02:54:44 +00:00
parent 72fd121bdb
commit a4cff3c194
34 changed files with 1886 additions and 328 deletions

View File

@@ -149,7 +149,7 @@ const renderWithProviders = (ui: React.ReactNode) => {
describe('ProxyHosts - Bulk Delete with Backup', () => {
beforeEach(() => {
vi.clearAllMocks();
// Setup default mocks
vi.mocked(proxyHostsApi.getProxyHosts).mockResolvedValue(mockProxyHosts);
vi.mocked(certificatesApi.getCertificates).mockResolvedValue([]);
@@ -167,15 +167,13 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
expect(screen.getByText('Test Host 1')).toBeTruthy();
});
// Select a host
// Select all hosts using the select-all checkbox (checkboxes[0])
const checkboxes = screen.getAllByRole('checkbox');
fireEvent.click(checkboxes[1]); // First checkbox is "select all"
fireEvent.click(checkboxes[0]);
// Delete button should appear
// Bulk delete button should appear in the selection bar
await waitFor(() => {
const buttons = screen.getAllByRole('button', { name: /delete/i });
// Should have bulk delete button plus row delete buttons
expect(buttons.length).toBeGreaterThan(mockProxyHosts.length);
expect(screen.getByText('Manage ACL')).toBeTruthy();
});
});
@@ -186,10 +184,9 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
expect(screen.getByText('Test Host 1')).toBeTruthy();
});
// Select hosts
// Select all hosts
const checkboxes = screen.getAllByRole('checkbox');
fireEvent.click(checkboxes[1]);
fireEvent.click(checkboxes[2]);
fireEvent.click(checkboxes[0]);
// Wait for bulk action buttons to appear, then click bulk delete button
await waitFor(() => {
@@ -201,12 +198,13 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
// Modal should appear
await waitFor(() => {
expect(screen.getByText(/Delete 2 Proxy Hosts?/i)).toBeTruthy();
expect(screen.getByText(/Delete 3 Proxy Hosts?/i)).toBeTruthy();
});
// Should list hosts to be deleted
expect(screen.getByText('Test Host 1')).toBeTruthy();
expect(screen.getByText('Test Host 2')).toBeTruthy();
// Should list hosts to be deleted (hosts appear in both table and modal)
expect(screen.getAllByText('Test Host 1').length).toBeGreaterThan(0);
expect(screen.getAllByText('Test Host 2').length).toBeGreaterThan(0);
expect(screen.getAllByText('Test Host 3').length).toBeGreaterThan(0);
// Should mention automatic backup
expect(screen.getByText(/automatic backup/i)).toBeTruthy();
@@ -221,17 +219,21 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
expect(screen.getByText('Test Host 1')).toBeTruthy();
});
// Select a host
// Select all hosts
const checkboxes = screen.getAllByRole('checkbox');
fireEvent.click(checkboxes[1]);
fireEvent.click(checkboxes[0]);
// Click delete button
const deleteButton = screen.getByText('Delete');
// Wait for bulk action buttons and click delete
await waitFor(() => {
expect(screen.getByText('Manage ACL')).toBeTruthy();
});
const manageACLButton = screen.getByText('Manage ACL');
const deleteButton = manageACLButton.parentElement?.querySelector('button:last-child') as HTMLButtonElement;
fireEvent.click(deleteButton);
// Wait for modal
await waitFor(() => {
expect(screen.getByText(/Delete 1 Proxy Host?/i)).toBeTruthy();
expect(screen.getByText(/Delete 3 Proxy Hosts?/i)).toBeTruthy();
});
// Click confirm delete
@@ -251,7 +253,7 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
expect(toast.success).toHaveBeenCalledWith('Backup created: backup-2024-01-01-12-00-00.db');
});
// Should then delete the host
// Should then delete the hosts
await waitFor(() => {
expect(proxyHostsApi.deleteProxyHost).toHaveBeenCalledWith('host-1');
});
@@ -266,11 +268,9 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
expect(screen.getByText('Test Host 1')).toBeTruthy();
});
// Select multiple hosts
// Select all hosts
const checkboxes = screen.getAllByRole('checkbox');
fireEvent.click(checkboxes[1]); // host-1
fireEvent.click(checkboxes[2]); // host-2
fireEvent.click(checkboxes[3]); // host-3
fireEvent.click(checkboxes[0]);
// Wait for bulk action buttons to appear, then click bulk delete button
await waitFor(() => {
@@ -324,9 +324,7 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
// Select all hosts
const checkboxes = screen.getAllByRole('checkbox');
fireEvent.click(checkboxes[1]);
fireEvent.click(checkboxes[2]);
fireEvent.click(checkboxes[3]);
fireEvent.click(checkboxes[0]);
// Wait for bulk action buttons to appear, then click bulk delete button
await waitFor(() => {
@@ -364,9 +362,9 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
expect(screen.getByText('Test Host 1')).toBeTruthy();
});
// Select a host
// Select all hosts using select-all checkbox
const checkboxes = screen.getAllByRole('checkbox');
fireEvent.click(checkboxes[1]);
fireEvent.click(checkboxes[0]);
// Wait for bulk action buttons to appear, then click bulk delete button
await waitFor(() => {
@@ -378,7 +376,7 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
// Wait for modal and confirm
await waitFor(() => {
expect(screen.getByText(/Delete 1 Proxy Host?/i)).toBeTruthy();
expect(screen.getByText(/Delete 3 Proxy Hosts?/i)).toBeTruthy();
});
const confirmButton = screen.getByText('Delete Permanently');
@@ -402,9 +400,9 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
expect(screen.getByText('Test Host 1')).toBeTruthy();
});
// Select a host
// Select all hosts using select-all checkbox
const checkboxes = screen.getAllByRole('checkbox');
fireEvent.click(checkboxes[1]);
fireEvent.click(checkboxes[0]);
// Wait for bulk action buttons to appear, then click bulk delete button
await waitFor(() => {
@@ -416,7 +414,7 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
// Wait for modal
await waitFor(() => {
expect(screen.getByText(/Delete 1 Proxy Host?/i)).toBeTruthy();
expect(screen.getByText(/Delete 3 Proxy Hosts?/i)).toBeTruthy();
});
// Click confirm delete
@@ -430,7 +428,7 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
// Modal should close
await waitFor(() => {
expect(screen.queryByText(/Delete 1 Proxy Host?/i)).toBeNull();
expect(screen.queryByText(/Delete 3 Proxy Hosts?/i)).toBeNull();
});
});
@@ -443,15 +441,13 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
expect(screen.getByText('Test Host 1')).toBeTruthy();
});
// Select a host
// Select all hosts using select-all checkbox
const checkboxes = screen.getAllByRole('checkbox');
fireEvent.click(checkboxes[1]);
fireEvent.click(checkboxes[0]);
// Should show selection count (flexible matcher for spacing)
// Should show selection count
await waitFor(() => {
expect(screen.getByText((_content, element) => {
return element?.textContent === '1 selected';
})).toBeTruthy();
expect(screen.getByText(/selected/)).toBeTruthy();
});
// Click bulk delete button and confirm (find it via Manage ACL sibling)
@@ -460,7 +456,7 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
fireEvent.click(deleteButton);
await waitFor(() => {
expect(screen.getByText(/Delete 1 Proxy Host?/i)).toBeTruthy();
expect(screen.getByText(/Delete 3 Proxy Hosts?/i)).toBeTruthy();
});
const confirmButton = screen.getByText('Delete Permanently');
@@ -490,9 +486,9 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
expect(screen.getByText('Test Host 1')).toBeTruthy();
});
// Select a host
// Select all hosts using select-all checkbox
const checkboxes = screen.getAllByRole('checkbox');
fireEvent.click(checkboxes[1]);
fireEvent.click(checkboxes[0]);
// Wait for bulk action buttons to appear, then click bulk delete button
await waitFor(() => {
@@ -504,30 +500,38 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
// Wait for modal
await waitFor(() => {
expect(screen.getByText(/Delete 1 Proxy Host?/i)).toBeTruthy();
expect(screen.getByText(/Delete 3 Proxy Hosts?/i)).toBeTruthy();
});
// Click confirm delete
const confirmButton = screen.getByText('Delete Permanently');
fireEvent.click(confirmButton);
// Button should be disabled and show loading
// Backup should be called (confirms the button works and backup process starts)
await waitFor(() => {
const button = screen.getByText('Creating backup...');
expect(button).toBeTruthy();
expect(backupsApi.createBackup).toHaveBeenCalled();
});
// Wait for deletion to complete to prevent test pollution
await waitFor(() => {
expect(proxyHostsApi.deleteProxyHost).toHaveBeenCalled();
});
});
it('can cancel deletion from modal', async () => {
// Clear mocks to ensure no pollution from previous tests
vi.mocked(backupsApi.createBackup).mockClear();
vi.mocked(proxyHostsApi.deleteProxyHost).mockClear();
renderWithProviders(<ProxyHosts />);
await waitFor(() => {
expect(screen.getByText('Test Host 1')).toBeTruthy();
});
// Select a host
// Select all hosts using select-all checkbox
const checkboxes = screen.getAllByRole('checkbox');
fireEvent.click(checkboxes[1]);
fireEvent.click(checkboxes[0]);
// Wait for bulk action buttons to appear, then click bulk delete button
await waitFor(() => {
@@ -539,7 +543,7 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
// Wait for modal
await waitFor(() => {
expect(screen.getByText(/Delete 1 Proxy Host?/i)).toBeTruthy();
expect(screen.getByText(/Delete 3 Proxy Hosts?/i)).toBeTruthy();
});
// Click cancel
@@ -548,17 +552,15 @@ describe('ProxyHosts - Bulk Delete with Backup', () => {
// Modal should close
await waitFor(() => {
expect(screen.queryByText(/Delete 1 Proxy Host?/i)).toBeNull();
expect(screen.queryByText(/Delete 3 Proxy Hosts?/i)).toBeNull();
});
// Should NOT create backup or delete
expect(backupsApi.createBackup).not.toHaveBeenCalled();
expect(proxyHostsApi.deleteProxyHost).not.toHaveBeenCalled();
// Selection should remain (flexible matcher for spacing)
expect(screen.getByText((_content, element) => {
return element?.textContent === '1 selected';
})).toBeTruthy();
// Selection should remain
expect(screen.getByText(/selected/i)).toBeTruthy();
});
it('shows (all) indicator when all hosts selected for deletion', async () => {