src/lib/return-to.test.ts
Rama main · réplica de lectura del repositorio original.
import { describe, it, expect } from "vitest";
import {
isFormPath,
labelForPath,
resolveReturnTarget,
withReturnTo,
} from "./return-to";
const FALLBACK = { href: "/dives", label: "Back to dives" };
describe("labelForPath", () => {
it("names the section's list page", () => {
expect(labelForPath("/dives")).toBe("Back to dives");
expect(labelForPath("/sites")).toBe("Back to dive sites");
expect(labelForPath("/sites/proposals")).toBe("Back to your proposals");
expect(labelForPath("/home")).toBe("Back to home");
expect(labelForPath("/courses")).toBe("Back to courses");
expect(labelForPath("/people")).toBe("Back to people");
});
it("switches to the singular for a single record", () => {
expect(labelForPath("/trips/abc")).toBe("Back to trip");
expect(labelForPath("/sites/abc")).toBe("Back to dive site");
expect(labelForPath("/dives/abc")).toBe("Back to dive");
expect(labelForPath("/courses/abc")).toBe("Back to course");
expect(labelForPath("/people/abc")).toBe("Back to person");
expect(labelForPath("/settings/account")).toBe("Back to settings");
});
it("ignores a query string or hash", () => {
expect(labelForPath("/trips?page=2")).toBe("Back to trips");
expect(labelForPath("/trips/abc#gear")).toBe("Back to trip");
});
it("falls back to a bare label for anything unrecognised", () => {
expect(labelForPath("/nowhere")).toBe("Back");
expect(labelForPath("/")).toBe("Back");
});
});
describe("resolveReturnTarget", () => {
it("prefers an explicit from over everything else", () => {
expect(
resolveReturnTarget({ from: "/trips/abc", trip_uuid: "xyz" }, FALLBACK),
).toEqual({ href: "/trips/abc", label: "Back to trip" });
});
it("derives the target from the context the form was opened with", () => {
expect(resolveReturnTarget({ trip_uuid: "abc" }, FALLBACK)).toEqual({
href: "/trips/abc",
label: "Back to trip",
});
expect(resolveReturnTarget({ dive_site_uuid: "abc" }, FALLBACK)).toEqual({
href: "/sites/abc",
label: "Back to dive site",
});
// What "Log a dive for this course" hands the form, with no `?from=` of its
// own - the same wiring the trip's own button gets for free.
expect(resolveReturnTarget({ course_uuid: "abc" }, FALLBACK)).toEqual({
href: "/courses/abc",
label: "Back to course",
});
});
it("uses the caller's fallback when the URL says nothing", () => {
expect(resolveReturnTarget({}, FALLBACK)).toEqual(FALLBACK);
});
// A `from` a visitor can hand-craft must not become an open redirect, and
// must not point back at a form.
it("rejects an off-origin from", () => {
expect(resolveReturnTarget({ from: "//evil.example" }, FALLBACK)).toEqual(
FALLBACK,
);
expect(
resolveReturnTarget({ from: "https://evil.example" }, FALLBACK),
).toEqual(FALLBACK);
expect(resolveReturnTarget({ from: "/\\evil.example" }, FALLBACK)).toEqual(
FALLBACK,
);
});
it("rejects a from that points back at a form", () => {
expect(resolveReturnTarget({ from: "/dives/new" }, FALLBACK)).toEqual(
FALLBACK,
);
expect(resolveReturnTarget({ from: "/dives/abc/edit" }, FALLBACK)).toEqual(
FALLBACK,
);
});
it("still derives from context when the from is rejected", () => {
expect(
resolveReturnTarget(
{ from: "//evil.example", trip_uuid: "abc" },
FALLBACK,
),
).toEqual({ href: "/trips/abc", label: "Back to trip" });
});
});
describe("isFormPath", () => {
it("recognises the dive form's own routes", () => {
expect(isFormPath("/dives/new")).toBe(true);
expect(isFormPath("/dives/abc/edit")).toBe(true);
expect(isFormPath("/dives/new?trip_uuid=abc")).toBe(true);
});
it("leaves ordinary pages alone", () => {
expect(isFormPath("/dives")).toBe(false);
expect(isFormPath("/dives/abc")).toBe(false);
expect(isFormPath("/trips/abc")).toBe(false);
});
});
describe("withReturnTo", () => {
// What the opened page reads back, as `useReturnTo` would.
const backFrom = (href: string) =>
resolveReturnTarget(
{ from: new URL(href, "http://localhost").searchParams.get("from") },
FALLBACK,
);
it("names the page the link is followed from", () => {
expect(withReturnTo("/trips/abc", "/home")).toBe("/trips/abc?from=%2Fhome");
expect(backFrom(withReturnTo("/dives/d", "/trips/abc"))).toEqual({
href: "/trips/abc",
label: "Back to trip",
});
});
// Home to trip to dive, and back twice.
it("keeps that page's own way back", () => {
const trip = withReturnTo("/trips/abc", "/home");
const back = backFrom(withReturnTo("/dives/d", trip));
expect(back).toEqual({ href: trip, label: "Back to trip" });
expect(backFrom(back.href)).toEqual({
href: "/home",
label: "Back to home",
});
});
it("adds nothing where the opened page's back link already goes", () => {
expect(withReturnTo("/dives/d", "/dives")).toBe("/dives/d");
expect(withReturnTo("/dives/new", "/dives")).toBe("/dives/new");
expect(withReturnTo("/dives/d/edit", "/dives/d")).toBe("/dives/d/edit");
// An edit from the list is not one from its own dive.
expect(withReturnTo("/dives/d/edit", "/dives")).toBe(
"/dives/d/edit?from=%2Fdives",
);
});
it("adds nothing from a form, or from nowhere", () => {
expect(withReturnTo("/dives/d", "/dives/new")).toBe("/dives/d");
expect(withReturnTo("/dives/d", "/dives/x/edit?from=/trips/t")).toBe(
"/dives/d",
);
expect(withReturnTo("/dives/d", null)).toBe("/dives/d");
});
it("leaves a link to the page it is on as that page stands", () => {
expect(withReturnTo("/courses/c", "/courses/c?from=/home")).toBe(
"/courses/c?from=/home",
);
expect(withReturnTo("/courses/c", "/courses/c")).toBe("/courses/c");
});
it("joins a query the link already has", () => {
expect(withReturnTo("/dives/new?trip_uuid=t", "/people/p")).toBe(
"/dives/new?trip_uuid=t&from=%2Fpeople%2Fp",
);
});
it("stops a long walk from growing the URL any further", () => {
const deep = `/sites/s?from=${"x".repeat(1000)}`;
expect(withReturnTo("/dives/d", deep)).toBe("/dives/d?from=%2Fsites%2Fs");
});
});