feat: add loading overlays and animations across various pages
- Implemented new CSS animations for UI elements including bobbing, pulsing, rotating, and spinning effects. - Integrated loading overlays in CrowdSecConfig, Login, ProxyHosts, Security, and WafConfig pages to enhance user experience during asynchronous operations. - Added contextual messages for loading states to inform users about ongoing processes. - Created tests for Login and Security pages to ensure overlays function correctly during login attempts and security operations.
This commit is contained in:
130
frontend/src/api/__tests__/crowdsec.test.ts
Normal file
130
frontend/src/api/__tests__/crowdsec.test.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import * as crowdsec from '../crowdsec'
|
||||
import client from '../client'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
describe('crowdsec API', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('startCrowdsec', () => {
|
||||
it('should call POST /admin/crowdsec/start', async () => {
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await crowdsec.startCrowdsec()
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/admin/crowdsec/start')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('stopCrowdsec', () => {
|
||||
it('should call POST /admin/crowdsec/stop', async () => {
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await crowdsec.stopCrowdsec()
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/admin/crowdsec/stop')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('statusCrowdsec', () => {
|
||||
it('should call GET /admin/crowdsec/status', async () => {
|
||||
const mockData = { running: true, pid: 1234 }
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await crowdsec.statusCrowdsec()
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/admin/crowdsec/status')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('importCrowdsecConfig', () => {
|
||||
it('should call POST /admin/crowdsec/import with FormData', async () => {
|
||||
const mockFile = new File(['content'], 'config.tar.gz', { type: 'application/gzip' })
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await crowdsec.importCrowdsecConfig(mockFile)
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith(
|
||||
'/admin/crowdsec/import',
|
||||
expect.any(FormData),
|
||||
{ headers: { 'Content-Type': 'multipart/form-data' } }
|
||||
)
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('exportCrowdsecConfig', () => {
|
||||
it('should call GET /admin/crowdsec/export with blob responseType', async () => {
|
||||
const mockBlob = new Blob(['data'], { type: 'application/gzip' })
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockBlob })
|
||||
|
||||
const result = await crowdsec.exportCrowdsecConfig()
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/admin/crowdsec/export', { responseType: 'blob' })
|
||||
expect(result).toEqual(mockBlob)
|
||||
})
|
||||
})
|
||||
|
||||
describe('listCrowdsecFiles', () => {
|
||||
it('should call GET /admin/crowdsec/files', async () => {
|
||||
const mockData = { files: ['file1.yaml', 'file2.yaml'] }
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await crowdsec.listCrowdsecFiles()
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/admin/crowdsec/files')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('readCrowdsecFile', () => {
|
||||
it('should call GET /admin/crowdsec/file with encoded path', async () => {
|
||||
const mockData = { content: 'file content' }
|
||||
const path = '/etc/crowdsec/file.yaml'
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await crowdsec.readCrowdsecFile(path)
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith(
|
||||
`/admin/crowdsec/file?path=${encodeURIComponent(path)}`
|
||||
)
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('writeCrowdsecFile', () => {
|
||||
it('should call POST /admin/crowdsec/file with path and content', async () => {
|
||||
const mockData = { success: true }
|
||||
const path = '/etc/crowdsec/file.yaml'
|
||||
const content = 'new content'
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await crowdsec.writeCrowdsecFile(path, content)
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/admin/crowdsec/file', { path, content })
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('default export', () => {
|
||||
it('should export all functions', () => {
|
||||
expect(crowdsec.default).toHaveProperty('startCrowdsec')
|
||||
expect(crowdsec.default).toHaveProperty('stopCrowdsec')
|
||||
expect(crowdsec.default).toHaveProperty('statusCrowdsec')
|
||||
expect(crowdsec.default).toHaveProperty('importCrowdsecConfig')
|
||||
expect(crowdsec.default).toHaveProperty('exportCrowdsecConfig')
|
||||
expect(crowdsec.default).toHaveProperty('listCrowdsecFiles')
|
||||
expect(crowdsec.default).toHaveProperty('readCrowdsecFile')
|
||||
expect(crowdsec.default).toHaveProperty('writeCrowdsecFile')
|
||||
})
|
||||
})
|
||||
})
|
||||
244
frontend/src/api/__tests__/security.test.ts
Normal file
244
frontend/src/api/__tests__/security.test.ts
Normal file
@@ -0,0 +1,244 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import * as security from '../security'
|
||||
import client from '../client'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
describe('security API', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('getSecurityStatus', () => {
|
||||
it('should call GET /security/status', async () => {
|
||||
const mockData: security.SecurityStatus = {
|
||||
cerberus: { enabled: true },
|
||||
crowdsec: { mode: 'local', api_url: 'http://localhost:8080', enabled: true },
|
||||
waf: { mode: 'enabled', enabled: true },
|
||||
rate_limit: { mode: 'enabled', enabled: true },
|
||||
acl: { enabled: true }
|
||||
}
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.getSecurityStatus()
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/security/status')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSecurityConfig', () => {
|
||||
it('should call GET /security/config', async () => {
|
||||
const mockData = { config: { admin_whitelist: '10.0.0.0/8' } }
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.getSecurityConfig()
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/security/config')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateSecurityConfig', () => {
|
||||
it('should call POST /security/config with payload', async () => {
|
||||
const payload: security.SecurityConfigPayload = {
|
||||
name: 'test',
|
||||
enabled: true,
|
||||
admin_whitelist: '10.0.0.0/8'
|
||||
}
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.updateSecurityConfig(payload)
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/security/config', payload)
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
|
||||
it('should handle all payload fields', async () => {
|
||||
const payload: security.SecurityConfigPayload = {
|
||||
name: 'test',
|
||||
enabled: true,
|
||||
admin_whitelist: '10.0.0.0/8',
|
||||
crowdsec_mode: 'local',
|
||||
crowdsec_api_url: 'http://localhost:8080',
|
||||
waf_mode: 'enabled',
|
||||
waf_rules_source: 'coreruleset',
|
||||
waf_learning: true,
|
||||
rate_limit_enable: true,
|
||||
rate_limit_burst: 10,
|
||||
rate_limit_requests: 100,
|
||||
rate_limit_window_sec: 60
|
||||
}
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.updateSecurityConfig(payload)
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/security/config', payload)
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('generateBreakGlassToken', () => {
|
||||
it('should call POST /security/breakglass/generate', async () => {
|
||||
const mockData = { token: 'abc123' }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.generateBreakGlassToken()
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/security/breakglass/generate')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('enableCerberus', () => {
|
||||
it('should call POST /security/enable with payload', async () => {
|
||||
const payload = { mode: 'full' }
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.enableCerberus(payload)
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/security/enable', payload)
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
|
||||
it('should call POST /security/enable with empty object when no payload', async () => {
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.enableCerberus()
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/security/enable', {})
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('disableCerberus', () => {
|
||||
it('should call POST /security/disable with payload', async () => {
|
||||
const payload = { reason: 'maintenance' }
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.disableCerberus(payload)
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/security/disable', payload)
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
|
||||
it('should call POST /security/disable with empty object when no payload', async () => {
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.disableCerberus()
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/security/disable', {})
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getDecisions', () => {
|
||||
it('should call GET /security/decisions with default limit', async () => {
|
||||
const mockData = { decisions: [] }
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.getDecisions()
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/security/decisions?limit=50')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
|
||||
it('should call GET /security/decisions with custom limit', async () => {
|
||||
const mockData = { decisions: [] }
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.getDecisions(100)
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/security/decisions?limit=100')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('createDecision', () => {
|
||||
it('should call POST /security/decisions with payload', async () => {
|
||||
const payload = { ip: '1.2.3.4', duration: '4h', type: 'ban' }
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.createDecision(payload)
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/security/decisions', payload)
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getRuleSets', () => {
|
||||
it('should call GET /security/rulesets', async () => {
|
||||
const mockData: security.RuleSetsResponse = {
|
||||
rulesets: [
|
||||
{
|
||||
id: 1,
|
||||
uuid: 'abc-123',
|
||||
name: 'OWASP CRS',
|
||||
source_url: 'https://example.com/rules',
|
||||
mode: 'blocking',
|
||||
last_updated: '2025-12-04T00:00:00Z',
|
||||
content: 'rule content'
|
||||
}
|
||||
]
|
||||
}
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.getRuleSets()
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/security/rulesets')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('upsertRuleSet', () => {
|
||||
it('should call POST /security/rulesets with create payload', async () => {
|
||||
const payload: security.UpsertRuleSetPayload = {
|
||||
name: 'Custom Rules',
|
||||
content: 'rule content',
|
||||
mode: 'blocking'
|
||||
}
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.upsertRuleSet(payload)
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/security/rulesets', payload)
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
|
||||
it('should call POST /security/rulesets with update payload', async () => {
|
||||
const payload: security.UpsertRuleSetPayload = {
|
||||
id: 1,
|
||||
name: 'Updated Rules',
|
||||
source_url: 'https://example.com/rules',
|
||||
mode: 'detection'
|
||||
}
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.upsertRuleSet(payload)
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/security/rulesets', payload)
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('deleteRuleSet', () => {
|
||||
it('should call DELETE /security/rulesets/:id', async () => {
|
||||
const mockData = { success: true }
|
||||
vi.mocked(client.delete).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await security.deleteRuleSet(1)
|
||||
|
||||
expect(client.delete).toHaveBeenCalledWith('/security/rulesets/1')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
})
|
||||
67
frontend/src/api/__tests__/settings.test.ts
Normal file
67
frontend/src/api/__tests__/settings.test.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import * as settings from '../settings'
|
||||
import client from '../client'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
describe('settings API', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('getSettings', () => {
|
||||
it('should call GET /settings', async () => {
|
||||
const mockData: settings.SettingsMap = {
|
||||
'ui.theme': 'dark',
|
||||
'security.cerberus.enabled': 'true'
|
||||
}
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await settings.getSettings()
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/settings')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateSetting', () => {
|
||||
it('should call POST /settings with key and value only', async () => {
|
||||
vi.mocked(client.post).mockResolvedValue({ data: {} })
|
||||
|
||||
await settings.updateSetting('ui.theme', 'light')
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/settings', {
|
||||
key: 'ui.theme',
|
||||
value: 'light',
|
||||
category: undefined,
|
||||
type: undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('should call POST /settings with all parameters', async () => {
|
||||
vi.mocked(client.post).mockResolvedValue({ data: {} })
|
||||
|
||||
await settings.updateSetting('security.cerberus.enabled', 'true', 'security', 'bool')
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/settings', {
|
||||
key: 'security.cerberus.enabled',
|
||||
value: 'true',
|
||||
category: 'security',
|
||||
type: 'bool'
|
||||
})
|
||||
})
|
||||
|
||||
it('should call POST /settings with category but no type', async () => {
|
||||
vi.mocked(client.post).mockResolvedValue({ data: {} })
|
||||
|
||||
await settings.updateSetting('ui.theme', 'dark', 'ui')
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/settings', {
|
||||
key: 'ui.theme',
|
||||
value: 'dark',
|
||||
category: 'ui',
|
||||
type: undefined
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
135
frontend/src/api/__tests__/uptime.test.ts
Normal file
135
frontend/src/api/__tests__/uptime.test.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import * as uptime from '../uptime'
|
||||
import client from '../client'
|
||||
import type { UptimeMonitor, UptimeHeartbeat } from '../uptime'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
describe('uptime API', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('getMonitors', () => {
|
||||
it('should call GET /uptime/monitors', async () => {
|
||||
const mockData: UptimeMonitor[] = [
|
||||
{
|
||||
id: 'mon-1',
|
||||
name: 'Test Monitor',
|
||||
type: 'http',
|
||||
url: 'https://example.com',
|
||||
interval: 60,
|
||||
enabled: true,
|
||||
status: 'up',
|
||||
latency: 100,
|
||||
max_retries: 3
|
||||
}
|
||||
]
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await uptime.getMonitors()
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/uptime/monitors')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getMonitorHistory', () => {
|
||||
it('should call GET /uptime/monitors/:id/history with default limit', async () => {
|
||||
const mockData: UptimeHeartbeat[] = [
|
||||
{
|
||||
id: 1,
|
||||
monitor_id: 'mon-1',
|
||||
status: 'up',
|
||||
latency: 100,
|
||||
message: 'OK',
|
||||
created_at: '2025-12-04T00:00:00Z'
|
||||
}
|
||||
]
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await uptime.getMonitorHistory('mon-1')
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/uptime/monitors/mon-1/history?limit=50')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
|
||||
it('should call GET /uptime/monitors/:id/history with custom limit', async () => {
|
||||
const mockData: UptimeHeartbeat[] = []
|
||||
vi.mocked(client.get).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await uptime.getMonitorHistory('mon-1', 100)
|
||||
|
||||
expect(client.get).toHaveBeenCalledWith('/uptime/monitors/mon-1/history?limit=100')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateMonitor', () => {
|
||||
it('should call PUT /uptime/monitors/:id', async () => {
|
||||
const mockMonitor: UptimeMonitor = {
|
||||
id: 'mon-1',
|
||||
name: 'Updated Monitor',
|
||||
type: 'http',
|
||||
url: 'https://example.com',
|
||||
interval: 120,
|
||||
enabled: false,
|
||||
status: 'down',
|
||||
latency: 0,
|
||||
max_retries: 5
|
||||
}
|
||||
vi.mocked(client.put).mockResolvedValue({ data: mockMonitor })
|
||||
|
||||
const result = await uptime.updateMonitor('mon-1', { enabled: false, interval: 120 })
|
||||
|
||||
expect(client.put).toHaveBeenCalledWith('/uptime/monitors/mon-1', { enabled: false, interval: 120 })
|
||||
expect(result).toEqual(mockMonitor)
|
||||
})
|
||||
})
|
||||
|
||||
describe('deleteMonitor', () => {
|
||||
it('should call DELETE /uptime/monitors/:id', async () => {
|
||||
vi.mocked(client.delete).mockResolvedValue({ data: undefined })
|
||||
|
||||
const result = await uptime.deleteMonitor('mon-1')
|
||||
|
||||
expect(client.delete).toHaveBeenCalledWith('/uptime/monitors/mon-1')
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('syncMonitors', () => {
|
||||
it('should call POST /uptime/sync with empty body when no params', async () => {
|
||||
const mockData = { synced: 5 }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await uptime.syncMonitors()
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/uptime/sync', {})
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
|
||||
it('should call POST /uptime/sync with provided parameters', async () => {
|
||||
const mockData = { synced: 5 }
|
||||
const body = { interval: 120, max_retries: 5 }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await uptime.syncMonitors(body)
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/uptime/sync', body)
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
|
||||
describe('checkMonitor', () => {
|
||||
it('should call POST /uptime/monitors/:id/check', async () => {
|
||||
const mockData = { message: 'Check initiated' }
|
||||
vi.mocked(client.post).mockResolvedValue({ data: mockData })
|
||||
|
||||
const result = await uptime.checkMonitor('mon-1')
|
||||
|
||||
expect(client.post).toHaveBeenCalledWith('/uptime/monitors/mon-1/check')
|
||||
expect(result).toEqual(mockData)
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user