* fix: rename getTemporaryOrgRedirect to handleOrgRedirect and prevent duplicate orgRedirection query parameter * refactor: improve handleOrgRedirect test robustness with scenario-based mocking - Replace brittle mockResolvedValue with mockImplementation that derives behavior from input - Create createRedirectScenario function that sets up mocks based on actual query parameters - Add expectRedirectUsesData helper to verify redirects use the correct data - Add comprehensive mock verification tests to ensure different inputs return different outputs - Ensure tests verify the actual usage of Prisma results, not just that Prisma was called This prevents false positives where tests pass even if the code doesn't use the database results correctly. * Fix bug with Private links redirecting an exposing users booking page URL * Narrow the type to what is being used --------- Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
705 lines
21 KiB
TypeScript
705 lines
21 KiB
TypeScript
import type { GetServerSidePropsContext } from "next";
|
|
import type { ParsedUrlQuery } from "querystring";
|
|
import { vi, describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
|
|
import * as constants from "@calcom/lib/constants";
|
|
import { RedirectType } from "@calcom/prisma/client";
|
|
|
|
import { handleOrgRedirect, getRedirectWithOriginAndSearchString } from "./handleOrgRedirect";
|
|
|
|
// Mock prisma for all tests
|
|
const prismaMock = vi.hoisted(() => ({
|
|
tempOrgRedirect: {
|
|
findMany: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
vi.mock("@calcom/prisma", () => ({
|
|
default: prismaMock,
|
|
}));
|
|
|
|
const createTestContext = (overrides?: {
|
|
host?: string;
|
|
query?: ParsedUrlQuery;
|
|
}): GetServerSidePropsContext =>
|
|
({
|
|
req: {
|
|
headers: {
|
|
host: overrides?.host || "cal.local:3000",
|
|
},
|
|
},
|
|
query: overrides?.query || {},
|
|
} as unknown as GetServerSidePropsContext);
|
|
|
|
const createTestRedirectParams = (overrides?: {
|
|
slugs?: string[];
|
|
redirectType?: RedirectType;
|
|
eventTypeSlug?: string | null;
|
|
context?: GetServerSidePropsContext;
|
|
currentOrgDomain?: string | null;
|
|
}) => ({
|
|
slugs: overrides?.slugs || ["pro"],
|
|
redirectType: overrides?.redirectType || RedirectType.User,
|
|
eventTypeSlug: overrides?.eventTypeSlug ?? null,
|
|
context: overrides?.context || createTestContext(),
|
|
currentOrgDomain: overrides?.currentOrgDomain ?? null,
|
|
});
|
|
|
|
interface RedirectScenario {
|
|
redirects: Array<{
|
|
from: string;
|
|
toUrl: string;
|
|
type?: RedirectType;
|
|
}>;
|
|
}
|
|
|
|
const createRedirectScenario = (scenario: RedirectScenario) => {
|
|
// Create a map for quick lookup based on input parameters
|
|
const redirectMap = new Map<string, (typeof scenario.redirects)[0]>();
|
|
|
|
scenario.redirects.forEach((redirect) => {
|
|
const key = `${redirect.type || RedirectType.User}-${redirect.from}`;
|
|
redirectMap.set(key, redirect);
|
|
});
|
|
|
|
// Return a mock implementation that returns data based on the actual query
|
|
prismaMock.tempOrgRedirect.findMany.mockImplementation(async (params) => {
|
|
const { type, from } = params?.where || {};
|
|
const slugsToFind = from?.in || [];
|
|
|
|
// Return redirects that match the requested type and slugs
|
|
const matchingRedirects = slugsToFind
|
|
.map((slug: string) => {
|
|
const key = `${type}-${slug}`;
|
|
const redirect = redirectMap.get(key);
|
|
if (redirect) {
|
|
return {
|
|
from: redirect.from,
|
|
toUrl: redirect.toUrl,
|
|
type: redirect.type || type,
|
|
fromOrgId: 0,
|
|
};
|
|
}
|
|
return null;
|
|
})
|
|
.filter(Boolean);
|
|
|
|
return matchingRedirects;
|
|
});
|
|
};
|
|
|
|
const expectRedirectTo = (result: any, expectedDestination: string) => {
|
|
expect(result).toEqual({
|
|
redirect: {
|
|
permanent: false,
|
|
destination: expectedDestination,
|
|
},
|
|
});
|
|
};
|
|
|
|
const expectNoRedirect = (result: any) => {
|
|
expect(result).toBeNull();
|
|
};
|
|
|
|
const expectPrismaCalledWith = (expectedParams: { type: RedirectType; slugs: string[] }) => {
|
|
expect(prismaMock.tempOrgRedirect.findMany).toHaveBeenCalledWith({
|
|
where: {
|
|
type: expectedParams.type,
|
|
from: {
|
|
in: expectedParams.slugs,
|
|
},
|
|
fromOrgId: 0,
|
|
},
|
|
});
|
|
};
|
|
|
|
const expectPrismaNotCalled = () => {
|
|
expect(prismaMock.tempOrgRedirect.findMany).not.toHaveBeenCalled();
|
|
};
|
|
|
|
// Verify that the redirect was actually built from the data returned by Prisma
|
|
const expectRedirectUsesData = (
|
|
result: any,
|
|
expectedSlug: string,
|
|
expectedOrigin = "https://acme.cal.local:3000"
|
|
) => {
|
|
if (!result || !result.redirect) {
|
|
throw new Error("Expected a redirect result but got null/undefined");
|
|
}
|
|
const url = new URL(result.redirect.destination);
|
|
expect(url.origin).toBe(expectedOrigin);
|
|
expect(url.pathname).toContain(expectedSlug);
|
|
};
|
|
|
|
describe("handleOrgRedirect", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
// Default to no redirects - tests will override with specific scenarios
|
|
createRedirectScenario({ redirects: [] });
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe("when not in organization context", () => {
|
|
it("should redirect to organization URL when redirect exists", async () => {
|
|
// Setup scenario with unique test data to verify correct usage
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "pro",
|
|
toUrl: "https://acme.cal.local:3000/pro-example",
|
|
type: RedirectType.User,
|
|
},
|
|
// Add a decoy redirect to ensure the code picks the right one
|
|
{
|
|
from: "other-user",
|
|
toUrl: "https://acme.cal.local:3000/wrong-redirect",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
slugs: ["pro"],
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectPrismaCalledWith({ type: RedirectType.User, slugs: ["pro"] });
|
|
expectRedirectTo(result, "https://acme.cal.local:3000/pro-example?orgRedirection=true");
|
|
expectRedirectUsesData(result, "pro-example");
|
|
});
|
|
|
|
it("should return null when no redirect exists", async () => {
|
|
// Explicitly set up no redirects scenario
|
|
createRedirectScenario({ redirects: [] });
|
|
|
|
const params = createTestRedirectParams({
|
|
slugs: ["pro"],
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectPrismaCalledWith({ type: RedirectType.User, slugs: ["pro"] });
|
|
expectNoRedirect(result);
|
|
});
|
|
|
|
it("should handle Team redirect type", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "sales-team",
|
|
toUrl: "https://acme.cal.local:3000/sales",
|
|
type: RedirectType.Team,
|
|
},
|
|
// Add a User redirect with same slug to verify type filtering
|
|
{
|
|
from: "sales-team",
|
|
toUrl: "https://acme.cal.local:3000/wrong-user-redirect",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
slugs: ["sales-team"],
|
|
redirectType: RedirectType.Team,
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectPrismaCalledWith({ type: RedirectType.Team, slugs: ["sales-team"] });
|
|
expectRedirectTo(result, "https://acme.cal.local:3000/sales?orgRedirection=true");
|
|
expectRedirectUsesData(result, "sales");
|
|
});
|
|
});
|
|
|
|
describe("when SINGLE_ORG_SLUG mode is enabled", () => {
|
|
beforeEach(() => {
|
|
vi.spyOn(constants, "SINGLE_ORG_SLUG", "get").mockReturnValue("acme");
|
|
});
|
|
|
|
it("should redirect using relative path when accessing from base domain", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "pro",
|
|
toUrl: "https://acme.cal.local:3000/pro-example",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
context: createTestContext({ host: "cal.local:3000" }),
|
|
currentOrgDomain: "acme",
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectPrismaCalledWith({ type: RedirectType.User, slugs: ["pro"] });
|
|
// Should use relative path to stay on same domain
|
|
expectRedirectTo(result, "/pro-example?orgRedirection=true");
|
|
});
|
|
|
|
it("should redirect john87 to john using relative path in single org mode", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "john87",
|
|
toUrl: "https://acme.cal.local:3000/john",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
slugs: ["john87"],
|
|
context: createTestContext({
|
|
host: "my-instance.com",
|
|
}),
|
|
currentOrgDomain: "acme",
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectPrismaCalledWith({ type: RedirectType.User, slugs: ["john87"] });
|
|
// Should redirect to relative path /john to stay on my-instance.com
|
|
expectRedirectTo(result, "/john?orgRedirection=true");
|
|
});
|
|
|
|
describe("when orgRedirection parameter is present", () => {
|
|
it("should not redirect to prevent loops", async () => {
|
|
const params = createTestRedirectParams({
|
|
context: createTestContext({ query: { orgRedirection: "true" } }),
|
|
currentOrgDomain: "acme",
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectPrismaNotCalled();
|
|
expectNoRedirect(result);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("when event type slug is provided", () => {
|
|
it("should include event type slug in redirect destination", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "pro",
|
|
toUrl: "https://acme.cal.local:3000/pro-example",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
eventTypeSlug: "30min",
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectPrismaCalledWith({ type: RedirectType.User, slugs: ["pro"] });
|
|
expectRedirectTo(result, "https://acme.cal.local:3000/pro-example/30min?orgRedirection=true");
|
|
// Verify the event type slug was properly appended
|
|
const url = new URL(result?.redirect.destination || "");
|
|
expect(url.pathname).toBe("/pro-example/30min");
|
|
});
|
|
|
|
it("should handle empty event type slug", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "pro",
|
|
toUrl: "https://acme.cal.local:3000/pro-example",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
eventTypeSlug: null,
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectRedirectTo(result, "https://acme.cal.local:3000/pro-example?orgRedirection=true");
|
|
expectRedirectUsesData(result, "pro-example");
|
|
});
|
|
});
|
|
|
|
describe("when handling multiple slugs (group bookings)", () => {
|
|
it("should preserve order of slugs in redirect", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "user1",
|
|
toUrl: "https://acme.cal.local:3000/org-user1",
|
|
type: RedirectType.User,
|
|
},
|
|
{
|
|
from: "user2",
|
|
toUrl: "https://acme.cal.local:3000/org-user2",
|
|
type: RedirectType.User,
|
|
},
|
|
{
|
|
from: "user3",
|
|
toUrl: "https://acme.cal.local:3000/org-user3",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
slugs: ["user1", "user2", "user3"],
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectRedirectTo(
|
|
result,
|
|
"https://acme.cal.local:3000/org-user1+org-user2+org-user3?orgRedirection=true"
|
|
);
|
|
// Verify order is preserved from input slugs
|
|
const url = new URL(result?.redirect.destination || "");
|
|
expect(url.pathname).toBe("/org-user1+org-user2+org-user3");
|
|
});
|
|
|
|
it("should handle partial redirects in group bookings", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "user1",
|
|
toUrl: "https://acme.cal.local:3000/org-user1",
|
|
type: RedirectType.User,
|
|
},
|
|
// user2 has no redirect - it should stay as-is
|
|
{
|
|
from: "user3",
|
|
toUrl: "https://acme.cal.local:3000/org-user3",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
slugs: ["user1", "user2", "user3"],
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectRedirectTo(result, "https://acme.cal.local:3000/org-user1+user2+org-user3?orgRedirection=true");
|
|
// Verify that user2 remains unchanged while others are redirected
|
|
const url = new URL(result?.redirect.destination || "");
|
|
expect(url.pathname).toBe("/org-user1+user2+org-user3");
|
|
});
|
|
|
|
it("should handle different origins in redirects", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "user1",
|
|
toUrl: "https://org1.cal.com/john",
|
|
type: RedirectType.User,
|
|
},
|
|
{
|
|
from: "user2",
|
|
toUrl: "https://org1.cal.com/jane",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
slugs: ["user1", "user2"],
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
// Should use the first redirect's origin
|
|
expectRedirectTo(result, "https://org1.cal.com/john+jane?orgRedirection=true");
|
|
expectRedirectUsesData(result, "john+jane", "https://org1.cal.com");
|
|
});
|
|
});
|
|
|
|
describe("when handling query parameters", () => {
|
|
it("should add orgRedirection=true to empty query", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "pro",
|
|
toUrl: "https://acme.cal.local:3000/pro-example",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
context: createTestContext({ query: {} }),
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectRedirectTo(result, "https://acme.cal.local:3000/pro-example?orgRedirection=true");
|
|
expectRedirectUsesData(result, "pro-example");
|
|
});
|
|
|
|
it("should preserve existing query parameters", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "pro",
|
|
toUrl: "https://acme.cal.local:3000/pro-example",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
context: createTestContext({
|
|
query: { abc: "1", xyz: "test" },
|
|
}),
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectRedirectTo(result, "https://acme.cal.local:3000/pro-example?abc=1&xyz=test&orgRedirection=true");
|
|
// Verify query parameters are preserved
|
|
const url = new URL(result?.redirect.destination || "");
|
|
expect(url.searchParams.get("abc")).toBe("1");
|
|
expect(url.searchParams.get("xyz")).toBe("test");
|
|
});
|
|
|
|
it("should not duplicate orgRedirection parameter", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "pro",
|
|
toUrl: "https://acme.cal.local:3000/pro-example",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
context: createTestContext({
|
|
query: { orgRedirection: "true", abc: "1" },
|
|
}),
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectRedirectTo(result, "https://acme.cal.local:3000/pro-example?abc=1&orgRedirection=true");
|
|
|
|
// Verify only one orgRedirection parameter exists
|
|
const url = new URL(result?.redirect.destination || "");
|
|
const orgRedirectionParams = url.searchParams.getAll("orgRedirection");
|
|
expect(orgRedirectionParams).toHaveLength(1);
|
|
expect(orgRedirectionParams[0]).toBe("true");
|
|
});
|
|
|
|
it("should handle array query parameters", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "pro",
|
|
toUrl: "https://acme.cal.local:3000/pro-example",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
context: createTestContext({
|
|
query: { tags: ["tag1", "tag2"], filter: "active" },
|
|
}),
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
const url = new URL(result?.redirect.destination || "");
|
|
expect(url.searchParams.getAll("tags")).toEqual(["tag1", "tag2"]);
|
|
expect(url.searchParams.get("filter")).toBe("active");
|
|
expect(url.searchParams.get("orgRedirection")).toBe("true");
|
|
});
|
|
});
|
|
|
|
describe("edge cases and error scenarios", () => {
|
|
it("should handle empty slugs array", async () => {
|
|
createRedirectScenario({ redirects: [] });
|
|
|
|
const params = createTestRedirectParams({
|
|
slugs: [],
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectPrismaCalledWith({ type: RedirectType.User, slugs: [] });
|
|
expectNoRedirect(result);
|
|
});
|
|
|
|
it("should handle redirects with trailing slashes", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "pro",
|
|
toUrl: "https://acme.cal.local:3000/pro-example/",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams();
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectRedirectTo(result, "https://acme.cal.local:3000/pro-example/?orgRedirection=true");
|
|
// Verify trailing slash is preserved
|
|
const url = new URL(result?.redirect.destination || "");
|
|
expect(url.pathname).toBe("/pro-example/");
|
|
});
|
|
|
|
it("should handle redirects to root path", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "pro",
|
|
toUrl: "https://acme.cal.local:3000",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams();
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectRedirectTo(result, "https://acme.cal.local:3000?orgRedirection=true");
|
|
// Verify root path redirect
|
|
const url = new URL(result?.redirect.destination || "");
|
|
expect(url.pathname).toBe("/");
|
|
});
|
|
|
|
it("should handle special characters in slugs", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "user-name.test",
|
|
toUrl: "https://acme.cal.local:3000/user_name_test",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = createTestRedirectParams({
|
|
slugs: ["user-name.test"],
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectRedirectTo(result, "https://acme.cal.local:3000/user_name_test?orgRedirection=true");
|
|
expectRedirectUsesData(result, "user_name_test");
|
|
});
|
|
});
|
|
|
|
describe("when SINGLE_ORG_SLUG is not set", () => {
|
|
beforeEach(() => {
|
|
vi.spyOn(constants, "SINGLE_ORG_SLUG", "get").mockReturnValue(undefined);
|
|
});
|
|
|
|
it("should not check for redirects when in org context", async () => {
|
|
const params = createTestRedirectParams({
|
|
currentOrgDomain: "acme",
|
|
});
|
|
const result = await handleOrgRedirect(params);
|
|
|
|
expectPrismaNotCalled();
|
|
expectNoRedirect(result);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("getRedirectWithOriginAndSearchString", () => {
|
|
beforeEach(() => {
|
|
vi.spyOn(constants, "SINGLE_ORG_SLUG", "get").mockReturnValue(undefined);
|
|
});
|
|
|
|
afterEach(() => {
|
|
prismaMock.tempOrgRedirect.findMany.mockReset();
|
|
});
|
|
|
|
it("should return origin and search string for absolute URL redirects", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "john",
|
|
toUrl: "https://acme.cal.local:3000/john-org",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = {
|
|
slugs: ["john"],
|
|
redirectType: RedirectType.User,
|
|
context: createTestContext(),
|
|
currentOrgDomain: null,
|
|
};
|
|
const result = await getRedirectWithOriginAndSearchString(params);
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result?.origin).toBe("https://acme.cal.local:3000");
|
|
expect(result?.searchString).toBe("?orgRedirection=true");
|
|
});
|
|
|
|
it("should return null origin for relative path redirects", async () => {
|
|
// Enable SINGLE_ORG_SLUG for this test to get relative paths
|
|
vi.spyOn(constants, "SINGLE_ORG_SLUG", "get").mockReturnValue("acme");
|
|
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "john",
|
|
toUrl: "https://acme.cal.local:3000/john-org",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = {
|
|
slugs: ["john"],
|
|
redirectType: RedirectType.User,
|
|
context: createTestContext({ host: "my-instance.com" }),
|
|
currentOrgDomain: "acme",
|
|
};
|
|
const result = await getRedirectWithOriginAndSearchString(params);
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result?.origin).toBeNull(); // Relative path has no origin
|
|
expect(result?.searchString).toBe("?orgRedirection=true");
|
|
});
|
|
|
|
it("should preserve existing query parameters in search string", async () => {
|
|
createRedirectScenario({
|
|
redirects: [
|
|
{
|
|
from: "john",
|
|
toUrl: "https://acme.cal.local:3000/john-org",
|
|
type: RedirectType.User,
|
|
},
|
|
],
|
|
});
|
|
|
|
const params = {
|
|
slugs: ["john"],
|
|
redirectType: RedirectType.User,
|
|
context: createTestContext({ query: { foo: "bar", baz: "qux" } }),
|
|
currentOrgDomain: null,
|
|
};
|
|
const result = await getRedirectWithOriginAndSearchString(params);
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result?.origin).toBe("https://acme.cal.local:3000");
|
|
expect(result?.searchString).toBe("?foo=bar&baz=qux&orgRedirection=true");
|
|
});
|
|
|
|
it("should return null when no redirect exists", async () => {
|
|
createRedirectScenario({ redirects: [] });
|
|
|
|
const params = {
|
|
slugs: ["john"],
|
|
redirectType: RedirectType.User,
|
|
context: createTestContext(),
|
|
currentOrgDomain: null,
|
|
};
|
|
const result = await getRedirectWithOriginAndSearchString(params);
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
});
|