fix(frontend): remove test types from base tsconfig for CI build

The base tsconfig.json had types: ["vitest/globals", "@testing-library/jest-dom/vitest"]
which are devDependencies only installed during development. CI production
builds with npm ci --production don't include these, causing TS2688 errors.

Solution:

Remove types array from tsconfig.json (let TS auto-discover available types)
Simplify tsconfig.build.json to only exclude test files
Add triple-slash type references to test setup file
Add typecheck config to vitest.config.ts
This ensures:

Production builds work without devDependencies
Test files still have proper type definitions
No JSX.IntrinsicElements errors from missing React types
This commit is contained in:
GitHub Actions
2026-01-25 21:26:47 +00:00
parent 8612aa52e1
commit 0cd93ceb79
18 changed files with 111 additions and 91 deletions
+14 -9
View File
@@ -68,11 +68,12 @@ export default function CredentialManager({
toast.success(t('credentials.deleteSuccess', 'Credential deleted successfully'))
setDeleteConfirm(null)
refetch()
} catch (error: any) {
} catch (error: unknown) {
const err = error as { response?: { data?: { error?: string } }; message?: string }
toast.error(
t('credentials.deleteFailed', 'Failed to delete credential') +
': ' +
(error.response?.data?.error || error.message)
(err.response?.data?.error || err.message)
)
}
}
@@ -90,11 +91,12 @@ export default function CredentialManager({
toast.error(result.error || t('credentials.testFailed', 'Credential test failed'))
}
refetch()
} catch (error: any) {
} catch (error: unknown) {
const err = error as { response?: { data?: { error?: string } }; message?: string }
toast.error(
t('credentials.testFailed', 'Failed to test credential') +
': ' +
(error.response?.data?.error || error.message)
(err.response?.data?.error || err.message)
)
} finally {
setTestingId(null)
@@ -367,7 +369,8 @@ function CredentialForm({
}
}
setErrors((prev) => {
const { zone_filter, ...rest } = prev
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { zone_filter: _, ...rest } = prev
return rest
})
return true
@@ -426,11 +429,12 @@ function CredentialForm({
await createMutation.mutateAsync({ providerId, data })
}
onSuccess()
} catch (error: any) {
} catch (error: unknown) {
const err = error as { response?: { data?: { error?: string } }; message?: string }
toast.error(
t('credentials.saveFailed', 'Failed to save credential') +
': ' +
(error.response?.data?.error || error.message)
(err.response?.data?.error || err.message)
)
}
}
@@ -451,11 +455,12 @@ function CredentialForm({
} else {
toast.error(result.error || t('credentials.testFailed', 'Test failed'))
}
} catch (error: any) {
} catch (error: unknown) {
const err = error as { response?: { data?: { error?: string } }; message?: string }
toast.error(
t('credentials.testFailed', 'Test failed') +
': ' +
(error.response?.data?.error || error.message)
(err.response?.data?.error || err.message)
)
}
}
+8 -7
View File
@@ -65,7 +65,7 @@ export default function DNSProviderForm({
setPropagationTimeout(provider.propagation_timeout)
setPollingInterval(provider.polling_interval)
setIsDefault(provider.is_default)
setUseMultiCredentials((provider as any).use_multi_credentials || false)
setUseMultiCredentials((provider as { use_multi_credentials?: boolean }).use_multi_credentials || false)
setCredentials({}) // Don't pre-fill credentials (they're encrypted)
} else {
resetForm()
@@ -91,7 +91,7 @@ export default function DNSProviderForm({
// Prefer dynamic fields from API if available
if (dynamicFields) {
return {
type: dynamicFields.type as any,
type: dynamicFields.type as DNSProviderTypeInfo['type'],
name: dynamicFields.name,
fields: [
...dynamicFields.required_fields.map(f => ({ ...f, required: true })),
@@ -118,7 +118,7 @@ export default function DNSProviderForm({
const data: DNSProviderRequest = {
name: name || 'Test',
provider_type: providerType as any,
provider_type: providerType as DNSProviderRequest['provider_type'],
credentials,
propagation_timeout: propagationTimeout,
polling_interval: pollingInterval,
@@ -130,10 +130,11 @@ export default function DNSProviderForm({
success: result.success,
message: result.message || result.error || t('dnsProviders.testSuccess'),
})
} catch (error: any) {
} catch (error: unknown) {
const err = error as { response?: { data?: { error?: string } }; message?: string }
setTestResult({
success: false,
message: error.response?.data?.error || error.message || t('dnsProviders.testFailed'),
message: err.response?.data?.error || err.message || t('dnsProviders.testFailed'),
})
}
}
@@ -144,7 +145,7 @@ export default function DNSProviderForm({
const data: DNSProviderRequest = {
name,
provider_type: providerType as any,
provider_type: providerType as DNSProviderRequest['provider_type'],
credentials,
propagation_timeout: propagationTimeout,
polling_interval: pollingInterval,
@@ -348,7 +349,7 @@ export default function DNSProviderForm({
try {
await enableMultiCredsMutation.mutateAsync(provider.id)
setUseMultiCredentials(true)
} catch (error: any) {
} catch (error: unknown) {
console.error('Failed to enable multi-credentials:', error)
}
} else if (!checked && useMultiCredentials && existingCredentials?.length) {
@@ -125,27 +125,27 @@ describe('CredentialManager', () => {
data: mockCredentials,
isLoading: false,
refetch: mockRefetch,
} as any)
} as unknown as ReturnType<typeof useCredentials>)
vi.mocked(useCreateCredential).mockReturnValue({
mutateAsync: mockMutateAsync,
isPending: false,
} as any)
} as unknown as ReturnType<typeof useCreateCredential>)
vi.mocked(useUpdateCredential).mockReturnValue({
mutateAsync: mockMutateAsync,
isPending: false,
} as any)
} as unknown as ReturnType<typeof useUpdateCredential>)
vi.mocked(useDeleteCredential).mockReturnValue({
mutateAsync: mockMutateAsync,
isPending: false,
} as any)
} as unknown as ReturnType<typeof useDeleteCredential>)
vi.mocked(useTestCredential).mockReturnValue({
mutateAsync: mockMutateAsync,
isPending: false,
} as any)
} as unknown as ReturnType<typeof useTestCredential>)
})
describe('Rendering', () => {
@@ -242,7 +242,7 @@ describe('CredentialManager', () => {
data: [],
isLoading: false,
refetch: mockRefetch,
} as any)
} as unknown as ReturnType<typeof useCredentials>)
renderWithClient(
<CredentialManager
@@ -266,7 +266,7 @@ describe('CredentialManager', () => {
data: [],
isLoading: false,
refetch: mockRefetch,
} as any)
} as unknown as ReturnType<typeof useCredentials>)
renderWithClient(
<CredentialManager
@@ -298,7 +298,7 @@ describe('CredentialManager', () => {
data: undefined,
isLoading: true,
refetch: mockRefetch,
} as any)
} as unknown as ReturnType<typeof useCredentials>)
renderWithClient(
<CredentialManager
@@ -477,7 +477,7 @@ describe('CredentialManager', () => {
isError: true,
error: new Error('Failed to fetch'),
refetch: mockRefetch,
} as any)
} as unknown as ReturnType<typeof useCredentials>)
renderWithClient(
<CredentialManager
@@ -137,7 +137,7 @@ describe('DNSProviderSelector', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useDNSProviders>)
})
describe('Rendering', () => {
@@ -232,7 +232,7 @@ describe('DNSProviderSelector', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useDNSProviders>)
renderWithClient(<DNSProviderSelector value={undefined} onChange={mockOnChange} />)
@@ -254,7 +254,7 @@ describe('DNSProviderSelector', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useDNSProviders>)
renderWithClient(<DNSProviderSelector value={undefined} onChange={mockOnChange} />)
@@ -272,7 +272,7 @@ describe('DNSProviderSelector', () => {
isLoading: true,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useDNSProviders>)
renderWithClient(<DNSProviderSelector value={undefined} onChange={mockOnChange} />)
@@ -286,7 +286,7 @@ describe('DNSProviderSelector', () => {
isLoading: true,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useDNSProviders>)
renderWithClient(<DNSProviderSelector value={undefined} onChange={mockOnChange} />)
@@ -301,7 +301,7 @@ describe('DNSProviderSelector', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useDNSProviders>)
renderWithClient(<DNSProviderSelector value={undefined} onChange={mockOnChange} />)
@@ -316,7 +316,7 @@ describe('DNSProviderSelector', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useDNSProviders>)
renderWithClient(<DNSProviderSelector value={undefined} onChange={mockOnChange} />)
@@ -421,7 +421,7 @@ describe('DNSProviderSelector', () => {
isLoading: true,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useDNSProviders>)
renderWithClient(<DNSProviderSelector value={undefined} onChange={mockOnChange} />)
@@ -144,7 +144,7 @@ describe('ManualDNSChallenge', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useChallengePoll>)
vi.mocked(useManualChallengeMutations).mockReturnValue({
verifyMutation: {
@@ -159,7 +159,7 @@ describe('ManualDNSChallenge', () => {
mutateAsync: vi.fn(),
isPending: false,
},
} as any)
} as unknown as ReturnType<typeof useManualChallengeMutations>)
})
afterEach(() => {
@@ -401,7 +401,7 @@ describe('ManualDNSChallenge', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useChallengePoll>)
const verifiedChallenge: ManualChallenge = {
...mockChallenge,
@@ -424,7 +424,7 @@ describe('ManualDNSChallenge', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useChallengePoll>)
const expiredChallenge: ManualChallenge = {
...mockChallenge,
@@ -449,7 +449,7 @@ describe('ManualDNSChallenge', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useChallengePoll>)
const failedChallenge: ManualChallenge = {
...mockChallenge,
@@ -477,7 +477,7 @@ describe('ManualDNSChallenge', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useChallengePoll>)
// Re-render to trigger effect
const verifiedChallenge: ManualChallenge = {
@@ -517,7 +517,7 @@ describe('ManualDNSChallenge', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useChallengePoll>)
const expiredChallenge: ManualChallenge = {
...mockChallenge,
@@ -611,7 +611,7 @@ describe('ManualDNSChallenge', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useChallengePoll>)
const verifiedChallenge: ManualChallenge = {
...mockChallenge,
@@ -639,7 +639,7 @@ describe('ManualDNSChallenge', () => {
mutateAsync: vi.fn(),
isPending: false,
},
} as any)
} as unknown as ReturnType<typeof useManualChallengeMutations>)
renderComponent()
@@ -661,7 +661,7 @@ describe('ManualDNSChallenge', () => {
mutateAsync: vi.fn(),
isPending: false,
},
} as any)
} as unknown as ReturnType<typeof useManualChallengeMutations>)
renderComponent()
@@ -683,7 +683,7 @@ describe('ManualDNSChallenge', () => {
isLoading: false,
isError: false,
error: null,
} as any)
} as unknown as ReturnType<typeof useChallengePoll>)
const failedChallenge: ManualChallenge = {
...mockChallenge,
@@ -212,8 +212,9 @@ export default function ManualDNSChallenge({
} else if (!result.dns_found) {
toast.warning(t('dnsProvider.manual.dnsNotFound'))
}
} catch (error: any) {
toast.error(error.response?.data?.message || t('dnsProvider.manual.verifyFailed'))
} catch (error: unknown) {
const err = error as { response?: { data?: { message?: string } } }
toast.error(err.response?.data?.message || t('dnsProvider.manual.verifyFailed'))
}
}, [verifyMutation, providerId, challenge.id, t])
@@ -226,8 +227,9 @@ export default function ManualDNSChallenge({
})
toast.info(t('dnsProvider.manual.challengeCancelled'))
onCancel()
} catch (error: any) {
toast.error(error.response?.data?.message || t('dnsProvider.manual.cancelFailed'))
} catch (error: unknown) {
const err = error as { response?: { data?: { message?: string } } }
toast.error(err.response?.data?.message || t('dnsProvider.manual.cancelFailed'))
}
}, [deleteMutation, providerId, challenge.id, onCancel, t])