- Implement tests for ImportSuccessModal to verify rendering and functionality. - Update AuthContext to store authentication token in localStorage and manage token state. - Modify useImport hook to capture and expose commit results, preventing unnecessary refetches. - Enhance useCertificates hook to support optional refetch intervals. - Update Dashboard to conditionally poll certificates based on pending status. - Integrate ImportSuccessModal into ImportCaddy for user feedback on import completion. - Adjust Login component to utilize returned token for authentication. - Refactor CrowdSecConfig tests for improved readability and reliability. - Add debug_db.py script for inspecting the SQLite database. - Update integration and test scripts for better configuration and error handling. - Introduce Trivy scan script for vulnerability assessment of Docker images.
349 lines
9.6 KiB
TypeScript
349 lines
9.6 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
import { renderHook, waitFor, act } from '@testing-library/react'
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
import React from 'react'
|
|
import { useImport } from '../useImport'
|
|
import * as api from '../../api/import'
|
|
|
|
// Mock the API
|
|
vi.mock('../../api/import', () => ({
|
|
uploadCaddyfile: vi.fn(),
|
|
getImportPreview: vi.fn(),
|
|
commitImport: vi.fn(),
|
|
cancelImport: vi.fn(),
|
|
getImportStatus: vi.fn(),
|
|
}))
|
|
|
|
const createWrapper = () => {
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: false,
|
|
},
|
|
},
|
|
})
|
|
return ({ children }: { children: React.ReactNode }) => (
|
|
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
)
|
|
}
|
|
|
|
describe('useImport', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
vi.mocked(api.getImportStatus).mockResolvedValue({ has_pending: false })
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
it('starts with no active session', async () => {
|
|
const { result } = renderHook(() => useImport(), { wrapper: createWrapper() })
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
expect(result.current.session).toBeNull()
|
|
})
|
|
expect(result.current.error).toBeNull()
|
|
})
|
|
|
|
it('uploads content and creates session', async () => {
|
|
const mockSession = {
|
|
id: 'session-1',
|
|
state: 'reviewing' as const,
|
|
created_at: '2025-01-18T10:00:00Z',
|
|
updated_at: '2025-01-18T10:00:00Z',
|
|
}
|
|
|
|
const mockPreviewData = {
|
|
hosts: [{ domain_names: 'test.com' }],
|
|
conflicts: [],
|
|
errors: [],
|
|
}
|
|
|
|
const mockResponse = {
|
|
session: mockSession,
|
|
preview: mockPreviewData,
|
|
}
|
|
|
|
vi.mocked(api.uploadCaddyfile).mockResolvedValue(mockResponse)
|
|
vi.mocked(api.getImportStatus).mockResolvedValue({ has_pending: true, session: mockSession })
|
|
vi.mocked(api.getImportPreview).mockResolvedValue(mockResponse)
|
|
|
|
const { result } = renderHook(() => useImport(), { wrapper: createWrapper() })
|
|
|
|
await act(async () => {
|
|
await result.current.upload('example.com { reverse_proxy localhost:8080 }')
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.session).toEqual(mockSession)
|
|
})
|
|
|
|
expect(api.uploadCaddyfile).toHaveBeenCalledWith('example.com { reverse_proxy localhost:8080 }')
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
|
|
it('handles upload errors', async () => {
|
|
const mockError = new Error('Upload failed')
|
|
vi.mocked(api.uploadCaddyfile).mockRejectedValue(mockError)
|
|
|
|
const { result } = renderHook(() => useImport(), { wrapper: createWrapper() })
|
|
|
|
let threw = false
|
|
await act(async () => {
|
|
try {
|
|
await result.current.upload('invalid')
|
|
} catch {
|
|
threw = true
|
|
}
|
|
})
|
|
expect(threw).toBe(true)
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.error).toBe('Upload failed')
|
|
})
|
|
})
|
|
|
|
it('commits import with resolutions', async () => {
|
|
const mockSession = {
|
|
id: 'session-2',
|
|
state: 'reviewing' as const,
|
|
created_at: '2025-01-18T10:00:00Z',
|
|
updated_at: '2025-01-18T10:00:00Z',
|
|
}
|
|
|
|
const mockResponse = {
|
|
session: mockSession,
|
|
preview: { hosts: [], conflicts: [], errors: [] },
|
|
}
|
|
|
|
let isCommitted = false
|
|
vi.mocked(api.uploadCaddyfile).mockResolvedValue(mockResponse)
|
|
vi.mocked(api.getImportStatus).mockImplementation(async () => {
|
|
if (isCommitted) return { has_pending: false }
|
|
return { has_pending: true, session: mockSession }
|
|
})
|
|
vi.mocked(api.getImportPreview).mockResolvedValue(mockResponse)
|
|
vi.mocked(api.commitImport).mockImplementation(async () => {
|
|
isCommitted = true
|
|
return { created: 0, updated: 0, skipped: 0, errors: [] }
|
|
})
|
|
|
|
const { result } = renderHook(() => useImport(), { wrapper: createWrapper() })
|
|
|
|
await act(async () => {
|
|
await result.current.upload('test')
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.session).toEqual(mockSession)
|
|
})
|
|
|
|
await act(async () => {
|
|
await result.current.commit({ 'test.com': 'skip' }, { 'test.com': 'Test' })
|
|
})
|
|
|
|
expect(api.commitImport).toHaveBeenCalledWith('session-2', { 'test.com': 'skip' }, { 'test.com': 'Test' })
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.session).toBeNull()
|
|
})
|
|
})
|
|
|
|
it('cancels active import session', async () => {
|
|
const mockSession = {
|
|
id: 'session-3',
|
|
state: 'reviewing' as const,
|
|
created_at: '2025-01-18T10:00:00Z',
|
|
updated_at: '2025-01-18T10:00:00Z',
|
|
}
|
|
|
|
const mockResponse = {
|
|
session: mockSession,
|
|
preview: { hosts: [], conflicts: [], errors: [] },
|
|
}
|
|
|
|
let isCancelled = false
|
|
vi.mocked(api.uploadCaddyfile).mockResolvedValue(mockResponse)
|
|
vi.mocked(api.getImportStatus).mockImplementation(async () => {
|
|
if (isCancelled) return { has_pending: false }
|
|
return { has_pending: true, session: mockSession }
|
|
})
|
|
vi.mocked(api.getImportPreview).mockResolvedValue(mockResponse)
|
|
vi.mocked(api.cancelImport).mockImplementation(async () => {
|
|
isCancelled = true
|
|
})
|
|
|
|
const { result } = renderHook(() => useImport(), { wrapper: createWrapper() })
|
|
|
|
await act(async () => {
|
|
await result.current.upload('test')
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.session).toEqual(mockSession)
|
|
})
|
|
|
|
await act(async () => {
|
|
await result.current.cancel()
|
|
})
|
|
|
|
expect(api.cancelImport).toHaveBeenCalled()
|
|
await waitFor(() => {
|
|
expect(result.current.session).toBeNull()
|
|
})
|
|
})
|
|
|
|
it('handles commit errors', async () => {
|
|
const mockSession = {
|
|
id: 'session-4',
|
|
state: 'reviewing' as const,
|
|
created_at: '2025-01-18T10:00:00Z',
|
|
updated_at: '2025-01-18T10:00:00Z',
|
|
}
|
|
|
|
const mockResponse = {
|
|
session: mockSession,
|
|
preview: { hosts: [], conflicts: [], errors: [] },
|
|
}
|
|
|
|
vi.mocked(api.uploadCaddyfile).mockResolvedValue(mockResponse)
|
|
vi.mocked(api.getImportStatus).mockResolvedValue({ has_pending: true, session: mockSession })
|
|
vi.mocked(api.getImportPreview).mockResolvedValue(mockResponse)
|
|
|
|
const mockError = new Error('Commit failed')
|
|
vi.mocked(api.commitImport).mockRejectedValue(mockError)
|
|
|
|
const { result } = renderHook(() => useImport(), { wrapper: createWrapper() })
|
|
|
|
await act(async () => {
|
|
await result.current.upload('test')
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.session).toEqual(mockSession)
|
|
})
|
|
|
|
let threw = false
|
|
await act(async () => {
|
|
try {
|
|
await result.current.commit({}, {})
|
|
} catch {
|
|
threw = true
|
|
}
|
|
})
|
|
expect(threw).toBe(true)
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.error).toBe('Commit failed')
|
|
})
|
|
})
|
|
|
|
it('captures and exposes commit result on success', async () => {
|
|
const mockSession = {
|
|
id: 'session-5',
|
|
state: 'reviewing' as const,
|
|
created_at: '2025-01-18T10:00:00Z',
|
|
updated_at: '2025-01-18T10:00:00Z',
|
|
}
|
|
|
|
const mockResponse = {
|
|
session: mockSession,
|
|
preview: { hosts: [], conflicts: [], errors: [] },
|
|
}
|
|
|
|
const mockCommitResult = {
|
|
created: 3,
|
|
updated: 1,
|
|
skipped: 2,
|
|
errors: [],
|
|
}
|
|
|
|
let isCommitted = false
|
|
vi.mocked(api.uploadCaddyfile).mockResolvedValue(mockResponse)
|
|
vi.mocked(api.getImportStatus).mockImplementation(async () => {
|
|
if (isCommitted) return { has_pending: false }
|
|
return { has_pending: true, session: mockSession }
|
|
})
|
|
vi.mocked(api.getImportPreview).mockResolvedValue(mockResponse)
|
|
vi.mocked(api.commitImport).mockImplementation(async () => {
|
|
isCommitted = true
|
|
return mockCommitResult
|
|
})
|
|
|
|
const { result } = renderHook(() => useImport(), { wrapper: createWrapper() })
|
|
|
|
await act(async () => {
|
|
await result.current.upload('test')
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.session).toEqual(mockSession)
|
|
})
|
|
|
|
await act(async () => {
|
|
await result.current.commit({}, {})
|
|
})
|
|
|
|
expect(result.current.commitResult).toEqual(mockCommitResult)
|
|
expect(result.current.commitSuccess).toBe(true)
|
|
})
|
|
|
|
it('clears commit result when clearCommitResult is called', async () => {
|
|
const mockSession = {
|
|
id: 'session-6',
|
|
state: 'reviewing' as const,
|
|
created_at: '2025-01-18T10:00:00Z',
|
|
updated_at: '2025-01-18T10:00:00Z',
|
|
}
|
|
|
|
const mockResponse = {
|
|
session: mockSession,
|
|
preview: { hosts: [], conflicts: [], errors: [] },
|
|
}
|
|
|
|
const mockCommitResult = {
|
|
created: 2,
|
|
updated: 0,
|
|
skipped: 0,
|
|
errors: [],
|
|
}
|
|
|
|
let isCommitted = false
|
|
vi.mocked(api.uploadCaddyfile).mockResolvedValue(mockResponse)
|
|
vi.mocked(api.getImportStatus).mockImplementation(async () => {
|
|
if (isCommitted) return { has_pending: false }
|
|
return { has_pending: true, session: mockSession }
|
|
})
|
|
vi.mocked(api.getImportPreview).mockResolvedValue(mockResponse)
|
|
vi.mocked(api.commitImport).mockImplementation(async () => {
|
|
isCommitted = true
|
|
return mockCommitResult
|
|
})
|
|
|
|
const { result } = renderHook(() => useImport(), { wrapper: createWrapper() })
|
|
|
|
await act(async () => {
|
|
await result.current.upload('test')
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.session).toEqual(mockSession)
|
|
})
|
|
|
|
await act(async () => {
|
|
await result.current.commit({}, {})
|
|
})
|
|
|
|
expect(result.current.commitResult).toEqual(mockCommitResult)
|
|
|
|
act(() => {
|
|
result.current.clearCommitResult()
|
|
})
|
|
|
|
expect(result.current.commitResult).toBeNull()
|
|
expect(result.current.commitSuccess).toBe(false)
|
|
})
|
|
})
|