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:
GitHub Actions
2026-02-06 17:38:08 +00:00
parent 57c3a70007
commit 10582872f9
34 changed files with 4197 additions and 724 deletions

View File

@@ -0,0 +1,143 @@
import {
formatSettingLabel,
settingHelpText,
settingKeyToField,
applyBulkSettingsToHosts,
} from '../proxyHostsHelpers'
import type { ProxyHost } from '../../api/proxyHosts'
import { vi } from 'vitest'
describe('proxyHostsHelpers', () => {
describe('formatSettingLabel', () => {
it('returns correct labels for known keys', () => {
expect(formatSettingLabel('ssl_forced')).toBe('Force SSL')
expect(formatSettingLabel('http2_support')).toBe('HTTP/2 Support')
expect(formatSettingLabel('hsts_enabled')).toBe('HSTS Enabled')
expect(formatSettingLabel('hsts_subdomains')).toBe('HSTS Subdomains')
expect(formatSettingLabel('block_exploits')).toBe('Block Exploits')
expect(formatSettingLabel('websocket_support')).toBe('Websockets Support')
expect(formatSettingLabel('enable_standard_headers')).toBe('Standard Proxy Headers')
})
it('returns key for unknown keys', () => {
expect(formatSettingLabel('unknown_key')).toBe('unknown_key')
})
})
describe('settingHelpText', () => {
it('returns correct help text for known keys', () => {
expect(settingHelpText('ssl_forced')).toContain('Redirect all HTTP traffic')
expect(settingHelpText('http2_support')).toContain('Enable HTTP/2')
expect(settingHelpText('block_exploits')).toContain('Add common exploit-mitigation')
})
it('returns empty string for unknown keys', () => {
expect(settingHelpText('unknown_key')).toBe('')
})
})
describe('settingKeyToField', () => {
it('returns correct field for known keys', () => {
expect(settingKeyToField('ssl_forced')).toBe('ssl_forced')
expect(settingKeyToField('websocket_support')).toBe('websocket_support')
})
it('returns key for unknown keys', () => {
expect(settingKeyToField('unknown_key')).toBe('unknown_key')
})
})
describe('applyBulkSettingsToHosts', () => {
const mockHosts: ProxyHost[] = [
{ uuid: 'h1', is_enabled: true } as unknown as ProxyHost,
{ uuid: 'h2', is_enabled: false } as unknown as ProxyHost
]
const mockUpdateHost = vi.fn()
const mockSetProgress = vi.fn()
beforeEach(() => {
vi.clearAllMocks()
})
it('applies settings to specified hosts', async () => {
mockUpdateHost.mockResolvedValue({} as ProxyHost)
const result = await applyBulkSettingsToHosts({
hosts: mockHosts,
hostUUIDs: ['h1'],
keysToApply: ['ssl_forced'],
bulkApplySettings: {
ssl_forced: { apply: true, value: true }
},
updateHost: mockUpdateHost,
setApplyProgress: mockSetProgress
})
expect(result).toEqual({ errors: 0, completed: 1 })
expect(mockUpdateHost).toHaveBeenCalledWith('h1', expect.objectContaining({
uuid: 'h1',
ssl_forced: true
}))
expect(mockUpdateHost).toHaveBeenCalledTimes(1)
expect(mockSetProgress).toHaveBeenCalled()
})
it('handles errors during update', async () => {
mockUpdateHost.mockRejectedValue(new Error('Update failed'))
const result = await applyBulkSettingsToHosts({
hosts: mockHosts,
hostUUIDs: ['h1'],
keysToApply: ['ssl_forced'],
bulkApplySettings: {
ssl_forced: { apply: true, value: true }
},
updateHost: mockUpdateHost
})
expect(result).toEqual({ errors: 1, completed: 1 })
})
it('handles missing hosts', async () => {
const result = await applyBulkSettingsToHosts({
hosts: mockHosts,
// h3 doesn't exist
hostUUIDs: ['h3'],
keysToApply: ['ssl_forced'],
bulkApplySettings: {
ssl_forced: { apply: true, value: true }
},
updateHost: mockUpdateHost
})
expect(result).toEqual({ errors: 1, completed: 1 })
expect(mockUpdateHost).not.toHaveBeenCalled()
})
it('handles multiple hosts and settings', async () => {
mockUpdateHost.mockResolvedValue({} as ProxyHost)
const result = await applyBulkSettingsToHosts({
hosts: mockHosts,
hostUUIDs: ['h1', 'h2'],
keysToApply: ['ssl_forced', 'http2_support'],
bulkApplySettings: {
ssl_forced: { apply: true, value: true },
http2_support: { apply: true, value: false }
},
updateHost: mockUpdateHost,
setApplyProgress: mockSetProgress
})
expect(result).toEqual({ errors: 0, completed: 2 })
expect(mockUpdateHost).toHaveBeenCalledWith('h1', expect.objectContaining({
uuid: 'h1',
ssl_forced: true,
http2_support: false
}))
expect(mockUpdateHost).toHaveBeenCalledWith('h2', expect.objectContaining({
uuid: 'h2',
ssl_forced: true,
http2_support: false
}))
expect(mockUpdateHost).toHaveBeenCalledTimes(2)
})
})
})

