import { describe, expect, it } from "vitest"; import { languageAlternates, localeOfPath, pathFor, routeRequest, sitemapEntries, switchPath, } from "./routes"; describe("pathFor", () => { it("serves German at the root, with German names for the legal pages", () => { expect(pathFor("home", "de")).toBe("/"); expect(pathFor("imprint", "de")).toBe("/impressum"); expect(pathFor("privacy", "de")).toBe("/datenschutz"); }); it("serves English under /en", () => { expect(pathFor("home", "en")).toBe("/en"); expect(pathFor("imprint", "en")).toBe("/en/imprint"); expect(pathFor("privacy", "en")).toBe("/en/privacy"); }); }); describe("languageAlternates", () => { it("names both languages of a page and German as the fallback", () => { expect(languageAlternates("home")).toEqual({ de: "/", en: "/en", "x-default": "/", }); expect(languageAlternates("privacy")).toEqual({ de: "/datenschutz", en: "/en/privacy", "x-default": "/datenschutz", }); }); }); describe("localeOfPath", () => { it.each([ ["/", "de"], ["/impressum", "de"], ["/en", "en"], ["/en/", "en"], ["/en/imprint", "en"], ["/en/anything/else", "en"], // Only a whole first segment counts. ["/energy", "de"], ["/dev/en", "de"], ["", "de"], ] as const)("%s is %s", (pathname, locale) => { expect(localeOfPath(pathname)).toBe(locale); }); }); describe("switchPath", () => { it("leads to the same page in the other language", () => { expect(switchPath("/", "en")).toBe("/en"); expect(switchPath("/en", "de")).toBe("/"); expect(switchPath("/impressum", "en")).toBe("/en/imprint"); expect(switchPath("/en/imprint", "de")).toBe("/impressum"); expect(switchPath("/datenschutz", "en")).toBe("/en/privacy"); expect(switchPath("/en/privacy", "de")).toBe("/datenschutz"); }); it("stays on the page when the language is already the requested one", () => { expect(switchPath("/en/imprint", "en")).toBe("/en/imprint"); expect(switchPath("/datenschutz", "de")).toBe("/datenschutz"); }); it("ignores a trailing slash", () => { expect(switchPath("/en/", "de")).toBe("/"); expect(switchPath("/impressum/", "en")).toBe("/en/imprint"); }); it("leads to the homepage from an address that is not a page", () => { expect(switchPath("/nothing-here", "en")).toBe("/en"); expect(switchPath("/en/nothing-here", "de")).toBe("/"); // A German page name under /en is not an English page. expect(switchPath("/en/impressum", "de")).toBe("/"); }); }); const german = { cookie: undefined, acceptLanguage: "de-DE,de;q=0.9,en;q=0.8" }; const english = { cookie: undefined, acceptLanguage: "en-US,en;q=0.9" }; const unknown = { cookie: undefined, acceptLanguage: undefined }; describe("routeRequest", () => { describe("addresses without a language", () => { it.each([ ["/", "/de"], ["/impressum", "/de/imprint"], ["/datenschutz", "/de/privacy"], ])("shows %s in German to a German browser", (pathname, to) => { expect(routeRequest({ pathname, ...german })).toEqual({ kind: "rewrite", to, negotiated: true, }); }); it("shows German when nothing is known about the visitor, as for a search engine", () => { expect(routeRequest({ pathname: "/", ...unknown })).toEqual({ kind: "rewrite", to: "/de", negotiated: true, }); }); it.each([ ["/", "/en"], ["/impressum", "/en/imprint"], ["/datenschutz", "/en/privacy"], ])( "sends an English browser from %s to %s, not permanently", (pathname, to) => { expect(routeRequest({ pathname, ...english })).toEqual({ kind: "redirect", to, permanent: false, negotiated: true, }); }, ); it("leaves an English browser on German once German was chosen", () => { expect(routeRequest({ pathname: "/", ...english, cookie: "de" })).toEqual( { kind: "rewrite", to: "/de", negotiated: true }, ); }); it("sends a German browser to English once English was chosen", () => { expect(routeRequest({ pathname: "/", ...german, cookie: "en" })).toEqual({ kind: "redirect", to: "/en", permanent: false, negotiated: true, }); }); it("treats a trailing slash like the page itself", () => { expect(routeRequest({ pathname: "/impressum/", ...english })).toEqual({ kind: "redirect", to: "/en/imprint", permanent: false, negotiated: true, }); expect(routeRequest({ pathname: "/impressum/", ...german })).toEqual({ kind: "rewrite", to: "/de/imprint", negotiated: true, }); expect(routeRequest({ pathname: "/impressum//", ...german })).toEqual({ kind: "rewrite", to: "/de/imprint", negotiated: true, }); }); // The legal pages used to live here in English; search engines know those addresses. it.each([ ["/imprint", "/en/imprint"], ["/privacy", "/en/privacy"], ["/privacy/", "/en/privacy"], ])( "moves the English page name %s to %s for good, whatever the browser says", (pathname, to) => { for (const visitor of [german, english, unknown]) { expect(routeRequest({ pathname, ...visitor })).toEqual({ kind: "redirect", to, permanent: true, negotiated: false, }); } }, ); it("shows the German error page for an unknown address, whatever the browser says", () => { expect(routeRequest({ pathname: "/nothing-here", ...english })).toEqual({ kind: "rewrite", to: "/de/nothing-here", negotiated: false, }); expect(routeRequest({ pathname: "/a/b", ...german })).toEqual({ kind: "rewrite", to: "/de/a/b", negotiated: false, }); }); }); describe("English addresses", () => { it.each([ ["/en", "/en"], ["/en/", "/en"], ["/en/imprint", "/en/imprint"], ["/en/privacy", "/en/privacy"], ])("shows %s in English to everyone", (pathname, to) => { for (const visitor of [german, english, { ...english, cookie: "de" }]) { expect(routeRequest({ pathname, ...visitor })).toEqual({ kind: "rewrite", to, negotiated: false, }); } }); it.each([ ["/en/impressum", "/en/imprint"], ["/en/datenschutz", "/en/privacy"], ["/en/datenschutz/", "/en/privacy"], ])( "moves the German page name %s to the English one for good", (pathname, to) => { expect(routeRequest({ pathname, ...german })).toEqual({ kind: "redirect", to, permanent: true, negotiated: false, }); }, ); it("shows the English error page for an unknown English address", () => { expect(routeRequest({ pathname: "/en/nothing-here", ...german })).toEqual( { kind: "rewrite", to: "/en/nothing-here", negotiated: false }, ); }); }); describe("addresses with the internal German prefix", () => { it.each([ ["/de", "/"], ["/de/", "/"], ["/de/impressum", "/impressum"], ["/de/datenschutz", "/datenschutz"], ["/de/imprint", "/impressum"], ["/de/privacy", "/datenschutz"], ["/de/nothing-here", "/nothing-here"], ])( "moves %s to %s for good, so that each page has one address", (pathname, to) => { expect(routeRequest({ pathname, ...english })).toEqual({ kind: "redirect", to, permanent: true, negotiated: false, }); }, ); it("only treats a whole segment as a prefix", () => { expect(routeRequest({ pathname: "/design", ...german })).toEqual({ kind: "rewrite", to: "/de/design", negotiated: false, }); expect(routeRequest({ pathname: "/energy", ...german })).toEqual({ kind: "rewrite", to: "/de/energy", negotiated: false, }); }); }); }); describe("sitemapEntries", () => { it("lists every language of the given pages, each with all its alternates", () => { const languages = { de: "https://example.com/", en: "https://example.com/en", "x-default": "https://example.com/", }; expect(sitemapEntries("https://example.com", ["home"])).toEqual([ { url: "https://example.com/", alternates: { languages } }, { url: "https://example.com/en", alternates: { languages } }, ]); }); it("keeps the order of the pages", () => { expect( sitemapEntries("https://example.com", ["privacy", "home"]).map( (entry) => entry.url, ), ).toEqual([ "https://example.com/datenschutz", "https://example.com/en/privacy", "https://example.com/", "https://example.com/en", ]); }); it("is empty without pages", () => { expect(sitemapEntries("https://example.com", [])).toEqual([]); }); });