brackt/app/routes/__tests__/settings.test.ts
chrisp 3273cf1bcb
All checks were successful
🚀 Deploy / ʦ🔍 Typecheck & Lint (push) Successful in 1m17s
🚀 Deploy / 🐳 Build (push) Successful in 1m9s
🚀 Deploy / 🧪 Test (push) Successful in 3m17s
🚀 Deploy / 🚀 Deploy (push) Successful in 14s
claude/settings-menu-urls-kbp6x8 (#116)
Co-authored-by: Claude <noreply@anthropic.com>
Reviewed-on: #116
2026-06-30 16:01:36 +00:00

102 lines
3.3 KiB
TypeScript

import { describe, it, expect, vi } from "vitest";
vi.mock("~/lib/auth.server", () => ({
auth: { api: { getSession: vi.fn() } },
}));
vi.mock("~/lib/cloudinary.server", () => ({ deleteCloudinaryImageByUrl: vi.fn() }));
vi.mock("~/lib/email.server", () => ({
sendEmail: vi.fn(),
wrapInEmailTemplate: vi.fn(),
emailParagraph: vi.fn(),
escapeHtml: vi.fn(),
}));
vi.mock("~/models/user", () => ({
findUserById: vi.fn(),
findUserByUsername: vi.fn(),
isUserInActiveDraft: vi.fn(),
updateUser: vi.fn(),
anonymizeUserAccount: vi.fn(),
USERNAME_RE: /^[a-zA-Z0-9_-]{3,30}$/,
}));
vi.mock("~/models/account", () => ({ findLinkedAccountsByUserId: vi.fn() }));
vi.mock("~/models/team", () => ({ findTeamsByOwnerId: vi.fn(), removeTeamOwner: vi.fn() }));
vi.mock("~/models/commissioner", () => ({ removeAllCommissionersByUserId: vi.fn() }));
import { loader, shouldRevalidate } from "../settings";
import { auth } from "~/lib/auth.server";
type RevalidateArgs = Parameters<typeof shouldRevalidate>[0];
function revalidateArgs(overrides: Partial<RevalidateArgs>): RevalidateArgs {
return {
currentParams: {},
nextParams: {},
formMethod: undefined,
defaultShouldRevalidate: true,
...overrides,
} as unknown as RevalidateArgs;
}
type LoaderArgs = Parameters<typeof loader>[0];
function loaderArgs(section?: string): LoaderArgs {
const path = section ? `/settings/${section}` : "/settings";
return {
params: { section },
request: new Request(`http://localhost${path}`),
context: {},
} as unknown as LoaderArgs;
}
describe("/settings loader section handling", () => {
it("redirects an unknown section back to /settings", async () => {
const result = (await loader(loaderArgs("bogus"))) as Response;
expect(result).toBeInstanceOf(Response);
expect(result.status).toBe(302);
expect(result.headers.get("Location")).toBe("/settings");
// The bad section short-circuits before we ever touch the session.
expect(auth.api.getSession).not.toHaveBeenCalled();
});
it("does not redirect a valid section before auth runs", async () => {
vi.mocked(auth.api.getSession).mockResolvedValue(null as never);
const result = (await loader(loaderArgs("account"))) as Response;
// Falls through to the auth check, which redirects to login (not /settings).
expect(result.headers.get("Location")).toBe("/login?redirectTo=/settings");
expect(auth.api.getSession).toHaveBeenCalled();
});
});
describe("/settings shouldRevalidate", () => {
it("skips revalidation when only the section param changes", () => {
expect(
shouldRevalidate(
revalidateArgs({ currentParams: { section: "profile" }, nextParams: { section: "account" } })
)
).toBe(false);
});
it("revalidates after a mutation regardless of section", () => {
expect(
shouldRevalidate(
revalidateArgs({
currentParams: { section: "profile" },
nextParams: { section: "account" },
formMethod: "POST",
})
)
).toBe(true);
});
it("defers to the default when the section is unchanged", () => {
expect(
shouldRevalidate(
revalidateArgs({
currentParams: { section: "account" },
nextParams: { section: "account" },
defaultShouldRevalidate: true,
})
)
).toBe(true);
});
});