View File

@@ -0,0 +1,89 @@
import {
isValidEmail,
isIPv4,
isPrivateOrDockerIP,
isLikelyDockerContainerIP,
} from '../validation'
describe('validation utils', () => {
describe('isValidEmail', () => {
it('returns true for valid emails', () => {
expect(isValidEmail('test@example.com')).toBe(true)
expect(isValidEmail('user.name@domain.co.uk')).toBe(true)
expect(isValidEmail('user+regex@domain.com')).toBe(true)
})
it('returns false for invalid emails', () => {
expect(isValidEmail('invalid')).toBe(false)
expect(isValidEmail('invalid@')).toBe(false)
expect(isValidEmail('@domain.com')).toBe(false)
expect(isValidEmail('user@domain')).toBe(false)
expect(isValidEmail('')).toBe(false)
})
})
describe('isIPv4', () => {
it('returns true for valid IPv4 addresses', () => {
expect(isIPv4('192.168.1.1')).toBe(true)
expect(isIPv4('10.0.0.1')).toBe(true)
expect(isIPv4('0.0.0.0')).toBe(true)
expect(isIPv4('255.255.255.255')).toBe(true)
})
it('returns false for invalid IPv4 addresses', () => {
expect(isIPv4('256.0.0.1')).toBe(false)
expect(isIPv4('1.2.3')).toBe(false)
expect(isIPv4('1.2.3.4.5')).toBe(false)
expect(isIPv4('1.2.3.4.')).toBe(false)
expect(isIPv4('abc')).toBe(false)
expect(isIPv4('192.168.1.a')).toBe(false)
expect(isIPv4('')).toBe(false)
})
})
describe('isPrivateOrDockerIP', () => {
it('returns true for private IP ranges', () => {
expect(isPrivateOrDockerIP('10.0.0.1')).toBe(true)
expect(isPrivateOrDockerIP('10.255.255.255')).toBe(true)
expect(isPrivateOrDockerIP('192.168.0.1')).toBe(true)
expect(isPrivateOrDockerIP('192.168.255.255')).toBe(true)
expect(isPrivateOrDockerIP('172.16.0.1')).toBe(true) // Start of 172.16.x.x
expect(isPrivateOrDockerIP('172.31.255.255')).toBe(true) // End of 172.31.x.x
})
it('returns false for public or non-private IP ranges', () => {
expect(isPrivateOrDockerIP('8.8.8.8')).toBe(false)
expect(isPrivateOrDockerIP('1.1.1.1')).toBe(false)
expect(isPrivateOrDockerIP('172.15.0.1')).toBe(false) // Below 172.16...
expect(isPrivateOrDockerIP('172.32.0.1')).toBe(false) // Above 172.31...
expect(isPrivateOrDockerIP('192.167.1.1')).toBe(false)
expect(isPrivateOrDockerIP('192.169.1.1')).toBe(false)
})
it('returns false for invalid IPs', () => {
expect(isPrivateOrDockerIP('invalid')).toBe(false)
expect(isPrivateOrDockerIP('999.999.999.999')).toBe(false)
})
})
describe('isLikelyDockerContainerIP', () => {
it('returns true for likely Docker IPs', () => {
// Docker default bridge: 172.17.x.x
expect(isLikelyDockerContainerIP('172.17.0.2')).toBe(true)
// Docker user-defined: 172.18.x.x - 172.31.x.x
expect(isLikelyDockerContainerIP('172.18.0.1')).toBe(true)
expect(isLikelyDockerContainerIP('172.31.255.255')).toBe(true)
})
it('returns false for non-Docker IPs', () => {
expect(isLikelyDockerContainerIP('172.16.0.1')).toBe(false) // Private but often not Docker default
expect(isLikelyDockerContainerIP('192.168.1.1')).toBe(false)
expect(isLikelyDockerContainerIP('10.0.0.1')).toBe(false)
expect(isLikelyDockerContainerIP('8.8.8.8')).toBe(false)
})
it('returns false for invalid IPs', () => {
expect(isLikelyDockerContainerIP('invalid')).toBe(false)
})
})
})