Skip to content

Instantly share code, notes, and snippets.

@ellemedit
Last active July 12, 2024 11:50
Show Gist options
  • Save ellemedit/33e02ee544cbcd076c94f2157e68a5cc to your computer and use it in GitHub Desktop.
Save ellemedit/33e02ee544cbcd076c94f2157e68a5cc to your computer and use it in GitHub Desktop.
NextJS App Router cookie module mock with Bun/TypeScript
import { mock } from "bun:test";
import { ReadonlyRequestCookies } from "next/dist/server/web/spec-extension/adapters/request-cookies";
export function mockNextjsReadonlyCookie() {
mock.module("next/headers", () => {
const cookieMap = new Map<string, { name: string; value: string }>();
const cookies: ReadonlyRequestCookies = {
get: (nameOrCookie: string | { name: string }) => {
const name =
typeof nameOrCookie === "string" ? nameOrCookie : nameOrCookie.name;
const cookie = cookieMap.get(name);
return cookie ? { name: cookie.name, value: cookie.value } : undefined;
},
has: (nameOrCookie: string | { name: string }) => {
const name =
typeof nameOrCookie === "string" ? nameOrCookie : nameOrCookie.name;
return cookieMap.has(name);
},
set: () => {
throw new Error(
"You should not set cookies in readonly mode like Server Component or Data Access Layer",
);
},
delete: () => {
throw new Error(
"You should not set cookies in readonly mode like Server Component or Data Access Layer",
);
},
get size() {
return cookieMap.size;
},
getAll: (...args: Array<string | { name: string }> | []) => {
if (args.length === 0) {
return Array.from(cookieMap.values());
}
const names = new Set(
args.map((arg) => (typeof arg === "string" ? arg : arg.name)),
);
return Array.from(cookieMap.values()).filter((cookie) =>
names.has(cookie.name),
);
},
[Symbol.iterator]: () => cookieMap.entries(),
};
return {
cookies: () => cookies,
headers: () => {
throw new Error("not implemented yet, mock this");
},
draftMode: () => {
throw new Error("not implemented yet, mock this");
},
};
});
}
export function mockNextjsMutableCookie() {
mock.module("next/headers", () => {
const cookieMap = new Map<string, { name: string; value: string }>();
const cookies: ReadonlyRequestCookies = {
get: (nameOrCookie: string | { name: string }) => {
const name =
typeof nameOrCookie === "string" ? nameOrCookie : nameOrCookie.name;
const cookie = cookieMap.get(name);
return cookie ? { name: cookie.name, value: cookie.value } : undefined;
},
has: (nameOrCookie: string | { name: string }) => {
const name =
typeof nameOrCookie === "string" ? nameOrCookie : nameOrCookie.name;
return cookieMap.has(name);
},
set: (...args: [string, string] | [{ name: string; value: string }]) => {
if (typeof args[0] === "string") {
cookieMap.set(args[0], { name: args[0], value: args[1]! });
} else if (typeof args[0] === "object") {
const cookie = args[0];
cookieMap.set(cookie.name, cookie);
} else {
throw new Error("Invalid cookie set or mock bug");
}
return cookies;
},
delete: (nameOrCookie: string | { name: string }) => {
const name =
typeof nameOrCookie === "string" ? nameOrCookie : nameOrCookie.name;
if (cookieMap.has(name)) {
cookieMap.set(name, { name, value: "" });
}
return cookies;
},
get size() {
return cookieMap.size;
},
getAll: (...args: Array<string | { name: string }> | []) => {
if (args.length === 0) {
return Array.from(cookieMap.values());
}
const names = new Set(
args.map((arg) => (typeof arg === "string" ? arg : arg.name)),
);
return Array.from(cookieMap.values()).filter((cookie) =>
names.has(cookie.name),
);
},
[Symbol.iterator]: () => cookieMap.entries(),
};
return {
cookies: () => cookies,
headers: () => {
throw new Error("not implemented yet, mock this");
},
draftMode: () => {
throw new Error("not implemented yet, mock this");
},
};
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment