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

View File

@@ -46,7 +46,8 @@ const hostB: ProxyHost = {
describe('compareHosts', () => {
it('returns 0 for unknown sort column (default case)', () => {
const res = compareHosts(hostA, hostB, 'unknown' as any, 'asc')
const compareAny = compareHosts as unknown as (a: ProxyHost, b: ProxyHost, sortColumn: string, sortDirection: 'asc' | 'desc') => number
const res = compareAny(hostA, hostB, 'unknown', 'asc')
expect(res).toBe(0)
})

View File

@@ -0,0 +1,40 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { toast, toastCallbacks } from '../toast'
describe('toast util', () => {
beforeEach(() => {
// Ensure callbacks set is empty before each test
toastCallbacks.clear()
})
afterEach(() => {
toastCallbacks.clear()
})
it('calls registered callbacks for each toast type', () => {
const mock = vi.fn()
toastCallbacks.add(mock)
toast.success('ok')
toast.error('bad')
toast.info('info')
toast.warning('warn')
expect(mock).toHaveBeenCalledTimes(4)
expect(mock.mock.calls[0][0]).toMatchObject({ message: 'ok', type: 'success' })
expect(mock.mock.calls[1][0]).toMatchObject({ message: 'bad', type: 'error' })
expect(mock.mock.calls[2][0]).toMatchObject({ message: 'info', type: 'info' })
expect(mock.mock.calls[3][0]).toMatchObject({ message: 'warn', type: 'warning' })
})
it('provides incrementing ids', () => {
const mock = vi.fn()
toastCallbacks.add(mock)
// send multiple messages
toast.success('one')
toast.success('two')
const firstId = mock.mock.calls[0][0].id
const secondId = mock.mock.calls[1][0].id
expect(secondId).toBeGreaterThan(firstId)
})
})

View File

@@ -0,0 +1,103 @@
import type { ProxyHost } from '../api/proxyHosts'
export function formatSettingLabel(key: string) {
switch (key) {
case 'ssl_forced':
return 'Force SSL'
case 'http2_support':
return 'HTTP/2 Support'
case 'hsts_enabled':
return 'HSTS Enabled'
case 'hsts_subdomains':
return 'HSTS Subdomains'
case 'block_exploits':
return 'Block Exploits'
case 'websocket_support':
return 'Websockets Support'
default:
return key
}
}
export function settingHelpText(key: string) {
switch (key) {
case 'ssl_forced':
return 'Redirect all HTTP traffic to HTTPS.'
case 'http2_support':
return 'Enable HTTP/2 for improved performance.'
case 'hsts_enabled':
return 'Send HSTS header to enforce HTTPS.'
case 'hsts_subdomains':
return 'Include subdomains in HSTS policy.'
case 'block_exploits':
return 'Add common exploit-mitigation headers and rules.'
case 'websocket_support':
return 'Enable websocket proxying support.'
default:
return ''
}
}
export function settingKeyToField(key: string) {
switch (key) {
case 'ssl_forced':
return 'ssl_forced'
case 'http2_support':
return 'http2_support'
case 'hsts_enabled':
return 'hsts_enabled'
case 'hsts_subdomains':
return 'hsts_subdomains'
case 'block_exploits':
return 'block_exploits'
case 'websocket_support':
return 'websocket_support'
default:
return key
}
}
export async function applyBulkSettingsToHosts(options: {
hosts: ProxyHost[]
hostUUIDs: string[]
keysToApply: string[]
bulkApplySettings: Record<string, { apply: boolean; value: boolean }>
updateHost: (uuid: string, data: Partial<ProxyHost>) => Promise<ProxyHost>
setApplyProgress?: (p: { current: number; total: number } | null) => void
}) {
const { hosts, hostUUIDs, keysToApply, bulkApplySettings, updateHost, setApplyProgress } = options
let completed = 0
let errors = 0
setApplyProgress?.({ current: 0, total: hostUUIDs.length })
for (const uuid of hostUUIDs) {
const patch: Partial<ProxyHost> = {}
for (const key of keysToApply) {
const field = settingKeyToField(key) as keyof ProxyHost
;(patch as unknown as Record<string, unknown>)[field as string] = bulkApplySettings[key].value
}
const host = hosts.find(h => h.uuid === uuid)
if (!host) {
errors++
completed++
setApplyProgress?.({ current: completed, total: hostUUIDs.length })
continue
}
const merged: Partial<ProxyHost> = { ...host, ...patch }
try {
await updateHost(uuid, merged)
} catch {
errors++
}
completed++
setApplyProgress?.({ current: completed, total: hostUUIDs.length })
}
setApplyProgress?.(null)
return { errors, completed }
}
export default {}