fix(tests): Enhance CrowdSecConfig with new input fields and improve accessibility
- Added IDs to input fields in CrowdSecConfig for better accessibility. - Updated labels to use <label> elements for checkboxes and inputs. - Improved error handling and user feedback in the CrowdSecConfig tests. - Enhanced test coverage for console enrollment and banned IP functionalities. fix: Update SecurityHeaders to include aria-label for delete button - Added aria-label to the delete button for better screen reader support. test: Add comprehensive tests for proxyHostsHelpers and validation utilities - Implemented tests for formatting and help text functions in proxyHostsHelpers. - Added validation tests for email and IP address formats. chore: Update vitest configuration for dynamic coverage thresholds - Adjusted coverage thresholds to be dynamic based on environment variables. - Included additional coverage reporters. chore: Update frontend-test-coverage script to reflect new coverage threshold - Increased minimum coverage requirement from 85% to 87.5%. fix: Ensure tests pass with consistent data in passwd file - Updated tests/etc/passwd to ensure consistent content.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import { render, screen, waitFor, within } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { act } from 'react'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
@@ -60,6 +60,50 @@ vi.mock('../../hooks/useCertificates', () => ({
|
||||
})),
|
||||
}))
|
||||
|
||||
vi.mock('../../hooks/useAccessLists', () => ({
|
||||
useAccessLists: vi.fn(() => ({
|
||||
data: [
|
||||
{ id: 10, name: 'Trusted IPs', type: 'allow_list', enabled: true, description: 'Only trusted' },
|
||||
{ id: 11, name: 'Geo Block', type: 'geo_block', enabled: true }
|
||||
],
|
||||
isLoading: false,
|
||||
error: null,
|
||||
})),
|
||||
}))
|
||||
|
||||
vi.mock('../../hooks/useSecurityHeaders', () => ({
|
||||
useSecurityHeaderProfiles: vi.fn(() => ({
|
||||
data: [
|
||||
{ id: 100, name: 'Strict Profile', description: 'Very strict', security_score: 90, is_preset: true, preset_type: 'strict' }
|
||||
],
|
||||
isLoading: false,
|
||||
error: null,
|
||||
})),
|
||||
}))
|
||||
|
||||
vi.mock('../../hooks/useDNSDetection', () => ({
|
||||
useDetectDNSProvider: vi.fn(() => ({
|
||||
mutateAsync: vi.fn(),
|
||||
isPending: false,
|
||||
data: null,
|
||||
reset: vi.fn(),
|
||||
})),
|
||||
}))
|
||||
|
||||
vi.mock('../../hooks/useDNSProviders', () => ({
|
||||
useDNSProviders: vi.fn(() => ({
|
||||
data: [
|
||||
{ id: 1, name: 'Cloudflare', provider_type: 'cloudflare', enabled: true, has_credentials: true }
|
||||
],
|
||||
isLoading: false,
|
||||
error: null,
|
||||
})),
|
||||
}))
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({ t: (key: string) => key }),
|
||||
}))
|
||||
|
||||
vi.mock('../../hooks/useSecurity', () => ({
|
||||
useAuthPolicies: vi.fn(() => ({
|
||||
policies: [
|
||||
@@ -657,4 +701,530 @@ describe('ProxyHostForm', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Security Options', () => {
|
||||
it('toggles security options', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
// Toggle SSL Forced (default is true)
|
||||
const sslCheckbox = screen.getByLabelText('Force SSL')
|
||||
expect(sslCheckbox).toBeChecked()
|
||||
await userEvent.click(sslCheckbox)
|
||||
expect(sslCheckbox).not.toBeChecked()
|
||||
|
||||
// Toggle HSTS (default is true)
|
||||
const hstsCheckbox = screen.getByLabelText('HSTS Enabled')
|
||||
expect(hstsCheckbox).toBeChecked()
|
||||
await userEvent.click(hstsCheckbox)
|
||||
expect(hstsCheckbox).not.toBeChecked()
|
||||
|
||||
// Toggle HTTP/2 (default is true)
|
||||
const http2Checkbox = screen.getByLabelText('HTTP/2 Support')
|
||||
expect(http2Checkbox).toBeChecked()
|
||||
await userEvent.click(http2Checkbox)
|
||||
expect(http2Checkbox).not.toBeChecked()
|
||||
|
||||
// Toggle Block Exploits (default is true)
|
||||
const blockExploitsCheckbox = screen.getByLabelText('Block Exploits')
|
||||
expect(blockExploitsCheckbox).toBeChecked()
|
||||
await userEvent.click(blockExploitsCheckbox)
|
||||
expect(blockExploitsCheckbox).not.toBeChecked()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Access Control', () => {
|
||||
it('selects an access list', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
// Select 'Trusted IPs'
|
||||
// Need to find the select by label/aria-label? AccessListSelector has label "Access Control List"
|
||||
const aclSelect = screen.getByLabelText(/Access Control List/i)
|
||||
await userEvent.selectOptions(aclSelect, '10')
|
||||
|
||||
// Verify it was selected
|
||||
expect(aclSelect).toHaveValue('10')
|
||||
|
||||
// Verify description appears
|
||||
expect(screen.getByText('Trusted IPs')).toBeInTheDocument()
|
||||
expect(screen.getByText('Only trusted')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Wildcard Domains', () => {
|
||||
it('shows DNS provider selector for wildcard domains', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
// Enter a wildcard domain
|
||||
const domainInput = screen.getByPlaceholderText('example.com, www.example.com')
|
||||
await userEvent.type(domainInput, '*.example.com')
|
||||
|
||||
// DNS Provider Selector should appear
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('dns-provider-section')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
// Select a provider using the mocked data: Cloudflare (ID 1)
|
||||
const section = screen.getByTestId('dns-provider-section')
|
||||
|
||||
// Since Shadcn Select uses Radix, the trigger is a button with role combobox
|
||||
const providerSelectTrigger = within(section).getByRole('combobox')
|
||||
await userEvent.click(providerSelectTrigger)
|
||||
|
||||
const cloudflareOption = screen.getByText('Cloudflare')
|
||||
await userEvent.click(cloudflareOption)
|
||||
|
||||
// Now try to save
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'Wildcard Test')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '192.168.1.10')
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '80')
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
domain_names: '*.example.com',
|
||||
dns_provider_id: 1
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
it('validates DNS provider requirement for wildcard domains', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
// Enter a wildcard domain
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), '*.missing.com')
|
||||
|
||||
// Fill other required fields
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'Missing Provider')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '192.168.1.10')
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '80')
|
||||
|
||||
// Click save without selecting provider
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
// Expect toast error (mocked only effectively if we check for it, but here we check it prevents submit)
|
||||
expect(mockOnSubmit).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
// ===== BRANCH COVERAGE EXPANSION TESTS =====
|
||||
|
||||
describe('Form Submission and Validation', () => {
|
||||
it('prevents submission without required fields', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
// Click save without filling any fields
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
// Submit should not be called
|
||||
expect(mockOnSubmit).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('submits form with all basic fields', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'My Service')
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), 'myservice.com')
|
||||
await userEvent.selectOptions(screen.getByLabelText(/^Scheme/), 'https')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '192.168.1.100')
|
||||
await userEvent.clear(screen.getByLabelText(/^Port/))
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '8080')
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
name: 'My Service',
|
||||
domain_names: 'myservice.com',
|
||||
forward_scheme: 'https',
|
||||
forward_host: '192.168.1.100',
|
||||
forward_port: 8080,
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
it('submits form with certificate selection', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'Cert Test')
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), 'cert.example.com')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '192.168.1.100')
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '80')
|
||||
|
||||
// Select certificate
|
||||
const certSelect = screen.getByLabelText(/Certificate/i)
|
||||
await userEvent.selectOptions(certSelect, '1')
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
certificate_id: 1,
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
it('submits form with security header profile selection', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'Security Headers Test')
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), 'secure.example.com')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '192.168.1.100')
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '80')
|
||||
|
||||
// Select security header profile
|
||||
const profileSelect = screen.getByLabelText(/Security Headers/i)
|
||||
await userEvent.selectOptions(profileSelect, '100')
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
security_header_profile_id: 100,
|
||||
}))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Edit Mode vs Create Mode', () => {
|
||||
it('shows edit mode with pre-filled data', async () => {
|
||||
const existingHost: ProxyHost = {
|
||||
uuid: 'host-uuid-1',
|
||||
name: 'Existing Service',
|
||||
domain_names: 'existing.com',
|
||||
forward_scheme: 'https' as const,
|
||||
forward_host: '192.168.1.50',
|
||||
forward_port: 443,
|
||||
ssl_forced: true,
|
||||
http2_support: true,
|
||||
hsts_enabled: true,
|
||||
hsts_subdomains: true,
|
||||
block_exploits: true,
|
||||
websocket_support: false,
|
||||
enable_standard_headers: true,
|
||||
application: 'none' as const,
|
||||
advanced_config: '',
|
||||
enabled: true,
|
||||
locations: [],
|
||||
certificate_id: null,
|
||||
access_list_id: null,
|
||||
security_header_profile_id: null,
|
||||
dns_provider_id: null,
|
||||
created_at: '2025-01-01T00:00:00Z',
|
||||
updated_at: '2025-01-01T00:00:00Z',
|
||||
}
|
||||
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm host={existingHost} onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
// Fields should be pre-filled
|
||||
expect(screen.getByDisplayValue('Existing Service')).toBeInTheDocument()
|
||||
expect(screen.getByDisplayValue('existing.com')).toBeInTheDocument()
|
||||
expect(screen.getByDisplayValue('192.168.1.50')).toBeInTheDocument()
|
||||
|
||||
// Update and save
|
||||
const nameInput = screen.getByDisplayValue('Existing Service') as HTMLInputElement
|
||||
await userEvent.clear(nameInput)
|
||||
await userEvent.type(nameInput, 'Updated Service')
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
name: 'Updated Service',
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
it('renders title as Edit for existing host', async () => {
|
||||
const existingHost: ProxyHost = {
|
||||
uuid: 'host-uuid-1',
|
||||
name: 'Existing',
|
||||
domain_names: 'test.com',
|
||||
forward_scheme: 'http' as const,
|
||||
forward_host: '127.0.0.1',
|
||||
forward_port: 80,
|
||||
ssl_forced: true,
|
||||
http2_support: true,
|
||||
hsts_enabled: true,
|
||||
hsts_subdomains: true,
|
||||
block_exploits: true,
|
||||
websocket_support: false,
|
||||
enable_standard_headers: true,
|
||||
application: 'none' as const,
|
||||
advanced_config: '',
|
||||
enabled: true,
|
||||
locations: [],
|
||||
certificate_id: null,
|
||||
access_list_id: null,
|
||||
security_header_profile_id: null,
|
||||
dns_provider_id: null,
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
}
|
||||
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm host={existingHost} onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
expect(screen.getByText('Edit Proxy Host')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders title as Add for new proxy host', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
expect(screen.getByText('Add Proxy Host')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Scheme Selection', () => {
|
||||
it('shows scheme options http, https, ws, wss', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
const schemeSelect = screen.getByLabelText('Scheme')
|
||||
expect(schemeSelect).toBeInTheDocument()
|
||||
|
||||
const options = schemeSelect.querySelectorAll('option')
|
||||
const values = Array.from(options).map(o => o.value)
|
||||
|
||||
expect(values).toContain('http')
|
||||
expect(values).toContain('https')
|
||||
expect(values).toContain('ws')
|
||||
expect(values).toContain('wss')
|
||||
})
|
||||
|
||||
it('accepts websockets scheme', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'WS Test')
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), 'ws.example.com')
|
||||
await userEvent.selectOptions(screen.getByLabelText('Scheme') as HTMLSelectElement, 'ws')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '192.168.1.100')
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '8000')
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
forward_scheme: 'ws',
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
it('accepts secure websockets scheme', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'WSS Test')
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), 'wss.example.com')
|
||||
await userEvent.selectOptions(screen.getByLabelText('Scheme') as HTMLSelectElement, 'wss')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '192.168.1.100')
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '8000')
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
forward_scheme: 'wss',
|
||||
}))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Cancel Operations', () => {
|
||||
it('calls onCancel when cancel button is clicked', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
const cancelBtn = screen.getByRole('button', { name: /Cancel/i })
|
||||
await userEvent.click(cancelBtn)
|
||||
|
||||
expect(mockOnCancel).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Advanced Config', () => {
|
||||
it('shows advanced config field for application presets', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
// Select Plex preset
|
||||
await userEvent.selectOptions(screen.getByLabelText(/Application Preset/i) as HTMLSelectElement, 'plex')
|
||||
|
||||
// Find advanced config field (it's in a collapsible section)
|
||||
// Check that advanced config JSON for plex has been populated
|
||||
const advancedConfigField = screen.getByPlaceholderText(/Caddy JSON config/i) as HTMLTextAreaElement
|
||||
|
||||
// Verify it contains JSON (Plex has some default config)
|
||||
if (advancedConfigField.value) {
|
||||
expect(advancedConfigField.value).toContain('handler')
|
||||
}
|
||||
})
|
||||
|
||||
it('allows manual advanced config input', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'Custom Config')
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), 'custom.example.com')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '192.168.1.100')
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '80')
|
||||
|
||||
const advancedConfigField = screen.getByPlaceholderText('Additional Caddy directives...')
|
||||
await userEvent.type(advancedConfigField, 'header /api/* X-Custom-Header "test"')
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
advanced_config: expect.stringContaining('header'),
|
||||
}))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Port Input Handling', () => {
|
||||
it('validates port number range', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'Port Test')
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), 'port.example.com')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '192.168.1.100')
|
||||
|
||||
// Clear and set invalid port
|
||||
const portInput = screen.getByLabelText(/^Port$/) as HTMLInputElement
|
||||
await userEvent.clear(portInput)
|
||||
await userEvent.type(portInput, '99999')
|
||||
|
||||
// The form should still allow submission (validation happens server-side usually)
|
||||
// But port should be converted to number
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Host and Port Combination', () => {
|
||||
it('accepts docker container IP', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'Docker Container')
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), 'docker.example.com')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '172.17.0.2')
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '8080')
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
forward_host: '172.17.0.2',
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
it('accepts localhost IP', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'Localhost')
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), 'localhost.example.com')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), 'localhost')
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '3000')
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
forward_host: 'localhost',
|
||||
}))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Enabled/Disabled State', () => {
|
||||
it('toggles enabled state', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'Enabled Test')
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), 'enabled.example.com')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '192.168.1.100')
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '80')
|
||||
|
||||
// Toggle enabled (defaults to true) - look for "Enable Proxy Host" text
|
||||
const enabledCheckbox = screen.getByLabelText(/Enable Proxy Host/)
|
||||
await userEvent.click(enabledCheckbox)
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
enabled: false,
|
||||
}))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Standard Headers Option', () => {
|
||||
it('toggles standard headers option', async () => {
|
||||
await renderWithClientAct(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
const standardHeadersCheckbox = screen.getByLabelText(/Enable Standard Proxy Headers/)
|
||||
expect(standardHeadersCheckbox).toBeChecked()
|
||||
|
||||
await userEvent.click(standardHeadersCheckbox)
|
||||
|
||||
expect(standardHeadersCheckbox).not.toBeChecked()
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^Name/), 'No Headers')
|
||||
await userEvent.type(screen.getByPlaceholderText('example.com, www.example.com'), 'no-headers.com')
|
||||
await userEvent.type(screen.getByLabelText(/^Host/), '192.168.1.100')
|
||||
await userEvent.type(screen.getByLabelText(/^Port/), '80')
|
||||
|
||||
await userEvent.click(screen.getByText('Save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
|
||||
enable_standard_headers: false,
|
||||
}))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user