Эх сурвалжийг харах

RHL-009 feat(password-policy): add password policy UI and corresponding tests in German

Code_Uwe 5 өдөр өмнө
parent
commit
0aeed05255

+ 70 - 0
lib/frontend/profile/passwordPolicyUi.js

@@ -0,0 +1,70 @@
+import {
+	PASSWORD_POLICY,
+	PASSWORD_POLICY_REASON,
+} from "@/lib/auth/passwordPolicy";
+
+const ORDERED_REASONS = [
+	PASSWORD_POLICY_REASON.MIN_LENGTH,
+	PASSWORD_POLICY_REASON.MISSING_LETTER,
+	PASSWORD_POLICY_REASON.MISSING_NUMBER,
+	PASSWORD_POLICY_REASON.SAME_AS_CURRENT,
+];
+
+function uniqueStrings(arr) {
+	const list = Array.isArray(arr) ? arr.map(String) : [];
+	return Array.from(new Set(list));
+}
+
+function labelForReasonDe(reason, { minLength } = {}) {
+	const min =
+		Number.isInteger(minLength) && minLength > 0
+			? minLength
+			: PASSWORD_POLICY.minLength;
+
+	if (reason === PASSWORD_POLICY_REASON.MIN_LENGTH) {
+		return `Mindestens ${min} Zeichen`;
+	}
+	if (reason === PASSWORD_POLICY_REASON.MISSING_LETTER) {
+		return "Mindestens 1 Buchstabe (A–Z)";
+	}
+	if (reason === PASSWORD_POLICY_REASON.MISSING_NUMBER) {
+		return "Mindestens 1 Zahl (0–9)";
+	}
+	if (reason === PASSWORD_POLICY_REASON.SAME_AS_CURRENT) {
+		return "Neues Passwort darf nicht identisch sein";
+	}
+	return null;
+}
+
+export function getPasswordPolicyHintLinesDe(policy = PASSWORD_POLICY) {
+	const min =
+		Number.isInteger(policy?.minLength) && policy.minLength > 0
+			? policy.minLength
+			: PASSWORD_POLICY.minLength;
+
+	const lines = [`Mindestens ${min} Zeichen`];
+
+	if (policy?.requireLetter) lines.push("Mindestens 1 Buchstabe (A–Z)");
+	if (policy?.requireNumber) lines.push("Mindestens 1 Zahl (0–9)");
+	if (policy?.disallowSameAsCurrent)
+		lines.push("Darf nicht identisch zum aktuellen Passwort sein");
+
+	return lines;
+}
+
+export function reasonsToHintLinesDe({ reasons, minLength } = {}) {
+	const set = new Set(uniqueStrings(reasons));
+	const ordered = ORDERED_REASONS.filter((r) => set.has(r));
+
+	const lines = ordered
+		.map((r) => labelForReasonDe(r, { minLength }))
+		.filter(Boolean);
+
+	return lines;
+}
+
+export function buildWeakPasswordMessageDe({ reasons, minLength } = {}) {
+	const lines = reasonsToHintLinesDe({ reasons, minLength });
+	if (lines.length === 0) return "Bitte wählen Sie ein stärkeres Passwort.";
+	return lines.join(" • ");
+}

+ 38 - 0
lib/frontend/profile/passwordPolicyUi.test.js

@@ -0,0 +1,38 @@
+/* @vitest-environment node */
+
+import { describe, it, expect } from "vitest";
+import {
+	getPasswordPolicyHintLinesDe,
+	reasonsToHintLinesDe,
+	buildWeakPasswordMessageDe,
+} from "./passwordPolicyUi.js";
+
+describe("lib/frontend/profile/passwordPolicyUi", () => {
+	it("returns stable policy hint lines (German)", () => {
+		const lines = getPasswordPolicyHintLinesDe();
+		expect(lines.length).toBeGreaterThanOrEqual(3);
+		expect(lines[0]).toMatch(/Mindestens/i);
+	});
+
+	it("maps ordered reasons to German hint lines", () => {
+		const lines = reasonsToHintLinesDe({
+			reasons: ["MISSING_NUMBER", "MIN_LENGTH"],
+			minLength: 8,
+		});
+
+		expect(lines).toEqual(["Mindestens 8 Zeichen", "Mindestens 1 Zahl (0–9)"]);
+	});
+
+	it("buildWeakPasswordMessageDe joins hint lines with separators", () => {
+		const msg = buildWeakPasswordMessageDe({
+			reasons: ["MIN_LENGTH", "MISSING_LETTER"],
+			minLength: 8,
+		});
+
+		expect(msg).toBe("Mindestens 8 Zeichen • Mindestens 1 Buchstabe (A–Z)");
+	});
+
+	it("returns a generic message when reasons are missing", () => {
+		expect(buildWeakPasswordMessageDe({ reasons: null })).toMatch(/stärkeres/i);
+	});
+});