feat(admin): Anmeldehinweise der Willkommensmail in der Vorlage bearbeitbar
Neue Felder loginHintDirectory/loginHintLocal (Platzhalter, Pflicht, max. 1000), Migration 20260930170000 (nullable, leer = Standard aus @tessera/shared). Knopf Passwort festlegen und Gueltigkeitshinweis bleiben fest; local-no-link wird nie erzeugt und bleibt fest. Vorschau springt beim Bearbeiten auf die passende Kontoart. Lokal im Browser nachgewiesen. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,18 @@ const base: WelcomeMailInput = {
|
||||
headerImageSrc: null,
|
||||
};
|
||||
|
||||
/** Standard-Anmeldehinweise, damit Vorlagen im Test vollstaendig sind. */
|
||||
const hints = {
|
||||
loginHintDirectory: DEFAULT_WELCOME_MAIL_TEXTS.loginHintDirectory,
|
||||
loginHintLocal: DEFAULT_WELCOME_MAIL_TEXTS.loginHintLocal,
|
||||
};
|
||||
|
||||
const localAccount = {
|
||||
kind: 'local',
|
||||
setPasswordUrl: 'https://tessera.example.invalid/reset-password/abc',
|
||||
validHours: 168,
|
||||
} as const;
|
||||
|
||||
const values = {
|
||||
name: 'Max Muster',
|
||||
vorname: 'Max',
|
||||
@@ -75,6 +87,7 @@ describe('renderWelcomeMail mit Vorlage', () => {
|
||||
subject: 'Hallo\r\n{{firma}}',
|
||||
heading: '<h2>{{name}}</h2>',
|
||||
intro: '<a href="javascript:alert(1)">klick</a>',
|
||||
...hints,
|
||||
closing: '',
|
||||
},
|
||||
});
|
||||
@@ -89,7 +102,7 @@ describe('renderWelcomeMail mit Vorlage', () => {
|
||||
it('Leerzeile = neuer Absatz, einfacher Umbruch = <br>; leerer Abschluss faellt weg', () => {
|
||||
const mail = renderWelcomeMail({
|
||||
...base,
|
||||
texts: { subject: 's', heading: 'h', intro: 'A1\nA2\r\n\r\n\nB', closing: ' ' },
|
||||
texts: { subject: 's', heading: 'h', intro: 'A1\nA2\r\n\r\n\nB', ...hints, closing: ' ' },
|
||||
});
|
||||
expect(mail.html).toContain('>A1<br>A2</p>');
|
||||
expect(mail.html).toContain('>B</p>');
|
||||
@@ -105,7 +118,7 @@ describe('renderWelcomeMail mit Vorlage', () => {
|
||||
setPasswordUrl: 'https://tessera.example.invalid/reset-password/abc',
|
||||
validHours: 168,
|
||||
},
|
||||
texts: { subject: 'x', heading: 'y', intro: '', closing: '' },
|
||||
texts: { subject: 'x', heading: 'y', intro: '', ...hints, closing: '' },
|
||||
});
|
||||
expect(mail.html).toContain('https://tessera.example.invalid/reset-password/abc');
|
||||
expect(mail.html).toContain('Passwort festlegen');
|
||||
@@ -128,6 +141,67 @@ describe('renderWelcomeMail mit Vorlage', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Anmeldehinweis je Kontoart', () => {
|
||||
it('Standard: Verzeichniskonto bekommt den Windows-Hinweis, lokales Konto den Hinweis vor dem Knopf', () => {
|
||||
const dir = renderWelcomeMail(base);
|
||||
expect(dir.html).toContain('gewohnten Windows-Passwort');
|
||||
expect(dir.html).not.toContain('persönliches Passwort fest');
|
||||
const local = renderWelcomeMail({ ...base, account: localAccount });
|
||||
expect(local.html).toContain('legen Sie bitte Ihr persönliches Passwort fest');
|
||||
expect(local.html).not.toContain('Windows-Passwort');
|
||||
// Hinweis steht vor dem Knopf
|
||||
expect(local.html.indexOf('persönliches Passwort fest')).toBeLessThan(
|
||||
local.html.indexOf('Passwort festlegen</a>'),
|
||||
);
|
||||
});
|
||||
|
||||
it('eigener Text je Kontoart: Platzhalter ersetzt, escaped, Leerzeile = Absatz; Knopf und Gueltigkeit bleiben fest', () => {
|
||||
const texts = {
|
||||
...DEFAULT_WELCOME_MAIL_TEXTS,
|
||||
loginHintDirectory:
|
||||
'Anmeldung als {{benutzername}} mit <b>Firmenkennwort</b>.\n\nFragen? IT anrufen.',
|
||||
loginHintLocal: 'Hallo {{vorname}}, bitte zuerst ein Passwort setzen.',
|
||||
};
|
||||
const dir = renderWelcomeMail({ ...base, texts });
|
||||
expect(dir.html).toContain(
|
||||
'Anmeldung als max.muster mit <b>Firmenkennwort</b>.</p>',
|
||||
);
|
||||
expect(dir.html).toContain('>Fragen? IT anrufen.</p>');
|
||||
expect(dir.html).not.toContain('Windows-Passwort');
|
||||
expect(dir.html).not.toContain('bitte zuerst ein Passwort setzen');
|
||||
expect(dir.text).toContain(
|
||||
'Anmeldung als max.muster mit <b>Firmenkennwort</b>.\n\nFragen? IT anrufen.',
|
||||
);
|
||||
|
||||
const local = renderWelcomeMail({ ...base, account: localAccount, texts });
|
||||
expect(local.html).toContain('Hallo Max, bitte zuerst ein Passwort setzen.');
|
||||
expect(local.html).not.toContain('Firmenkennwort');
|
||||
expect(local.html).toContain('reset-password/abc');
|
||||
expect(local.html).toContain('7 Tage');
|
||||
expect(local.text).toContain('Hallo Max, bitte zuerst ein Passwort setzen.');
|
||||
|
||||
const example = renderWelcomeMail({ ...base, account: { kind: 'local-example' }, texts });
|
||||
expect(example.html).toContain('Hallo Max, bitte zuerst ein Passwort setzen.');
|
||||
});
|
||||
|
||||
it('leerer oder fehlender Hinweis (aeltere Aufrufer) → Standardtext', () => {
|
||||
const { loginHintDirectory: _d, loginHintLocal: _l, ...old } = DEFAULT_WELCOME_MAIL_TEXTS;
|
||||
const dir = renderWelcomeMail({ ...base, texts: old as any });
|
||||
expect(dir.html).toContain('gewohnten Windows-Passwort');
|
||||
const local = renderWelcomeMail({
|
||||
...base,
|
||||
account: localAccount,
|
||||
texts: { ...DEFAULT_WELCOME_MAIL_TEXTS, loginHintLocal: ' ' },
|
||||
});
|
||||
expect(local.html).toContain('persönliches Passwort fest');
|
||||
});
|
||||
|
||||
it('local-no-link behaelt den festen Hinweis', () => {
|
||||
const mail = renderWelcomeMail({ ...base, account: { kind: 'local-no-link' } });
|
||||
expect(mail.html).toContain('Ihr Startpasswort erhalten Sie von Ihrem Administrator.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Kopf (Outlook ohne CID-Bild)', () => {
|
||||
it('Wellenstreifen 600x40 in einer Zelle mit dunkler Kopffarbe, Inhalt beginnt mit 24px Abstand', () => {
|
||||
const mail = renderWelcomeMail({ ...base, headerImageSrc: 'cid:welcome-header@tessera' });
|
||||
|
||||
Reference in New Issue
Block a user