Files
govoplan-core/webui/tests/mail-components.test.tsx
2026-06-25 19:58:20 +02:00

199 lines
8.9 KiB
TypeScript

function assert(condition: unknown, message = "assertion failed"): void {
if (!condition) throw new Error(message);
}
function assertEqual<T>(actual: T, expected: T, message = "values should be equal"): void {
if (actual !== expected) throw new Error(`${message}: expected ${String(expected)}, got ${String(actual)}`);
}
function assertDeepEqual(actual: unknown, expected: unknown, message = "values should be deeply equal"): void {
const actualJson = JSON.stringify(actual);
const expectedJson = JSON.stringify(expected);
if (actualJson !== expectedJson) throw new Error(`${message}: expected ${expectedJson}, got ${actualJson}`);
}
import { renderToStaticMarkup } from "react-dom/server";
import PasswordField from "../src/components/PasswordField";
import MessageDisplayPanel from "../src/components/MessageDisplayPanel";
import MailServerSettingsPanel from "../src/components/mail/MailServerSettingsPanel";
function noop() {}
const savedPassword = renderToStaticMarkup(
<PasswordField value="" saved savedPlaceholder="Saved password configured" onValueChange={noop} />
);
assert(savedPassword.includes('placeholder="Saved password configured"'), "saved password placeholder is rendered");
assert(!savedPassword.includes("password-field-toggle"), "saved empty password does not show reveal button");
const typedPassword = renderToStaticMarkup(
<PasswordField value="secret" saved savedPlaceholder="Saved password configured" onValueChange={noop} />
);
assert(typedPassword.includes('aria-label="Show password"'), "typed password shows reveal button");
assert(typedPassword.includes("password-field-toggle"), "typed password gets toggle class");
const settingsPanel = renderToStaticMarkup(
<MailServerSettingsPanel
smtp={{ host: "smtp.example.org", port: 587, username: "sender", password: "", security: "starttls", timeout_seconds: 30 }}
imap={{ host: "imap.example.org", port: 993, username: "sender", password: "", security: "tls", sent_folder: "auto", timeout_seconds: 30 }}
onSmtpChange={noop}
onImapChange={noop}
smtpPasswordSaved
smtpSavedPasswordPlaceholder="Saved SMTP password"
imapPasswordSaved
imapSavedPasswordPlaceholder="Saved IMAP password"
onTestSmtp={noop}
onTestImap={noop}
onLookupFolders={noop}
folderLookupResult={{
ok: true,
protocol: "imap",
message: "Folders loaded",
detected_sent_folder: "Sent",
folders: [{ name: "INBOX", flags: [] }, { name: "Sent", flags: ["\\Sent"] }]
}}
onUseDetectedFolder={noop}
/>
);
assert(settingsPanel.includes("Test SMTP"), "SMTP test action is rendered");
assert(settingsPanel.includes("Server"), "server heading is rendered");
assert(settingsPanel.includes("Credentials"), "credentials heading is rendered");
assert(!settingsPanel.includes("Enable IMAP"), "legacy IMAP enable toggle is not rendered");
assert(settingsPanel.includes('placeholder="Saved SMTP password"'), "SMTP saved credential placeholder is rendered");
const imapSettingsPanel = renderToStaticMarkup(
<MailServerSettingsPanel
initialSection="imap"
smtp={{ host: "smtp.example.org", port: 587, username: "sender", password: "", security: "starttls", timeout_seconds: 30 }}
imap={{ host: "imap.example.org", port: 993, username: "sender", password: "", security: "tls", sent_folder: "auto", timeout_seconds: 30 }}
onSmtpChange={noop}
onImapChange={noop}
imapPasswordSaved
imapSavedPasswordPlaceholder="Saved IMAP password"
onTestImap={noop}
onLookupFolders={noop}
folderLookupResult={{
ok: true,
protocol: "imap",
message: "Folders loaded",
detected_sent_folder: "Sent",
folders: [{ name: "INBOX", flags: [] }, { name: "Sent", flags: ["\\Sent"] }]
}}
onUseDetectedFolder={noop}
/>
);
assert(imapSettingsPanel.includes("Test IMAP"), "IMAP test action is rendered");
assert(imapSettingsPanel.includes("Server"), "IMAP server heading is rendered");
assert(imapSettingsPanel.includes("Credentials"), "IMAP credentials heading is rendered");
assert(!imapSettingsPanel.includes("Enable IMAP"), "legacy IMAP enable toggle is not rendered in IMAP tab");
assert(!imapSettingsPanel.includes("Folders..."), "folder lookup action is not rendered in the IMAP tab");
assert(imapSettingsPanel.includes('placeholder="Saved IMAP password"'), "IMAP saved credential placeholder is rendered");
assert(!imapSettingsPanel.includes("Folders loaded"), "folder lookup result is not rendered in the IMAP tab");
assert(!imapSettingsPanel.includes("Default sent folder"), "default sent folder field is not rendered");
const advancedSettingsPanel = renderToStaticMarkup(
<MailServerSettingsPanel
initialSection="advanced"
smtp={{ host: "smtp.example.org", security: "starttls" }}
imap={{ host: "imap.example.org", security: "tls", sent_folder: "Sent" }}
onSmtpChange={noop}
onImapChange={noop}
onLookupFolders={noop}
folderLookupResult={{
ok: true,
protocol: "imap",
message: "Folders loaded",
detected_sent_folder: "Sent",
folders: [{ name: "INBOX", flags: [] }, { name: "Sent", flags: ["\\Sent"] }]
}}
onUseDetectedFolder={noop}
/>
);
assert(advancedSettingsPanel.includes("Append target folder"), "append target folder is the advanced IMAP folder field");
assert(advancedSettingsPanel.includes("Folders..."), "folder lookup action is rendered near append target folder");
assert(advancedSettingsPanel.includes("Folders loaded"), "folder lookup result is rendered in Advanced");
assert(advancedSettingsPanel.includes("Use detected folder"), "detected folder action is rendered near append target folder");
assert(advancedSettingsPanel.includes('value="Sent"'), "append target folder uses IMAP sent folder value without append override");
const disabledAppendFolderPanel = renderToStaticMarkup(
<MailServerSettingsPanel
initialSection="advanced"
smtp={{ host: "smtp.example.org", security: "starttls" }}
imap={{ host: "imap.example.org", security: "tls", sent_folder: "Sent" }}
onSmtpChange={noop}
onImapChange={noop}
onLookupFolders={noop}
folderLookupResult={{
ok: true,
protocol: "imap",
message: "Folders loaded",
detected_sent_folder: "Sent",
folders: [{ name: "Sent", flags: ["\\Sent"] }]
}}
onUseDetectedFolder={noop}
append={{
enabled: true,
folder: "Sent",
folderDisabled: true,
onEnabledChange: noop,
onFolderChange: noop
}}
/>
);
assert(!disabledAppendFolderPanel.includes("Folders..."), "folder lookup action is hidden when append target is disabled");
assert(!disabledAppendFolderPanel.includes("Use detected folder"), "detected folder action is hidden when append target is disabled");
const defaultPortSettingsPanel = renderToStaticMarkup(
<MailServerSettingsPanel
smtp={{ host: "smtp.example.org", security: "starttls" }}
imap={{ host: "imap.example.org", security: "tls" }}
onSmtpChange={noop}
onImapChange={noop}
/>
);
const defaultImapPortSettingsPanel = renderToStaticMarkup(
<MailServerSettingsPanel
initialSection="imap"
smtp={{ host: "smtp.example.org", security: "starttls" }}
imap={{ host: "imap.example.org", security: "tls" }}
onSmtpChange={noop}
onImapChange={noop}
/>
);
assert(defaultPortSettingsPanel.includes('value="587"'), "SMTP starttls default port is displayed");
assert(defaultImapPortSettingsPanel.includes('value="993"'), "IMAP TLS default port is displayed");
const messageDisplay = renderToStaticMarkup(
<MessageDisplayPanel
title="Quarterly update"
fields={[
{ label: "From", value: "Sender <sender@example.org>" },
{ label: "Cc", value: null },
{ label: "Bcc", value: "Audit <audit@example.org>" }
]}
bodyText="Plain body"
bodyHtml="<p><strong>HTML body</strong></p>"
preferredBodyMode="html"
attachments={[
{ filename: "agenda.pdf", contentType: "application/pdf", sizeBytes: 2048 },
{
filename: "secret.pdf",
contentType: "application/pdf",
archiveGroup: "archive-1",
archiveLabel: "recipient-files.zip",
protected: true,
protectionNote: 'Password-protected ZIP using local field "zip_password". Encryption: AES.'
}
]}
/>
);
assert(messageDisplay.includes("Quarterly update"), "message subject is rendered");
assert(messageDisplay.includes("Sender &lt;sender@example.org&gt;"), "sender field is rendered");
assert(!messageDisplay.includes("<dt>Cc</dt>"), "empty optional CC field is hidden");
assert(messageDisplay.includes("<dt>Bcc</dt>"), "present BCC field is rendered");
assert(messageDisplay.includes("HTML"), "HTML body switch is rendered");
assert(messageDisplay.includes("Text"), "text body switch is rendered");
assert(messageDisplay.includes("agenda.pdf"), "direct attachment is rendered");
assert(messageDisplay.includes("recipient-files.zip"), "ZIP archive attachment group is rendered");
assert(messageDisplay.includes("Password protected"), "ZIP protection badge is rendered");
assert(messageDisplay.includes("zip_password"), "ZIP protection note is rendered");