test(07-06): add failing SMTP settings form tests (RED — DKV-05)
- 5 Vitest tests for SmtpSettingsForm: load config, save, test success/failure, password toggle - Mocks @/lib/settings-api (fetchSmtp/saveSmtp/testSmtp) and next-intl - Mirrors calendar-settings.test.tsx mocking pattern - RED: SmtpSettingsForm does not yet exist
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
import { cleanup, render, screen, waitFor, fireEvent } from '@testing-library/react';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
// Mock next-intl — returns a short readable string for each key
|
||||
vi.mock('next-intl', () => ({
|
||||
useTranslations: (ns: string) => (key: string) => {
|
||||
const map: Record<string, Record<string, string>> = {
|
||||
settings: {
|
||||
'smtp.title': 'SMTP-Konfiguration',
|
||||
'smtp.host': 'Host',
|
||||
'smtp.port': 'Port',
|
||||
'smtp.encryption': 'Verschluesselung',
|
||||
'smtp.username': 'Benutzername',
|
||||
'smtp.password': 'Passwort',
|
||||
'smtp.fromAddress': 'Absenderadresse (Von)',
|
||||
'smtp.fromAddressHelp': 'Die E-Mail-Adresse, die als Absender angezeigt wird.',
|
||||
'smtp.save': 'Einstellungen speichern',
|
||||
'smtp.test': 'Verbindung testen',
|
||||
'smtp.showPassword': 'Passwort anzeigen',
|
||||
'smtp.hidePassword': 'Passwort verbergen',
|
||||
'smtp.testTesting': 'Verbindung wird getestet...',
|
||||
'smtp.testSuccess': 'Verbindung erfolgreich',
|
||||
'smtp.testFailed': 'Verbindung fehlgeschlagen',
|
||||
},
|
||||
};
|
||||
return map[ns]?.[key] ?? key;
|
||||
},
|
||||
}));
|
||||
|
||||
// Mock @/lib/settings-api
|
||||
const mockFetchSmtp = vi.fn();
|
||||
const mockSaveSmtp = vi.fn();
|
||||
const mockTestSmtp = vi.fn();
|
||||
|
||||
vi.mock('@/lib/settings-api', () => ({
|
||||
fetchSmtp: (...args: unknown[]) => mockFetchSmtp(...args),
|
||||
saveSmtp: (...args: unknown[]) => mockSaveSmtp(...args),
|
||||
testSmtp: (...args: unknown[]) => mockTestSmtp(...args),
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('SmtpSettingsForm', () => {
|
||||
it('loads existing config and populates fields (password stays blank)', async () => {
|
||||
mockFetchSmtp.mockResolvedValue({
|
||||
host: 'smtp.example.com',
|
||||
port: 587,
|
||||
encryption: 'starttls',
|
||||
username: 'user@example.com',
|
||||
fromAddress: 'tessera@example.com',
|
||||
hasPassword: true,
|
||||
});
|
||||
|
||||
const { SmtpSettingsForm } = await import(
|
||||
'@/components/settings/smtp-settings-form'
|
||||
);
|
||||
render(<SmtpSettingsForm />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
(screen.getByLabelText('Host') as HTMLInputElement).value,
|
||||
).toBe('smtp.example.com');
|
||||
});
|
||||
|
||||
expect((screen.getByLabelText('Port') as HTMLInputElement).value).toBe(
|
||||
'587',
|
||||
);
|
||||
expect(
|
||||
(screen.getByLabelText('Benutzername') as HTMLInputElement).value,
|
||||
).toBe('user@example.com');
|
||||
expect(
|
||||
(screen.getByLabelText('Absenderadresse (Von)') as HTMLInputElement)
|
||||
.value,
|
||||
).toBe('tessera@example.com');
|
||||
// T-07-17: password must never be pre-filled from server data
|
||||
expect(
|
||||
(screen.getByLabelText('Passwort') as HTMLInputElement).value,
|
||||
).toBe('');
|
||||
});
|
||||
|
||||
it('calls saveSmtp with form values on submit', async () => {
|
||||
mockFetchSmtp.mockResolvedValue({
|
||||
host: 'smtp.example.com',
|
||||
port: 587,
|
||||
encryption: 'starttls',
|
||||
username: 'user@example.com',
|
||||
fromAddress: 'tessera@example.com',
|
||||
hasPassword: false,
|
||||
});
|
||||
mockSaveSmtp.mockResolvedValue({
|
||||
host: 'smtp.example.com',
|
||||
port: 587,
|
||||
encryption: 'starttls',
|
||||
username: 'user@example.com',
|
||||
fromAddress: 'tessera@example.com',
|
||||
hasPassword: false,
|
||||
});
|
||||
|
||||
const { SmtpSettingsForm } = await import(
|
||||
'@/components/settings/smtp-settings-form'
|
||||
);
|
||||
render(<SmtpSettingsForm />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
(screen.getByLabelText('Host') as HTMLInputElement).value,
|
||||
).toBe('smtp.example.com');
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByText('Einstellungen speichern'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockSaveSmtp).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
host: 'smtp.example.com',
|
||||
port: 587,
|
||||
encryption: 'starttls',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('shows success message when testSmtp resolves { success: true }', async () => {
|
||||
mockFetchSmtp.mockResolvedValue(null);
|
||||
mockTestSmtp.mockResolvedValue({ success: true });
|
||||
|
||||
const { SmtpSettingsForm } = await import(
|
||||
'@/components/settings/smtp-settings-form'
|
||||
);
|
||||
render(<SmtpSettingsForm />);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.getByText('Verbindung testen')).toBeInTheDocument(),
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByText('Verbindung testen'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText('Verbindung erfolgreich'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows error message when testSmtp resolves { success: false }', async () => {
|
||||
mockFetchSmtp.mockResolvedValue(null);
|
||||
mockTestSmtp.mockResolvedValue({ success: false });
|
||||
|
||||
const { SmtpSettingsForm } = await import(
|
||||
'@/components/settings/smtp-settings-form'
|
||||
);
|
||||
render(<SmtpSettingsForm />);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.getByText('Verbindung testen')).toBeInTheDocument(),
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByText('Verbindung testen'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText('Verbindung fehlgeschlagen'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('toggles password input type between password and text', async () => {
|
||||
mockFetchSmtp.mockResolvedValue(null);
|
||||
|
||||
const { SmtpSettingsForm } = await import(
|
||||
'@/components/settings/smtp-settings-form'
|
||||
);
|
||||
render(<SmtpSettingsForm />);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.getByLabelText('Passwort')).toBeInTheDocument(),
|
||||
);
|
||||
|
||||
const passwordInput = screen.getByLabelText('Passwort') as HTMLInputElement;
|
||||
expect(passwordInput.type).toBe('password');
|
||||
|
||||
const toggleButton = screen.getByRole('button', {
|
||||
name: 'Passwort anzeigen',
|
||||
});
|
||||
fireEvent.click(toggleButton);
|
||||
|
||||
expect(passwordInput.type).toBe('text');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user