make supabase client singleton

This commit is contained in:
Naytitorn Chaovirachot 2024-11-26 00:45:18 +07:00
parent 42a4fc4293
commit 8a65012044
8 changed files with 2085 additions and 30 deletions

View File

@ -1,3 +1,3 @@
{
"presets": ["next/babel"]
"presets": ["next/babel"]
}

View File

@ -2,8 +2,9 @@ import { render } from "@testing-library/react";
// Pages - Admin
import AdminPage from "@/app/admin/page";
import BusinesssApplicationAdminPage from "@/app/admin/business/page";
import BusinessApplicationAdminPage from "@/app/admin/business/page";
import ProjectAdminPage from "@/app/admin/business/[businessId]/projects/page";
import { createSupabaseClient } from "@/lib/supabase/serverComponentClient";
// Mock Cookies
jest.mock("next/headers", () => ({
@ -13,15 +14,31 @@ jest.mock("next/headers", () => ({
})),
}));
jest.mock('next/navigation', () => ({
redirect: jest.fn(),
}));
// Admin Pages
describe("Admin Pages", () => {
it("Admin Page should render without crashing", async () => {
render(await AdminPage());
});
// it("Business Application Admin Page should render without crashing", async () => {
// render(await BusinesssApplicationAdminPage());
// });
it("Business Application Admin Page should render without crashing", async () => {
const mockGetUser = jest.spyOn(createSupabaseClient().auth, 'getUser');
// Mock the getUser method's implementation to return a full User object
mockGetUser.mockResolvedValue({
data: {
user: {
id: '4d31cfe0-8ebd-4bc8-915e-d301ecaffb33',
}
},
error: null,
});
render(await BusinessApplicationAdminPage());
});
it("Project Admin Page should render without crashing", async () => {
render(await ProjectAdminPage({ params: { businessId: "1" } }));

View File

@ -1,3 +1,4 @@
import React from 'react';
import { render } from "@testing-library/react";
// Pages - Business
@ -26,8 +27,10 @@ jest.mock('next/navigation', () => ({
}));
// Business Pages
// describe("Business Pages", () => {
// it("Apply Business Page should render without crashing", async () => {
// render(await ApplyBusiness());
// });
// });
describe("Business Pages", () => {
// it("Apply Business Page should render without crashing", async () => {
// jest.spyOn(React, 'useRef').mockReturnValue({ current: false });
// jest.spyOn(React, 'useEffect').mockImplementation((fn) => fn());
// render(await ApplyBusiness());
// });
});

View File

@ -13,7 +13,10 @@ const config: Config = {
transformIgnorePatterns: [
'/node_modules/(?!(flat|@supabase-cache-helpers|react-markdown)/)'
],
setupFiles: ["jest-canvas-mock"]
setupFiles: ["jest-canvas-mock"],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1', // Resolves @/ to src/
},
// Add more setup options before each test is run
// setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
}

2017
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -76,6 +76,8 @@
"zod": "^3.23.8"
},
"devDependencies": {
"@babel/preset-env": "^7.26.0",
"@babel/preset-react": "^7.25.9",
"@babel/preset-typescript": "^7.26.0",
"@eslint/js": "^9.13.0",
"@playwright/test": "^1.47.2",
@ -94,6 +96,7 @@
"@types/react-file-icon": "^1.0.4",
"@types/react-lottie": "^1.2.10",
"@types/react-select-country-list": "^2.2.3",
"babel-jest": "^29.7.0",
"eslint": "^8.57.1",
"eslint-config-next": "14.2.5",
"eslint-config-prettier": "^9.1.0",

View File

@ -81,13 +81,14 @@ function ApplicationTable({ applications }: { applications: ApplicationData[] })
));
}
export default async function BusinesssApplicationAdminPage() {
export default async function BusinessApplicationAdminPage() {
const client = createSupabaseClient();
const { data: userData, error: userDataError } = await client.auth.getUser();
if (userDataError) {
redirect("/");
}
const uid = userData.user!.id;
const { data: roleData, error: roleDataError } = await getUserRole(client, uid);
@ -104,7 +105,7 @@ export default async function BusinesssApplicationAdminPage() {
const pendingApplications = businessApplicationData?.filter((app) => app.status === "pending") || [];
const approvedApplications = businessApplicationData?.filter((app) => app.status === "approve") || [];
const rejectedApplications = businessApplicationData?.filter((app) => app.status === "rejecte") || [];
const rejectedApplications = businessApplicationData?.filter((app) => app.status === "rejected") || [];
return (
<div className="container max-w-screen-xl my-4">

View File

@ -1,21 +1,32 @@
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
export function createSupabaseClient() {
const cookieStore = cookies();
let supabaseClient: ReturnType<typeof createServerClient> | null = null;
return createServerClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, {
cookies: {
getAll() {
return cookieStore.getAll();
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options));
} catch (error) {
console.error("Error setting cookies:", error);
}
},
},
});
}
// This is singleton
export function createSupabaseClient() {
if (!supabaseClient) {
const cookieStore = cookies();
supabaseClient = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll();
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options));
} catch (error) {
console.error("Error setting cookies:", error);
}
},
},
}
);
}
return supabaseClient;
}