chore: Refactor tests to use findBy queries for better async handling, update mock implementations, and clean up imports across various test files. Adjust toast utility to use for-of loops for callback execution. Update Vite and Vitest configuration files for consistency.
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import { Suspense, lazy } from 'react'
|
||||
import { Navigate } from 'react-router-dom'
|
||||
import { BrowserRouter as Router, Routes, Route, Outlet } from 'react-router-dom'
|
||||
import { Toaster } from 'react-hot-toast'
|
||||
import { BrowserRouter as Router, Routes, Route, Outlet, Navigate } from 'react-router-dom'
|
||||
|
||||
import Layout from './components/Layout'
|
||||
import { ToastContainer } from './components/Toast'
|
||||
import { SetupGuard } from './components/SetupGuard'
|
||||
import { LoadingOverlay } from './components/LoadingStates'
|
||||
import RequireAuth from './components/RequireAuth'
|
||||
import RequireRole from './components/RequireRole'
|
||||
import { SetupGuard } from './components/SetupGuard'
|
||||
import { ToastContainer } from './components/Toast'
|
||||
import { AuthProvider } from './context/AuthContext'
|
||||
|
||||
// Lazy load pages for code splitting
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest'
|
||||
|
||||
import i18n from '../i18n'
|
||||
|
||||
describe('i18n configuration', () => {
|
||||
@@ -13,9 +14,9 @@ describe('i18n configuration', () => {
|
||||
|
||||
it('has all required language resources', () => {
|
||||
const languages = ['en', 'es', 'fr', 'de', 'zh']
|
||||
languages.forEach((lang) => {
|
||||
for (const lang of languages) {
|
||||
expect(i18n.hasResourceBundle(lang, 'translation')).toBe(true)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('translates common keys', () => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { accessListsApi } from '../accessLists';
|
||||
|
||||
import { accessListsApi, type AccessList } from '../accessLists';
|
||||
import client from '../client';
|
||||
import type { AccessList } from '../accessLists';
|
||||
|
||||
|
||||
// Mock the client module
|
||||
vi.mock('../client', () => ({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from '../../api/client'
|
||||
import { getBackups, createBackup, restoreBackup, deleteBackup } from '../backups'
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
import { getCertificates, uploadCertificate, deleteCertificate, type Certificate } from '../certificates';
|
||||
import client from '../client';
|
||||
import { getCertificates, uploadCertificate, deleteCertificate, Certificate } from '../certificates';
|
||||
|
||||
vi.mock('../client', () => ({
|
||||
default: {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import axios from 'axios'
|
||||
import { beforeEach, describe, it, expect, vi, afterEach } from 'vitest'
|
||||
|
||||
import { setAuthErrorHandler, setAuthToken } from '../client'
|
||||
|
||||
type ResponseHandler = (value: unknown) => unknown
|
||||
type ErrorHandler = (error: ResponseError) => Promise<never>
|
||||
|
||||
@@ -45,10 +48,6 @@ vi.mock('axios', () => {
|
||||
}
|
||||
})
|
||||
|
||||
// Must import AFTER mock definition
|
||||
import { setAuthErrorHandler, setAuthToken } from '../client'
|
||||
import axios from 'axios'
|
||||
|
||||
// Get mock client instance for header assertions
|
||||
const getMockClient = () => {
|
||||
const mockAxios = vi.mocked(axios)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import * as consoleEnrollment from '../consoleEnrollment'
|
||||
|
||||
import client from '../client'
|
||||
import * as consoleEnrollment from '../consoleEnrollment'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
@@ -480,13 +481,10 @@ describe('consoleEnrollment API', () => {
|
||||
}
|
||||
vi.mocked(client.post).mockRejectedValue(error)
|
||||
|
||||
try {
|
||||
await consoleEnrollment.enrollConsole(payload)
|
||||
} catch (e: unknown) {
|
||||
// Error message should NOT contain the key
|
||||
const error = e as { response?: { data?: { error?: string } } }
|
||||
expect(error.response?.data?.error).not.toContain('cs-enroll-sensitive-key')
|
||||
}
|
||||
const thrown = await consoleEnrollment.enrollConsole(payload).catch((e: unknown) => e)
|
||||
const caughtError = thrown as { response?: { data?: { error?: string } } }
|
||||
// Error message should NOT contain the key
|
||||
expect(caughtError.response?.data?.error).not.toContain('cs-enroll-sensitive-key')
|
||||
})
|
||||
|
||||
it('should handle correlation_id for debugging without exposing keys', async () => {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from '../client'
|
||||
import {
|
||||
getCredentials,
|
||||
getCredential,
|
||||
@@ -11,7 +13,6 @@ import {
|
||||
type CredentialRequest,
|
||||
type CredentialTestResult,
|
||||
} from '../credentials'
|
||||
import client from '../client'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import * as crowdsec from '../crowdsec'
|
||||
|
||||
import client from '../client'
|
||||
import * as crowdsec from '../crowdsec'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { detectDNSProvider, getDetectionPatterns } from '../dnsDetection'
|
||||
|
||||
import client from '../client'
|
||||
import type { DetectionResult, NameserverPattern } from '../dnsDetection'
|
||||
import { detectDNSProvider, getDetectionPatterns, type DetectionResult, type NameserverPattern } from '../dnsDetection'
|
||||
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from '../client'
|
||||
import {
|
||||
getDNSProviders,
|
||||
getDNSProvider,
|
||||
@@ -12,7 +14,6 @@ import {
|
||||
type DNSProviderRequest,
|
||||
type DNSProviderTypeInfo,
|
||||
} from '../dnsProviders'
|
||||
import client from '../client'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import { dockerApi } from '../docker';
|
||||
|
||||
import client from '../client';
|
||||
import { dockerApi } from '../docker';
|
||||
|
||||
vi.mock('../client', () => ({
|
||||
default: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
import client from '../client';
|
||||
import { getDomains, createDomain, deleteDomain, Domain } from '../domains';
|
||||
import { getDomains, createDomain, deleteDomain, type Domain } from '../domains';
|
||||
|
||||
vi.mock('../client', () => ({
|
||||
default: {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from '../client'
|
||||
import {
|
||||
getEncryptionStatus,
|
||||
rotateEncryptionKey,
|
||||
@@ -9,7 +11,6 @@ import {
|
||||
type RotationHistoryEntry,
|
||||
type KeyValidationResult,
|
||||
} from '../encryption'
|
||||
import client from '../client'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { uploadCaddyfile, uploadCaddyfilesMulti, getImportPreview, commitImport, cancelImport, getImportStatus } from '../import';
|
||||
|
||||
import client from '../client';
|
||||
import { uploadCaddyfile, uploadCaddyfilesMulti, getImportPreview, commitImport, cancelImport, getImportStatus } from '../import';
|
||||
|
||||
vi.mock('../client', () => ({
|
||||
default: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { uploadJSONExport, commitJSONImport, cancelJSONImport } from '../jsonImport';
|
||||
|
||||
import client from '../client';
|
||||
import { uploadJSONExport, commitJSONImport, cancelJSONImport } from '../jsonImport';
|
||||
|
||||
vi.mock('../client', () => ({
|
||||
default: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
import { connectLiveLogs } from '../logs';
|
||||
|
||||
// Mock WebSocket
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from '../client'
|
||||
import { downloadLog, getLogContent, getLogs } from '../logs'
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from '../client'
|
||||
import {
|
||||
getChallenge,
|
||||
createChallenge,
|
||||
@@ -6,7 +8,6 @@ import {
|
||||
pollChallenge,
|
||||
deleteChallenge,
|
||||
} from '../manualChallenge'
|
||||
import client from '../client'
|
||||
|
||||
vi.mock('../client', () => ({
|
||||
default: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from '../client'
|
||||
import {
|
||||
getProviders,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { uploadNPMExport, commitNPMImport, cancelNPMImport } from '../npmImport';
|
||||
|
||||
import client from '../client';
|
||||
import { uploadNPMExport, commitNPMImport, cancelNPMImport } from '../npmImport';
|
||||
|
||||
vi.mock('../client', () => ({
|
||||
default: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
import client from '../client';
|
||||
import {
|
||||
getPlugins,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import * as presets from '../presets'
|
||||
|
||||
import client from '../client'
|
||||
import * as presets from '../presets'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { bulkUpdateACL } from '../proxyHosts';
|
||||
import type { BulkUpdateACLResponse } from '../proxyHosts';
|
||||
|
||||
import { bulkUpdateACL, type BulkUpdateACLResponse } from '../proxyHosts';
|
||||
|
||||
|
||||
// Mock the client module
|
||||
const mockPut = vi.fn();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
import client from '../client';
|
||||
import {
|
||||
getProxyHosts,
|
||||
@@ -7,7 +8,7 @@ import {
|
||||
updateProxyHost,
|
||||
deleteProxyHost,
|
||||
testProxyHostConnection,
|
||||
ProxyHost
|
||||
type ProxyHost
|
||||
} from '../proxyHosts';
|
||||
|
||||
vi.mock('../client', () => ({
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
|
||||
import client from '../client';
|
||||
import {
|
||||
getRemoteServers,
|
||||
getRemoteServer,
|
||||
@@ -8,7 +10,6 @@ import {
|
||||
testRemoteServerConnection,
|
||||
testCustomRemoteServerConnection,
|
||||
} from '../remoteServers';
|
||||
import client from '../client';
|
||||
|
||||
vi.mock('../client', () => ({
|
||||
default: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import * as security from '../security'
|
||||
|
||||
import client from '../client'
|
||||
import * as security from '../security'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { securityHeadersApi } from '../securityHeaders';
|
||||
|
||||
import client from '../client';
|
||||
import { securityHeadersApi } from '../securityHeaders';
|
||||
|
||||
vi.mock('../client', () => ({
|
||||
default: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import * as settings from '../settings'
|
||||
|
||||
import client from '../client'
|
||||
import * as settings from '../settings'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from '../../api/client'
|
||||
import { getSetupStatus, performSetup } from '../setup'
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest'
|
||||
|
||||
import client from '../client'
|
||||
import { checkUpdates, getNotifications, markNotificationRead, markAllNotificationsRead } from '../system'
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import * as uptime from '../uptime'
|
||||
|
||||
import client from '../client'
|
||||
import * as uptime from '../uptime'
|
||||
|
||||
import type { UptimeMonitor, UptimeHeartbeat } from '../uptime'
|
||||
|
||||
vi.mock('../client')
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import client from '../client'
|
||||
import { getProfile, regenerateApiKey, updateProfile } from '../users'
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from '../client'
|
||||
import {
|
||||
listUsers,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { getWebSocketConnections, getWebSocketStats } from '../websocket';
|
||||
|
||||
import client from '../client';
|
||||
import { getWebSocketConnections, getWebSocketStats } from '../websocket';
|
||||
|
||||
vi.mock('../client');
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import client from './client'
|
||||
|
||||
import {
|
||||
getAuditLogs,
|
||||
getAuditLog,
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
type AuditLog,
|
||||
type AuditLogFilters,
|
||||
} from './auditLogs'
|
||||
import client from './client'
|
||||
|
||||
vi.mock('./client', () => ({
|
||||
default: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import client from './client'
|
||||
|
||||
import type { DNSProvider } from './dnsProviders'
|
||||
|
||||
/** DNS provider detection result */
|
||||
|
||||
@@ -8,8 +8,8 @@ vi.mock('./client', () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
import { getFeatureFlags, updateFeatureFlags } from './featureFlags'
|
||||
import client from './client'
|
||||
import { getFeatureFlags, updateFeatureFlags } from './featureFlags'
|
||||
|
||||
describe('featureFlags API', () => {
|
||||
it('fetches feature flags', async () => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
|
||||
import client from './client'
|
||||
import { getLogs, getLogContent, downloadLog, connectLiveLogs, connectSecurityLogs } from './logs'
|
||||
import type { LiveLogEntry, SecurityLogEntry } from './logs'
|
||||
import { getLogs, getLogContent, downloadLog, connectLiveLogs, connectSecurityLogs, type LiveLogEntry, type SecurityLogEntry } from './logs'
|
||||
|
||||
|
||||
vi.mock('./client', () => ({
|
||||
default: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from './client'
|
||||
import {
|
||||
getProviders,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from './client'
|
||||
import {
|
||||
listUsers,
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { X, Plus, ExternalLink, Shield, AlertTriangle, Info, Download, Trash2 } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
import { Button } from './ui/Button';
|
||||
import { Input } from './ui/Input';
|
||||
import { Switch } from './ui/Switch';
|
||||
import { X, Plus, ExternalLink, Shield, AlertTriangle, Info, Download, Trash2 } from 'lucide-react';
|
||||
import type { AccessList, AccessListRule } from '../api/accessLists';
|
||||
import { SECURITY_PRESETS, calculateTotalIPs, formatIPCount, type SecurityPreset } from '../data/securityPresets';
|
||||
import { getMyIP } from '../api/system';
|
||||
import toast from 'react-hot-toast';
|
||||
import { SECURITY_PRESETS, calculateTotalIPs, formatIPCount, type SecurityPreset } from '../data/securityPresets';
|
||||
|
||||
import type { AccessList, AccessListRule } from '../api/accessLists';
|
||||
|
||||
|
||||
|
||||
interface AccessListFormProps {
|
||||
initialData?: AccessList;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useAccessLists } from '../hooks/useAccessLists';
|
||||
import { ExternalLink } from 'lucide-react';
|
||||
|
||||
import { useAccessLists } from '../hooks/useAccessLists';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Plus, X, AlertCircle, Check, Code } from 'lucide-react';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
import { Alert } from './ui/Alert';
|
||||
import { Badge } from './ui/Badge';
|
||||
import { Button } from './ui/Button';
|
||||
import { Card } from './ui/Card';
|
||||
import { Input } from './ui/Input';
|
||||
import { NativeSelect } from './ui/NativeSelect';
|
||||
import { Card } from './ui/Card';
|
||||
import { Badge } from './ui/Badge';
|
||||
import { Alert } from './ui/Alert';
|
||||
|
||||
import type { CSPDirective } from '../api/securityHeaders';
|
||||
|
||||
interface CSPBuilderProps {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { useState, useMemo } from 'react'
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { Trash2, ChevronUp, ChevronDown } from 'lucide-react'
|
||||
import { useCertificates } from '../hooks/useCertificates'
|
||||
import { deleteCertificate } from '../api/certificates'
|
||||
import { useProxyHosts } from '../hooks/useProxyHosts'
|
||||
import { createBackup } from '../api/backups'
|
||||
import { useState, useMemo } from 'react'
|
||||
|
||||
import { LoadingSpinner, ConfigReloadOverlay } from './LoadingStates'
|
||||
import { createBackup } from '../api/backups'
|
||||
import { deleteCertificate } from '../api/certificates'
|
||||
import { useCertificates } from '../hooks/useCertificates'
|
||||
import { useProxyHosts } from '../hooks/useProxyHosts'
|
||||
import { toast } from '../utils/toast'
|
||||
|
||||
type SortColumn = 'name' | 'expires'
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { FileKey, Loader2 } from 'lucide-react'
|
||||
import { useMemo } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { FileKey, Loader2 } from 'lucide-react'
|
||||
|
||||
import { Card, CardHeader, CardContent, Badge, Skeleton, Progress } from './ui'
|
||||
|
||||
import type { Certificate } from '../api/certificates'
|
||||
import type { ProxyHost } from '../api/proxyHosts'
|
||||
|
||||
@@ -21,15 +23,15 @@ export default function CertificateStatusCard({ certificates, hosts, isLoading }
|
||||
// so we match by domain name instead
|
||||
const certifiedDomains = useMemo(() => {
|
||||
const domains = new Set<string>()
|
||||
certificates.forEach(cert => {
|
||||
for (const cert of certificates) {
|
||||
// Handle missing or undefined domain field
|
||||
if (!cert.domain) return
|
||||
if (!cert.domain) continue
|
||||
// Certificate domain field can be comma-separated
|
||||
cert.domain.split(',').forEach(d => {
|
||||
for (const d of cert.domain.split(',')) {
|
||||
const trimmed = d.trim().toLowerCase()
|
||||
if (trimmed) domains.add(trimmed)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
return domains
|
||||
}, [certificates])
|
||||
|
||||
@@ -38,13 +40,13 @@ export default function CertificateStatusCard({ certificates, hosts, isLoading }
|
||||
const sslHosts = hosts.filter(h => h.ssl_forced && h.enabled)
|
||||
|
||||
let withCerts = 0
|
||||
sslHosts.forEach(host => {
|
||||
for (const host of sslHosts) {
|
||||
// Check if any of the host's domains have a certificate
|
||||
const hostDomains = host.domain_names.split(',').map(d => d.trim().toLowerCase())
|
||||
if (hostDomains.some(domain => certifiedDomains.has(domain))) {
|
||||
withCerts++
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
pendingCount: sslHosts.length - withCerts,
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Copy, Check, Key, AlertCircle } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { Badge } from './ui/Badge'
|
||||
import { Button } from './ui/Button'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from './ui/Card'
|
||||
import { Badge } from './ui/Badge'
|
||||
import { Skeleton } from './ui/Skeleton'
|
||||
import { toast } from '../utils/toast'
|
||||
import client from '../api/client'
|
||||
import { toast } from '../utils/toast'
|
||||
|
||||
interface BouncerInfo {
|
||||
name: string
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Copy, Check, AlertTriangle, X, Eye, EyeOff } from 'lucide-react'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { Alert } from './ui/Alert'
|
||||
import { Button } from './ui/Button'
|
||||
import { toast } from '../utils/toast'
|
||||
import { getCrowdsecKeyStatus, type CrowdSecKeyStatus } from '../api/crowdsec'
|
||||
import { toast } from '../utils/toast'
|
||||
|
||||
const DISMISSAL_STORAGE_KEY = 'crowdsec-key-warning-dismissed'
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { CheckCircle2, AlertCircle, Info } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { Badge, Button, Alert } from './ui'
|
||||
|
||||
import type { DetectionResult } from '../api/dnsDetection'
|
||||
import type { DNSProvider } from '../api/dnsProviders'
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { formatDistanceToNow } from 'date-fns'
|
||||
import {
|
||||
Edit,
|
||||
Trash2,
|
||||
@@ -9,7 +8,9 @@ import {
|
||||
XCircle,
|
||||
AlertTriangle,
|
||||
} from 'lucide-react'
|
||||
import { formatDistanceToNow } from 'date-fns'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
@@ -24,6 +25,7 @@ import {
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
} from './ui'
|
||||
|
||||
import type { DNSProvider } from '../api/dnsProviders'
|
||||
|
||||
interface DNSProviderCardProps {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { ChevronDown, ChevronUp, ExternalLink, CheckCircle, XCircle, Settings } from 'lucide-react'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ChevronDown, ChevronUp, ExternalLink, CheckCircle, XCircle, Settings } from 'lucide-react'
|
||||
|
||||
import CredentialManager from './CredentialManager'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -19,11 +21,11 @@ import {
|
||||
Alert,
|
||||
Textarea,
|
||||
} from './ui'
|
||||
import { useDNSProviderTypes, useDNSProviderMutations, type DNSProvider } from '../hooks/useDNSProviders'
|
||||
import type { DNSProviderRequest, DNSProviderTypeInfo } from '../api/dnsProviders'
|
||||
import { defaultProviderSchemas } from '../data/dnsProviderSchemas'
|
||||
import { useEnableMultiCredentials, useCredentials } from '../hooks/useCredentials'
|
||||
import CredentialManager from './CredentialManager'
|
||||
import { useDNSProviderTypes, useDNSProviderMutations, type DNSProvider } from '../hooks/useDNSProviders'
|
||||
|
||||
import type { DNSProviderRequest, DNSProviderTypeInfo } from '../api/dnsProviders'
|
||||
|
||||
interface DNSProviderFormProps {
|
||||
open: boolean
|
||||
@@ -136,11 +138,7 @@ export default function DNSProviderForm({
|
||||
}
|
||||
|
||||
try {
|
||||
if (provider) {
|
||||
await updateMutation.mutateAsync({ id: provider.id, data })
|
||||
} else {
|
||||
await createMutation.mutateAsync(data)
|
||||
}
|
||||
await (provider ? updateMutation.mutateAsync({ id: provider.id, data }) : createMutation.mutateAsync(data));
|
||||
onSuccess()
|
||||
onOpenChange(false)
|
||||
resetForm()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Star } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react'
|
||||
import { AlertTriangle, CheckCircle2 } from 'lucide-react'
|
||||
import React, { useState } from 'react'
|
||||
|
||||
interface HostPreview {
|
||||
domain_names: string
|
||||
@@ -48,10 +48,10 @@ export default function ImportReviewTable({ hosts, conflicts, conflictDetails, e
|
||||
})
|
||||
const [names, setNames] = useState<Record<string, string>>(() => {
|
||||
const init: Record<string, string> = {}
|
||||
hosts.forEach((h) => {
|
||||
for (const h of hosts) {
|
||||
// Default name to domain name (first domain if comma-separated)
|
||||
init[h.domain_names] = h.name || h.domain_names.split(',')[0].trim()
|
||||
})
|
||||
}
|
||||
return init
|
||||
})
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
||||
import ImportSitesModal from './ImportSitesModal'
|
||||
import { vi } from 'vitest'
|
||||
import { CaddyFile } from '../api/import'
|
||||
|
||||
import ImportSitesModal from './ImportSitesModal'
|
||||
import { type CaddyFile } from '../api/import'
|
||||
|
||||
// Mock the upload API used by the component
|
||||
const mockUpload = vi.fn()
|
||||
@@ -37,8 +38,8 @@ describe('ImportSitesModal', () => {
|
||||
expect(textareasAfterRemove.length).toBe(1)
|
||||
|
||||
// type into textarea
|
||||
const ta = screen.getAllByRole('textbox').filter(el => el.tagName === 'TEXTAREA')[0]
|
||||
fireEvent.change(ta, { target: { value: 'example.com { reverse_proxy 127.0.0.1:8080 }' } })
|
||||
const ta = screen.getAllByRole('textbox').find(el => el.tagName === 'TEXTAREA')
|
||||
fireEvent.change(ta!, { target: { value: 'example.com { reverse_proxy 127.0.0.1:8080 }' } })
|
||||
expect((ta as HTMLTextAreaElement).value).toContain('example.com')
|
||||
})
|
||||
|
||||
@@ -94,6 +95,6 @@ describe('ImportSitesModal', () => {
|
||||
fireEvent.click(screen.getByText('Parse and Review'))
|
||||
|
||||
// error message appears
|
||||
await waitFor(() => expect(screen.getByText(/upload-failed|Upload failed/i)).toBeInTheDocument())
|
||||
expect(await screen.findByText(/upload-failed|Upload failed/i)).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useState } from 'react'
|
||||
import { uploadCaddyfilesMulti, CaddyFile } from '../api/import'
|
||||
|
||||
import { uploadCaddyfilesMulti, type CaddyFile } from '../api/import'
|
||||
|
||||
type Props = {
|
||||
visible: boolean
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Globe } from 'lucide-react'
|
||||
|
||||
import { type Language } from '../context/LanguageContextValue'
|
||||
import { useLanguage } from '../hooks/useLanguage'
|
||||
import { Language } from '../context/LanguageContextValue'
|
||||
|
||||
const languageOptions: { code: Language; label: string; nativeLabel: string }[] = [
|
||||
{ code: 'en', label: 'English', nativeLabel: 'English' },
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { ReactNode, useState, useEffect } from 'react'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Menu, ChevronDown, ChevronRight } from 'lucide-react'
|
||||
import { type ReactNode, useState, useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ThemeToggle } from './ThemeToggle'
|
||||
import { Button } from './ui/Button'
|
||||
import { useAuth } from '../hooks/useAuth'
|
||||
import { checkHealth } from '../api/health'
|
||||
import { getFeatureFlags } from '../api/featureFlags'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
|
||||
import NotificationCenter from './NotificationCenter'
|
||||
import SystemStatus from './SystemStatus'
|
||||
import { Menu, ChevronDown, ChevronRight } from 'lucide-react'
|
||||
import { ThemeToggle } from './ThemeToggle'
|
||||
import { Button } from './ui/Button'
|
||||
import { getFeatureFlags } from '../api/featureFlags'
|
||||
import { checkHealth } from '../api/health'
|
||||
import { useAuth } from '../hooks/useAuth'
|
||||
|
||||
|
||||
interface LayoutProps {
|
||||
children: ReactNode
|
||||
@@ -151,7 +153,7 @@ export default function Layout({ children }: LayoutProps) {
|
||||
{isCollapsed ? (
|
||||
<img src="/logo.png" alt="Charon" className="h-12 w-auto" />
|
||||
) : (
|
||||
<img src="/banner.png" alt="Charon" className="h-14 w-auto max-max-w-50 object-contain" />
|
||||
<img src="/banner.png" alt="Charon" className="h-14 w-auto max-w-[200px] object-contain" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { Pause, Play, Trash2, Filter, Shield, Globe } from 'lucide-react';
|
||||
import { useEffect, useRef, useState, useCallback } from 'react';
|
||||
|
||||
import {
|
||||
connectLiveLogs,
|
||||
connectSecurityLogs,
|
||||
LiveLogEntry,
|
||||
LiveLogFilter,
|
||||
SecurityLogEntry,
|
||||
SecurityLogFilter,
|
||||
type LiveLogEntry,
|
||||
type LiveLogFilter,
|
||||
type SecurityLogEntry,
|
||||
type SecurityLogFilter,
|
||||
} from '../api/logs';
|
||||
import { Button } from './ui/Button';
|
||||
import { Pause, Play, Trash2, Filter, Shield, Globe } from 'lucide-react';
|
||||
|
||||
/**
|
||||
* Log viewing mode: application logs vs security access logs
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Search, Download, RefreshCw } from 'lucide-react';
|
||||
import React from 'react';
|
||||
|
||||
import { Button } from './ui/Button';
|
||||
|
||||
interface LogFiltersProps {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { CaddyAccessLog } from '../api/logs';
|
||||
import { format } from 'date-fns';
|
||||
import React from 'react';
|
||||
|
||||
import { type CaddyAccessLog } from '../api/logs';
|
||||
|
||||
interface LogTableProps {
|
||||
logs: CaddyAccessLog[];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, type FC } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { Bell, X, Info, AlertTriangle, AlertCircle, CheckCircle, ExternalLink } from 'lucide-react';
|
||||
import { useState, type FC } from 'react';
|
||||
|
||||
import { getNotifications, markNotificationRead, markAllNotificationsRead, checkUpdates } from '../api/system';
|
||||
|
||||
const NotificationCenter: FC = () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import { calculatePasswordStrength } from '../utils/passwordStrength';
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Plus, X, Code } from 'lucide-react';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
import { Alert } from './ui/Alert';
|
||||
import { Badge } from './ui/Badge';
|
||||
import { Button } from './ui/Button';
|
||||
import { Card } from './ui/Card';
|
||||
import { Input } from './ui/Input';
|
||||
import { NativeSelect } from './ui/NativeSelect';
|
||||
import { Card } from './ui/Card';
|
||||
import { Badge } from './ui/Badge';
|
||||
import { Alert } from './ui/Alert';
|
||||
|
||||
interface PermissionsPolicyItem {
|
||||
feature: string;
|
||||
@@ -127,11 +128,11 @@ export function PermissionsPolicyBuilder({ value, onChange }: PermissionsPolicyB
|
||||
|
||||
// Merge with existing (don't duplicate)
|
||||
const merged = [...policies];
|
||||
newPolicies.forEach((newPolicy) => {
|
||||
for (const newPolicy of newPolicies) {
|
||||
if (!merged.some((p) => p.feature === newPolicy.feature)) {
|
||||
merged.push(newPolicy);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updatePolicies(merged);
|
||||
};
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
import { useState, useEffect, useRef, useCallback } from 'react'
|
||||
import { CircleHelp, AlertCircle, Check, X, Loader2, Copy, Info, AlertTriangle } from 'lucide-react'
|
||||
import { useState, useEffect, useRef, useCallback } from 'react'
|
||||
import { toast } from 'react-hot-toast'
|
||||
import type { ProxyHost, ApplicationPreset } from '../api/proxyHosts'
|
||||
import { testProxyHostConnection } from '../api/proxyHosts'
|
||||
import { syncMonitors } from '../api/uptime'
|
||||
import { useRemoteServers } from '../hooks/useRemoteServers'
|
||||
import { useDomains } from '../hooks/useDomains'
|
||||
import { useCertificates } from '../hooks/useCertificates'
|
||||
import { useDocker } from '../hooks/useDocker'
|
||||
import AccessListSelector from './AccessListSelector'
|
||||
import { useSecurityHeaderProfiles } from '../hooks/useSecurityHeaders'
|
||||
import { SecurityScoreDisplay } from './SecurityScoreDisplay'
|
||||
import { parse } from 'tldts'
|
||||
|
||||
import AccessListSelector from './AccessListSelector'
|
||||
import { DNSDetectionResult } from './DNSDetectionResult'
|
||||
import DNSProviderSelector from './DNSProviderSelector'
|
||||
import { SecurityScoreDisplay } from './SecurityScoreDisplay'
|
||||
import { testProxyHostConnection, type ProxyHost, type ApplicationPreset } from '../api/proxyHosts'
|
||||
import { syncMonitors } from '../api/uptime'
|
||||
import { useCertificates } from '../hooks/useCertificates'
|
||||
import { useDetectDNSProvider } from '../hooks/useDNSDetection'
|
||||
import { useDocker } from '../hooks/useDocker'
|
||||
import { useDomains } from '../hooks/useDomains'
|
||||
import { useRemoteServers } from '../hooks/useRemoteServers'
|
||||
import { useSecurityHeaderProfiles } from '../hooks/useSecurityHeaders'
|
||||
import { Alert } from './ui/Alert'
|
||||
import { isLikelyDockerContainerIP, isPrivateOrDockerIP } from '../utils/validation'
|
||||
import DNSProviderSelector from './DNSProviderSelector'
|
||||
import { useDetectDNSProvider } from '../hooks/useDNSDetection'
|
||||
import { DNSDetectionResult } from './DNSDetectionResult'
|
||||
import type { DNSProvider } from '../api/dnsProviders'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -26,6 +25,8 @@ import {
|
||||
SelectValue,
|
||||
} from './ui/Select'
|
||||
|
||||
import type { DNSProvider } from '../api/dnsProviders'
|
||||
|
||||
// Application preset configurations
|
||||
const APPLICATION_PRESETS: { value: ApplicationPreset; label: string; description: string }[] = [
|
||||
{ value: 'none', label: 'None', description: 'Standard reverse proxy' },
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Loader2, Check, X, CircleHelp } from 'lucide-react'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { type RemoteServer, testCustomRemoteServerConnection } from '../api/remoteServers'
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Navigate, useLocation } from 'react-router-dom';
|
||||
import { useAuth } from '../hooks/useAuth';
|
||||
|
||||
import { LoadingOverlay } from './LoadingStates';
|
||||
import { useAuth } from '../hooks/useAuth';
|
||||
|
||||
const RequireAuth: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const { isAuthenticated, isLoading, user } = useAuth();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import { Navigate } from 'react-router-dom'
|
||||
|
||||
import { useAuth } from '../hooks/useAuth'
|
||||
|
||||
interface RequireRoleProps {
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { AlertTriangle, Save, X } from 'lucide-react';
|
||||
import { Button } from './ui/Button';
|
||||
import { Input } from './ui/Input';
|
||||
import { Textarea } from './ui/Textarea';
|
||||
import { Switch } from './ui/Switch';
|
||||
import { NativeSelect } from './ui/NativeSelect';
|
||||
import { Card } from './ui/Card';
|
||||
import { Alert } from './ui/Alert';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
import { CSPBuilder } from './CSPBuilder';
|
||||
import { PermissionsPolicyBuilder } from './PermissionsPolicyBuilder';
|
||||
import { SecurityScoreDisplay } from './SecurityScoreDisplay';
|
||||
import { Alert } from './ui/Alert';
|
||||
import { Button } from './ui/Button';
|
||||
import { Card } from './ui/Card';
|
||||
import { Input } from './ui/Input';
|
||||
import { NativeSelect } from './ui/NativeSelect';
|
||||
import { Switch } from './ui/Switch';
|
||||
import { Textarea } from './ui/Textarea';
|
||||
import { useCalculateSecurityScore } from '../hooks/useSecurityHeaders';
|
||||
|
||||
import type { SecurityHeaderProfile, CreateProfileRequest } from '../api/securityHeaders';
|
||||
|
||||
interface SecurityHeaderProfileFormProps {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useState } from 'react';
|
||||
import { Shield, ChevronDown, ChevronRight, AlertCircle } from 'lucide-react';
|
||||
import { Card } from './ui/Card';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { Badge } from './ui/Badge';
|
||||
import { Card } from './ui/Card';
|
||||
import { Progress } from './ui/Progress';
|
||||
|
||||
interface SecurityScoreDisplayProps {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { getSetupStatus } from '../api/setup';
|
||||
|
||||
interface SetupGuardProps {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import React from 'react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { checkUpdates } from '../api/system';
|
||||
|
||||
import type React from 'react';
|
||||
|
||||
|
||||
const SystemStatus: React.FC = () => {
|
||||
// We still query for updates here to keep the cache fresh,
|
||||
// but the UI is now handled by NotificationCenter
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { toastCallbacks, Toast } from '../utils/toast'
|
||||
|
||||
import { toastCallbacks, type Toast } from '../utils/toast'
|
||||
|
||||
export function ToastContainer() {
|
||||
const [toasts, setToasts] = useState<Toast[]>([])
|
||||
@@ -29,7 +30,7 @@ export function ToastContainer() {
|
||||
role={toast.type === 'error' || toast.type === 'warning' ? 'alert' : 'status'}
|
||||
aria-live={toast.type === 'error' || toast.type === 'warning' ? 'assertive' : 'polite'}
|
||||
data-testid={`toast-${toast.type}`}
|
||||
className={`pointer-events-auto px-4 py-3 rounded-lg shadow-lg flex items-center gap-3 min-w-75 max-w-125 animate-slide-in ${
|
||||
className={`pointer-events-auto px-4 py-3 rounded-lg shadow-lg flex items-center gap-3 min-w-[300px] max-w-[500px] animate-slide-in ${
|
||||
toast.type === 'success'
|
||||
? 'bg-green-600 text-white'
|
||||
: toast.type === 'error'
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Activity, CheckCircle2, XCircle, AlertCircle, ArrowRight } from 'lucide-react'
|
||||
import { getMonitors } from '../api/uptime'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
import { Card, CardHeader, CardContent, Badge, Skeleton } from './ui'
|
||||
import { getMonitors } from '../api/uptime'
|
||||
|
||||
export default function UptimeWidget() {
|
||||
const { data: monitors, isLoading } = useQuery({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { Wifi, WifiOff, Activity, Clock, Filter, Globe } from 'lucide-react';
|
||||
import { useWebSocketConnections, useWebSocketStats } from '../hooks/useWebSocketStatus';
|
||||
import { useState } from 'react';
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
@@ -11,7 +12,8 @@ import {
|
||||
Skeleton,
|
||||
Alert,
|
||||
} from './ui';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
import { useWebSocketConnections, useWebSocketStats } from '../hooks/useWebSocketStatus';
|
||||
|
||||
|
||||
interface WebSocketStatusCardProps {
|
||||
className?: string;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { AccessListForm } from '../AccessListForm';
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import * as systemApi from '../../api/system';
|
||||
import toast from 'react-hot-toast';
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
|
||||
import * as systemApi from '../../api/system';
|
||||
import { AccessListForm } from '../AccessListForm';
|
||||
|
||||
vi.mock('../../api/system', () => ({
|
||||
getMyIP: vi.fn(),
|
||||
@@ -100,12 +101,9 @@ describe('AccessListForm', () => {
|
||||
// We use querySelector because the icon is inside the button
|
||||
const removeButton = screen.getAllByRole('button').find(b => b.querySelector('.lucide-x'));
|
||||
|
||||
if (removeButton) {
|
||||
await user.click(removeButton);
|
||||
expect(screen.queryByText('1.2.3.4')).not.toBeInTheDocument();
|
||||
} else {
|
||||
throw new Error('Remove button not found');
|
||||
}
|
||||
expect(removeButton).toBeDefined();
|
||||
await user.click(removeButton!);
|
||||
expect(screen.queryByText('1.2.3.4')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('fetches and populates My IP', async () => {
|
||||
@@ -416,10 +414,9 @@ describe('AccessListForm', () => {
|
||||
|
||||
// Look for Apply buttons in presets
|
||||
const applyButtons = screen.getAllByRole('button', { name: /Apply/i });
|
||||
if (applyButtons.length > 0) {
|
||||
await user.click(applyButtons[0]);
|
||||
expect(toast.success).toHaveBeenCalled();
|
||||
}
|
||||
expect(applyButtons.length).toBeGreaterThan(0);
|
||||
await user.click(applyButtons[0]);
|
||||
expect(toast.success).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('applies geo preset correctly', async () => {
|
||||
@@ -434,10 +431,9 @@ describe('AccessListForm', () => {
|
||||
await user.click(showBtn);
|
||||
|
||||
const applyButtons = screen.getAllByRole('button', { name: /Apply/i });
|
||||
if (applyButtons.length > 0) {
|
||||
await user.click(applyButtons[0]);
|
||||
expect(toast.success).toHaveBeenCalled();
|
||||
}
|
||||
expect(applyButtons.length).toBeGreaterThan(0);
|
||||
await user.click(applyButtons[0]);
|
||||
expect(toast.success).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('toggles enabled switch', async () => {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import AccessListSelector from '../AccessListSelector';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
import * as useAccessListsHook from '../../hooks/useAccessLists';
|
||||
import AccessListSelector from '../AccessListSelector';
|
||||
|
||||
vi.mock('../../hooks/useAccessLists');
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import AccessListSelector from '../AccessListSelector';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
|
||||
import * as useAccessListsHook from '../../hooks/useAccessLists';
|
||||
import AccessListSelector from '../AccessListSelector';
|
||||
|
||||
import type { AccessList } from '../../api/accessLists';
|
||||
|
||||
// Mock the hooks
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
|
||||
import { CSPBuilder } from '../CSPBuilder';
|
||||
|
||||
describe('CSPBuilder', () => {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { QueryClientProvider } from '@tanstack/react-query'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { QueryClientProvider } from '@tanstack/react-query'
|
||||
import CertificateList from '../CertificateList'
|
||||
import { createTestQueryClient } from '../../test/createTestQueryClient'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import { useCertificates } from '../../hooks/useCertificates'
|
||||
import { useProxyHosts } from '../../hooks/useProxyHosts'
|
||||
import { createTestQueryClient } from '../../test/createTestQueryClient'
|
||||
import CertificateList from '../CertificateList'
|
||||
|
||||
import type { Certificate } from '../../api/certificates'
|
||||
import type { ProxyHost } from '../../api/proxyHosts'
|
||||
|
||||
@@ -14,7 +16,7 @@ vi.mock('../../hooks/useCertificates', () => ({
|
||||
}))
|
||||
|
||||
vi.mock('../../api/certificates', () => ({
|
||||
deleteCertificate: vi.fn(async () => undefined),
|
||||
deleteCertificate: vi.fn(async () => {}),
|
||||
}))
|
||||
|
||||
vi.mock('../../api/backups', () => ({
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
import CertificateStatusCard from '../CertificateStatusCard'
|
||||
|
||||
import type { Certificate } from '../../api/certificates'
|
||||
import type { ProxyHost } from '../../api/proxyHosts'
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { QueryClient, QueryClientProvider, type UseMutationResult } from '@tanstack/react-query'
|
||||
import { render, screen, waitFor, within } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { QueryClient, QueryClientProvider, type UseMutationResult } from '@tanstack/react-query'
|
||||
import CredentialManager from '../CredentialManager'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import {
|
||||
useCredentials,
|
||||
useCreateCredential,
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
useDeleteCredential,
|
||||
useTestCredential,
|
||||
} from '../../hooks/useCredentials'
|
||||
import CredentialManager from '../CredentialManager'
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
@@ -19,8 +20,8 @@ vi.mock('react-i18next', () => ({
|
||||
},
|
||||
}),
|
||||
}))
|
||||
import type { DNSProvider, DNSProviderTypeInfo } from '../../api/dnsProviders'
|
||||
import type { CredentialRequest, CredentialTestResult, DNSProviderCredential } from '../../api/credentials'
|
||||
import type { DNSProvider, DNSProviderTypeInfo } from '../../api/dnsProviders'
|
||||
|
||||
vi.mock('../../hooks/useCredentials')
|
||||
vi.mock('../../utils/toast', () => ({
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
* CrowdSecBouncerKeyDisplay Component Tests
|
||||
* Tests the bouncer API key display functionality for CrowdSec integration
|
||||
*/
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import client from '../../api/client'
|
||||
import { CrowdSecBouncerKeyDisplay } from '../CrowdSecBouncerKeyDisplay'
|
||||
|
||||
// Create mock axios instance
|
||||
@@ -48,9 +50,6 @@ vi.mock('react-i18next', () => ({
|
||||
}),
|
||||
}))
|
||||
|
||||
// Re-import client after mocking axios
|
||||
import client from '../../api/client'
|
||||
|
||||
const mockBouncerInfo = {
|
||||
name: 'caddy-bouncer',
|
||||
key_preview: 'abc***xyz',
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { CrowdSecKeyWarning } from '../CrowdSecKeyWarning'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import * as crowdsecApi from '../../api/crowdsec'
|
||||
import { toast } from '../../utils/toast'
|
||||
import { CrowdSecKeyWarning } from '../CrowdSecKeyWarning'
|
||||
|
||||
vi.mock('../../api/crowdsec')
|
||||
vi.mock('react-i18next', () => ({
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
|
||||
import { DNSDetectionResult } from '../DNSDetectionResult'
|
||||
|
||||
import type { DetectionResult } from '../../api/dnsDetection'
|
||||
import type { DNSProvider } from '../../api/dnsProviders'
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import DNSProviderForm from '../DNSProviderForm';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
import DNSProviderForm from '../DNSProviderForm';
|
||||
|
||||
// Mock the hooks
|
||||
const mockCreateMutation = {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import DNSProviderSelector from '../DNSProviderSelector'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import { useDNSProviders } from '../../hooks/useDNSProviders'
|
||||
import DNSProviderSelector from '../DNSProviderSelector'
|
||||
|
||||
import type { DNSProvider } from '../../api/dnsProviders'
|
||||
|
||||
vi.mock('../../hooks/useDNSProviders')
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
import { render, screen, fireEvent } from '@testing-library/react'
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
|
||||
import ImportReviewTable from '../ImportReviewTable'
|
||||
|
||||
describe('ImportReviewTable - Status Display', () => {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import ImportReviewTable from '../ImportReviewTable'
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest'
|
||||
|
||||
import { mockImportPreview } from '../../test/mockData'
|
||||
import ImportReviewTable from '../ImportReviewTable'
|
||||
|
||||
describe('ImportReviewTable', () => {
|
||||
const mockOnCommit = vi.fn(() => Promise.resolve())
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
import { render, screen, fireEvent } from '@testing-library/react'
|
||||
import { LanguageSelector } from '../LanguageSelector'
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
|
||||
import { LanguageProvider } from '../../context/LanguageContext'
|
||||
import { LanguageSelector } from '../LanguageSelector'
|
||||
|
||||
// Mock i18next
|
||||
vi.mock('react-i18next', () => ({
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { ReactNode } from 'react'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { type ReactNode } from 'react'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import Layout from '../Layout'
|
||||
import { ThemeProvider } from '../../context/ThemeContext'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import * as featureFlagsApi from '../../api/featureFlags'
|
||||
import { ThemeProvider } from '../../context/ThemeContext'
|
||||
import Layout from '../Layout'
|
||||
|
||||
const mockLogout = vi.fn()
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { render, screen, waitFor, act } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { LiveLogViewer } from '../LiveLogViewer';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
|
||||
import * as logsApi from '../../api/logs';
|
||||
import { LiveLogViewer } from '../LiveLogViewer';
|
||||
|
||||
// Mock the connectLiveLogs and connectSecurityLogs functions
|
||||
vi.mock('../../api/logs', async () => {
|
||||
@@ -320,7 +321,7 @@ describe('LiveLogViewer', () => {
|
||||
mockOnMessage({ level: 'error', timestamp: '2025-12-09T10:30:01Z', message: 'Hidden' });
|
||||
}
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Visible')).toBeTruthy());
|
||||
expect(await screen.findByText('Visible')).toBeTruthy();
|
||||
|
||||
await user.type(screen.getByPlaceholderText('Filter by text...'), 'nomatch');
|
||||
|
||||
@@ -332,13 +333,13 @@ describe('LiveLogViewer', () => {
|
||||
it('marks connection as disconnected when WebSocket closes', async () => {
|
||||
render(<LiveLogViewer />);
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Connected')).toBeTruthy());
|
||||
expect(await screen.findByText('Connected')).toBeTruthy();
|
||||
|
||||
act(() => {
|
||||
mockOnClose?.();
|
||||
});
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Disconnected')).toBeTruthy());
|
||||
expect(await screen.findByText('Disconnected')).toBeTruthy();
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
@@ -357,7 +358,7 @@ describe('LiveLogViewer', () => {
|
||||
render(<LiveLogViewer mode="security" />);
|
||||
|
||||
// Wait for connection to establish
|
||||
await waitFor(() => expect(screen.getByText('Connected')).toBeTruthy());
|
||||
expect(await screen.findByText('Connected')).toBeTruthy();
|
||||
|
||||
const securityLog: logsApi.SecurityLogEntry = {
|
||||
timestamp: '2025-12-12T10:30:00Z',
|
||||
@@ -390,7 +391,7 @@ describe('LiveLogViewer', () => {
|
||||
render(<LiveLogViewer mode="security" />);
|
||||
|
||||
// Wait for connection to establish
|
||||
await waitFor(() => expect(screen.getByText('Connected')).toBeTruthy());
|
||||
expect(await screen.findByText('Connected')).toBeTruthy();
|
||||
|
||||
const blockedLog: logsApi.SecurityLogEntry = {
|
||||
timestamp: '2025-12-12T10:30:00Z',
|
||||
@@ -446,7 +447,7 @@ describe('LiveLogViewer', () => {
|
||||
render(<LiveLogViewer mode="security" />);
|
||||
|
||||
// Wait for connection
|
||||
await waitFor(() => expect(screen.getByText('Connected')).toBeTruthy());
|
||||
expect(await screen.findByText('Connected')).toBeTruthy();
|
||||
|
||||
// Add logs from different sources
|
||||
if (mockOnSecurityMessage) {
|
||||
@@ -523,7 +524,7 @@ describe('LiveLogViewer', () => {
|
||||
render(<LiveLogViewer mode="security" />);
|
||||
|
||||
// Wait for connection to establish
|
||||
await waitFor(() => expect(screen.getByText('Connected')).toBeTruthy());
|
||||
expect(await screen.findByText('Connected')).toBeTruthy();
|
||||
|
||||
const securityLog: logsApi.SecurityLogEntry = {
|
||||
timestamp: '2025-12-12T10:30:00Z',
|
||||
@@ -554,7 +555,7 @@ describe('LiveLogViewer', () => {
|
||||
render(<LiveLogViewer mode="security" />);
|
||||
|
||||
// Wait for connection to establish
|
||||
await waitFor(() => expect(screen.getByText('Connected')).toBeTruthy());
|
||||
expect(await screen.findByText('Connected')).toBeTruthy();
|
||||
|
||||
if (mockOnSecurityMessage) {
|
||||
mockOnSecurityMessage({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
import { CharonLoader, CharonCoinLoader, CerberusLoader, ConfigReloadOverlay } from '../LoadingStates'
|
||||
|
||||
describe('CharonLoader', () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
import {
|
||||
CharonLoader,
|
||||
CharonCoinLoader,
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { render, screen, waitFor, act } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import ManualDNSChallenge from '../dns-providers/ManualDNSChallenge'
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
|
||||
import { useChallengePoll, useManualChallengeMutations } from '../../hooks/useManualChallenge'
|
||||
import type { ManualChallenge } from '../../api/manualChallenge'
|
||||
import { toast } from '../../utils/toast'
|
||||
import ManualDNSChallenge from '../dns-providers/ManualDNSChallenge'
|
||||
|
||||
import type { ManualChallenge } from '../../api/manualChallenge'
|
||||
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('../../hooks/useManualChallenge')
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import NotificationCenter from '../NotificationCenter'
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
|
||||
import * as api from '../../api/system'
|
||||
import NotificationCenter from '../NotificationCenter'
|
||||
|
||||
// Mock the API
|
||||
vi.mock('../../api/system', () => ({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
import { PasswordStrengthMeter } from '../PasswordStrengthMeter'
|
||||
|
||||
describe('PasswordStrengthMeter', () => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { PermissionsPolicyBuilder } from '../PermissionsPolicyBuilder';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
|
||||
import { PermissionsPolicyBuilder } from '../PermissionsPolicyBuilder';
|
||||
|
||||
describe('PermissionsPolicyBuilder', () => {
|
||||
const defaultProps = {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import ProxyHostForm from '../ProxyHostForm'
|
||||
import type { ProxyHost } from '../../api/proxyHosts'
|
||||
import { mockRemoteServers } from '../../test/mockData'
|
||||
import { toast } from 'react-hot-toast'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import { mockRemoteServers } from '../../test/mockData'
|
||||
import ProxyHostForm from '../ProxyHostForm'
|
||||
|
||||
import type { ProxyHost } from '../../api/proxyHosts'
|
||||
|
||||
|
||||
// Mock the hooks
|
||||
vi.mock('../../hooks/useRemoteServers', () => ({
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import ProxyHostForm from '../ProxyHostForm'
|
||||
import type { ProxyHost } from '../../api/proxyHosts'
|
||||
import type { AccessList } from '../../api/accessLists'
|
||||
import type { SecurityHeaderProfile } from '../../api/securityHeaders'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
import { useAccessLists } from '../../hooks/useAccessLists'
|
||||
import { useSecurityHeaderProfiles } from '../../hooks/useSecurityHeaders'
|
||||
import ProxyHostForm from '../ProxyHostForm'
|
||||
|
||||
import type { AccessList } from '../../api/accessLists'
|
||||
import type { ProxyHost } from '../../api/proxyHosts'
|
||||
import type { SecurityHeaderProfile } from '../../api/securityHeaders'
|
||||
|
||||
// Mock all required hooks
|
||||
vi.mock('../../hooks/useRemoteServers', () => ({
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
import ProxyHostForm from '../ProxyHostForm';
|
||||
|
||||
import type { ProxyHost } from '../../api/proxyHosts';
|
||||
|
||||
vi.mock('../../hooks/useRemoteServers', () => ({
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user