feat: add keepalive controls to System Settings
- Introduced optional keepalive settings: `keepalive_idle` and `keepalive_count` in the Server struct. - Implemented UI controls for keepalive settings in System Settings, including validation and persistence. - Added localization support for new keepalive fields in multiple languages. - Created a manual test tracking plan for verifying keepalive controls and their behavior. - Updated existing tests to cover new functionality and ensure proper validation of keepalive inputs. - Ensured safe defaults and fallback behavior for missing or invalid keepalive values.
This commit is contained in:
@@ -58,6 +58,8 @@ describe('SystemSettings', () => {
|
||||
vi.mocked(settingsApi.getSettings).mockResolvedValue({
|
||||
'caddy.admin_api': 'http://localhost:2019',
|
||||
'caddy.ssl_provider': 'auto',
|
||||
'caddy.keepalive_idle': '',
|
||||
'caddy.keepalive_count': '',
|
||||
'ui.domain_link_behavior': 'new_tab',
|
||||
'security.cerberus.enabled': 'false',
|
||||
})
|
||||
@@ -162,6 +164,34 @@ describe('SystemSettings', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('loads keepalive settings when present', async () => {
|
||||
vi.mocked(settingsApi.getSettings).mockResolvedValue({
|
||||
'caddy.admin_api': 'http://localhost:2019',
|
||||
'caddy.ssl_provider': 'auto',
|
||||
'caddy.keepalive_idle': '2m',
|
||||
'caddy.keepalive_count': '5',
|
||||
'ui.domain_link_behavior': 'new_tab',
|
||||
})
|
||||
|
||||
renderWithProviders(<SystemSettings />)
|
||||
|
||||
await waitFor(() => {
|
||||
const keepaliveIdleInput = screen.getByLabelText('Keepalive Idle (Optional)') as HTMLInputElement
|
||||
const keepaliveCountInput = screen.getByLabelText('Keepalive Count (Optional)') as HTMLInputElement
|
||||
expect(keepaliveIdleInput.value).toBe('2m')
|
||||
expect(keepaliveCountInput.value).toBe('5')
|
||||
})
|
||||
})
|
||||
|
||||
it('renders keepalive controls in General settings', async () => {
|
||||
renderWithProviders(<SystemSettings />)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByLabelText('Keepalive Idle (Optional)')).toBeInTheDocument()
|
||||
expect(screen.getByLabelText('Keepalive Count (Optional)')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('saves all settings when save button is clicked', async () => {
|
||||
vi.mocked(settingsApi.updateSetting).mockResolvedValue(undefined)
|
||||
|
||||
@@ -176,7 +206,7 @@ describe('SystemSettings', () => {
|
||||
await user.click(saveButtons[0])
|
||||
|
||||
await waitFor(() => {
|
||||
expect(settingsApi.updateSetting).toHaveBeenCalledTimes(4)
|
||||
expect(settingsApi.updateSetting).toHaveBeenCalledTimes(6)
|
||||
expect(settingsApi.updateSetting).toHaveBeenCalledWith(
|
||||
'caddy.admin_api',
|
||||
expect.any(String),
|
||||
@@ -189,6 +219,18 @@ describe('SystemSettings', () => {
|
||||
'caddy',
|
||||
'string'
|
||||
)
|
||||
expect(settingsApi.updateSetting).toHaveBeenCalledWith(
|
||||
'caddy.keepalive_idle',
|
||||
'',
|
||||
'caddy',
|
||||
'string'
|
||||
)
|
||||
expect(settingsApi.updateSetting).toHaveBeenCalledWith(
|
||||
'caddy.keepalive_count',
|
||||
'',
|
||||
'caddy',
|
||||
'string'
|
||||
)
|
||||
expect(settingsApi.updateSetting).toHaveBeenCalledWith(
|
||||
'ui.domain_link_behavior',
|
||||
expect.any(String),
|
||||
@@ -197,6 +239,62 @@ describe('SystemSettings', () => {
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('saves keepalive settings when valid values are provided', async () => {
|
||||
vi.mocked(settingsApi.updateSetting).mockResolvedValue(undefined)
|
||||
|
||||
renderWithProviders(<SystemSettings />)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByLabelText('Keepalive Idle (Optional)')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
const user = userEvent.setup()
|
||||
const keepaliveIdleInput = screen.getByLabelText('Keepalive Idle (Optional)')
|
||||
const keepaliveCountInput = screen.getByLabelText('Keepalive Count (Optional)')
|
||||
await user.clear(keepaliveIdleInput)
|
||||
await user.type(keepaliveIdleInput, '30s')
|
||||
await user.clear(keepaliveCountInput)
|
||||
await user.type(keepaliveCountInput, '3')
|
||||
|
||||
const saveButtons = screen.getAllByRole('button', { name: /Save Settings/i })
|
||||
await user.click(saveButtons[0])
|
||||
|
||||
await waitFor(() => {
|
||||
expect(settingsApi.updateSetting).toHaveBeenCalledWith(
|
||||
'caddy.keepalive_idle',
|
||||
'30s',
|
||||
'caddy',
|
||||
'string'
|
||||
)
|
||||
expect(settingsApi.updateSetting).toHaveBeenCalledWith(
|
||||
'caddy.keepalive_count',
|
||||
'3',
|
||||
'caddy',
|
||||
'string'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('disables save when keepalive values are invalid', async () => {
|
||||
renderWithProviders(<SystemSettings />)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByLabelText('Keepalive Idle (Optional)')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
const user = userEvent.setup()
|
||||
const keepaliveIdleInput = screen.getByLabelText('Keepalive Idle (Optional)')
|
||||
await user.clear(keepaliveIdleInput)
|
||||
await user.type(keepaliveIdleInput, 'invalid-duration')
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Enter a valid duration (for example: 30s, 2m, 1h).')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
const saveButtons = screen.getAllByRole('button', { name: /Save Settings/i })
|
||||
expect(saveButtons[0]).toBeDisabled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('System Status', () => {
|
||||
|
||||
Reference in New Issue
Block a user