fix: enhance DNSProviders page to improve manual challenge handling and visibility of provider cards

This commit is contained in:
GitHub Actions
2026-02-15 08:29:00 +00:00
parent 96ee1d717b
commit 3d614dd8e2
3 changed files with 493 additions and 163 deletions
@@ -0,0 +1,144 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import type { ReactNode } from 'react'
import DNSProviders from '../DNSProviders'
import { renderWithQueryClient } from '../../test-utils/renderWithQueryClient'
import { useDNSProviders, useDNSProviderMutations, type DNSProvider } from '../../hooks/useDNSProviders'
import { getChallenge } from '../../api/manualChallenge'
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key,
}),
}))
vi.mock('../../hooks/useDNSProviders', () => ({
useDNSProviders: vi.fn(),
useDNSProviderMutations: vi.fn(),
}))
vi.mock('../../api/manualChallenge', () => ({
getChallenge: vi.fn(),
}))
vi.mock('../../utils/toast', () => ({
toast: {
success: vi.fn(),
error: vi.fn(),
warning: vi.fn(),
info: vi.fn(),
},
}))
vi.mock('../../components/ui', () => ({
Button: ({ children, onClick, variant }: { children: ReactNode; onClick?: () => void; variant?: string }) => (
<button type="button" data-variant={variant} onClick={onClick}>
{children}
</button>
),
Alert: ({ children }: { children: ReactNode }) => <div role="alert">{children}</div>,
EmptyState: ({ title }: { title: string }) => <div>{title}</div>,
Skeleton: () => <div data-testid="skeleton" />,
}))
vi.mock('../../components/DNSProviderCard', () => ({
default: ({ provider }: { provider: DNSProvider }) => (
<article data-testid="provider-card">
<h3>{provider.name}</h3>
</article>
),
}))
vi.mock('../../components/DNSProviderForm', () => ({
default: () => null,
}))
vi.mock('../../components/dns-providers', () => ({
ManualDNSChallenge: ({ challenge }: { challenge: { fqdn: string } }) => (
<section data-testid="manual-dns-challenge">{challenge.fqdn}</section>
),
}))
const buildProvider = (overrides: Partial<DNSProvider> = {}): DNSProvider => ({
id: 7,
uuid: 'provider-uuid',
name: 'Seeded Provider',
provider_type: 'manual',
enabled: true,
is_default: false,
has_credentials: true,
propagation_timeout: 60,
polling_interval: 5,
success_count: 0,
failure_count: 0,
created_at: '2026-02-15T00:00:00Z',
updated_at: '2026-02-15T00:00:00Z',
...overrides,
})
describe('DNSProviders page state behavior', () => {
beforeEach(() => {
vi.clearAllMocks()
vi.mocked(useDNSProviderMutations).mockReturnValue({
deleteMutation: { mutateAsync: vi.fn() },
testMutation: { mutateAsync: vi.fn() },
createMutation: { mutateAsync: vi.fn() },
updateMutation: { mutateAsync: vi.fn() },
testCredentialsMutation: { mutateAsync: vi.fn() },
} as unknown as ReturnType<typeof useDNSProviderMutations>)
vi.mocked(useDNSProviders).mockReturnValue({
data: [buildProvider()],
isLoading: false,
refetch: vi.fn(),
} as unknown as ReturnType<typeof useDNSProviders>)
})
it('keeps provider cards visible by default without challenge fetch side effects', async () => {
renderWithQueryClient(<DNSProviders />)
expect(await screen.findByRole('heading', { name: 'Seeded Provider' })).toBeInTheDocument()
expect(getChallenge).not.toHaveBeenCalled()
expect(screen.queryByTestId('manual-dns-challenge')).not.toBeInTheDocument()
})
it('does not hide provider cards when manual challenge fetch fails', async () => {
vi.mocked(getChallenge).mockRejectedValue(new Error('not found'))
const user = userEvent.setup()
renderWithQueryClient(<DNSProviders />)
await user.click(screen.getByRole('button', { name: 'dnsProvider.manual.title' }))
await waitFor(() => {
expect(getChallenge).toHaveBeenCalledWith(7, 'active')
})
expect(screen.queryByTestId('manual-dns-challenge')).not.toBeInTheDocument()
expect(screen.getByRole('heading', { name: 'Seeded Provider' })).toBeInTheDocument()
})
it('opens manual challenge panel only after explicit action when fetch succeeds', async () => {
vi.mocked(getChallenge).mockResolvedValue({
id: 'active',
status: 'pending',
fqdn: '_acme-challenge.example.com',
value: 'token',
ttl: 300,
created_at: '2026-02-15T00:00:00Z',
expires_at: '2026-02-15T00:10:00Z',
dns_propagated: false,
})
const user = userEvent.setup()
renderWithQueryClient(<DNSProviders />)
expect(screen.queryByTestId('manual-dns-challenge')).not.toBeInTheDocument()
await user.click(screen.getByRole('button', { name: 'dnsProvider.manual.title' }))
expect(await screen.findByTestId('manual-dns-challenge')).toBeInTheDocument()
})
})