Files
scan-receipts/tests/e2e/seo_slugs.test.ts
Timo 84b9987c49 Add full application: receipt scanning, auth, billing, and account deletion
Brings the working codebase (Next.js app, auth system, Stripe billing,
Docker/deploy config, tests, docs) into version control on top of the
placeholder initial commit, and adds account self-deletion (Danger Zone
in Settings, password + typed-email confirmation, cascading DB cleanup,
Stripe cancellation) per GDPR right-to-erasure.

Excludes local build caches, node_modules, and internal agent scratch
files; .gitignore hardened to keep those out going forward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 20:59:04 +02:00

90 lines
3.2 KiB
TypeScript

/**
* Locale-specific SEO slugs — public German keyword URLs rewrite onto the
* shared App Router folders; English slugs under /de/ 301 to the DE slug.
*/
import { describe, test, expect } from "./runner";
import {
decideSeoLocalePath,
localizePathname,
publicPath,
} from "../../src/lib/seo/slugs";
describe("SEO slugs — public paths", () => {
test("German blog slugs use keyword URLs", () => {
expect(publicPath("de", "blog/simple-expense-tracking")).toBe(
"/de/blog/einfache-ausgabenverfolgung",
);
expect(publicPath("en", "blog/simple-expense-tracking")).toBe(
"/en/blog/simple-expense-tracking",
);
});
test("German keyword pages use German slugs", () => {
expect(publicPath("de", "ocr-receipt-scanner")).toBe("/de/beleg-ocr");
expect(publicPath("de", "expense-tracker-freelancers")).toBe(
"/de/ausgaben-tracker-freelancer",
);
expect(publicPath("de", "expensify-alternative")).toBe("/de/alternative-zu-expensify");
expect(publicPath("de", "lexoffice-alternative")).toBe("/de/alternative-zu-lexoffice");
});
});
describe("SEO slugs — middleware decisions", () => {
test("DE public slug rewrites onto the internal folder", () => {
expect(decideSeoLocalePath("/de/blog/einfache-ausgabenverfolgung")).toEqual({
kind: "rewrite",
pathname: "/de/blog/simple-expense-tracking",
});
expect(decideSeoLocalePath("/de/beleg-ocr")).toEqual({
kind: "rewrite",
pathname: "/de/ocr-receipt-scanner",
});
});
test("English slug under /de/ redirects to the German keyword URL", () => {
expect(decideSeoLocalePath("/de/blog/simple-expense-tracking")).toEqual({
kind: "redirect",
pathname: "/de/blog/einfache-ausgabenverfolgung",
});
expect(decideSeoLocalePath("/de/ocr-receipt-scanner")).toEqual({
kind: "redirect",
pathname: "/de/beleg-ocr",
});
});
test("German slug under /en/ redirects to the English URL", () => {
expect(decideSeoLocalePath("/en/blog/einfache-ausgabenverfolgung")).toEqual({
kind: "redirect",
pathname: "/en/blog/simple-expense-tracking",
});
});
test("correct English public slugs pass through", () => {
expect(decideSeoLocalePath("/en/blog/simple-expense-tracking")).toEqual({
kind: "none",
});
expect(decideSeoLocalePath("/en/ocr-receipt-scanner")).toEqual({ kind: "none" });
});
test("homepage and blog index are untouched", () => {
expect(decideSeoLocalePath("/de")).toEqual({ kind: "none" });
expect(decideSeoLocalePath("/en")).toEqual({ kind: "none" });
expect(decideSeoLocalePath("/de/blog")).toEqual({ kind: "none" });
expect(decideSeoLocalePath("/en/blog")).toEqual({ kind: "none" });
});
});
describe("SEO slugs — language switch", () => {
test("maps the sibling locale slug instead of only swapping /en and /de", () => {
expect(localizePathname("/en/blog/simple-expense-tracking", "de")).toBe(
"/de/blog/einfache-ausgabenverfolgung",
);
expect(localizePathname("/de/blog/einfache-ausgabenverfolgung", "en")).toBe(
"/en/blog/simple-expense-tracking",
);
expect(localizePathname("/de", "en")).toBe("/en");
expect(localizePathname("/en/blog", "de")).toBe("/de/blog");
});
});