Datenschutz-Weiterleitung nimmt den Anker mit
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
09e1832041
commit
3df23fabaf
3 files changed
+49
-6
No files matched your search
@@ -0,0 +1,6 @@
|
||||
// Die Datenschutzerklärung liegt zentral im Kundenportal. Ein Anker aus der Adresse
|
||||
// (zum Beispiel #interessenten aus der Kaltmail) wird nur übernommen, wenn er
|
||||
// ausschließlich aus Buchstaben, Ziffern, Unterstrich und Bindestrich besteht.
|
||||
const BASIS = "https://project.webklar.com/datenschutz.html";
|
||||
|
||||
export const weiterleitungsZiel = (hash: string): string => (/^#[A-Za-z0-9_-]{1,64}$/.test(hash) ? BASIS + hash : BASIS);
|
||||
@@ -1,17 +1,17 @@
|
||||
import { useEffect } from "react";
|
||||
import { weiterleitungsZiel } from "@/lib/datenschutzZiel";
|
||||
|
||||
// Die Datenschutzerklärung gilt für webklar.com und das Kundenportal gemeinsam
|
||||
// und liegt zentral im Kundenportal.
|
||||
const URL = "https://project.webklar.com/datenschutz.html";
|
||||
|
||||
// und liegt zentral im Kundenportal. Ein Anker (#interessenten) geht dorthin mit.
|
||||
const Datenschutz = () => {
|
||||
const ziel = weiterleitungsZiel(window.location.hash);
|
||||
useEffect(() => {
|
||||
window.location.replace(URL);
|
||||
}, []);
|
||||
window.location.replace(ziel);
|
||||
}, [ziel]);
|
||||
return (
|
||||
<main className="min-h-screen flex items-center justify-center p-6 text-center">
|
||||
<p>
|
||||
Weiter zur <a href={URL} className="underline">Datenschutzerklärung</a> …
|
||||
Weiter zur <a href={ziel} className="underline">Datenschutzerklärung</a> …
|
||||
</p>
|
||||
</main>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { afterEach, describe, it, expect, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import Datenschutz from "@/pages/Datenschutz";
|
||||
import { weiterleitungsZiel } from "@/lib/datenschutzZiel";
|
||||
|
||||
const BASIS = "https://project.webklar.com/datenschutz.html";
|
||||
|
||||
describe("Weiterleitung /datenschutz", () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllGlobals();
|
||||
window.history.pushState({}, "", "/");
|
||||
});
|
||||
|
||||
it("nimmt einen gültigen Anker mit", () => {
|
||||
expect(weiterleitungsZiel("#interessenten")).toBe(`${BASIS}#interessenten`);
|
||||
expect(weiterleitungsZiel("#chat-anhaenge")).toBe(`${BASIS}#chat-anhaenge`);
|
||||
});
|
||||
it("ohne Anker oder mit ungültigem Anker bleibt es bei der Seite", () => {
|
||||
for (const hash of ["", "#", "#javascript:alert(1)", '#a"b', "#a b", `#${"a".repeat(65)}`]) {
|
||||
expect(weiterleitungsZiel(hash)).toBe(BASIS);
|
||||
}
|
||||
});
|
||||
it("der Link im Text trägt denselben Anker", () => {
|
||||
vi.spyOn(console, "error").mockImplementation(() => {}); // jsdom meldet die nicht umgesetzte Navigation
|
||||
window.history.pushState({}, "", "/datenschutz#interessenten");
|
||||
render(<Datenschutz />);
|
||||
expect(screen.getByRole("link", { name: "Datenschutzerklärung" })).toHaveAttribute("href", `${BASIS}#interessenten`);
|
||||
});
|
||||
it("leitet mit dem Anker auf die Datenschutzerklärung im Portal weiter", () => {
|
||||
window.history.pushState({}, "", "/datenschutz#interessenten");
|
||||
const replace = vi.fn();
|
||||
vi.stubGlobal("location", { hash: window.location.hash, replace });
|
||||
render(<Datenschutz />);
|
||||
expect(replace).toHaveBeenCalledExactlyOnceWith(`${BASIS}#interessenten`);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user