chore: search bar and preview on survey list page (#6349)

Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com>
This commit is contained in:
Dhruwang Jariwala
2025-08-07 10:27:28 +05:30
committed by GitHub
parent f239ee9697
commit 68dc63ce0b
10 changed files with 603 additions and 54 deletions
@@ -123,14 +123,14 @@ export const EnvironmentLayout = async ({ environmentId, session, children }: En
isLicenseActive={active}
isAccessControlAllowed={isAccessControlAllowed}
/>
<div id="mainContent" className="flex-1 overflow-y-auto bg-slate-50">
<div id="mainContent" className="flex flex-1 flex-col overflow-hidden bg-slate-50">
<TopControlBar
environment={environment}
environments={environments}
membershipRole={membershipRole}
projectPermission={projectPermission}
/>
<div className="mt-14">{children}</div>
<div className="flex-1 overflow-y-auto">{children}</div>
</div>
</div>
</div>
@@ -44,10 +44,8 @@ describe("TopControlBar", () => {
);
// Check if the main div is rendered
const mainDiv = screen.getByTestId("top-control-buttons").parentElement?.parentElement?.parentElement;
expect(mainDiv).toHaveClass(
"fixed inset-0 top-0 z-30 flex h-14 w-full items-center justify-end bg-slate-50 px-6"
);
const mainDiv = screen.getByTestId("fb__global-top-control-bar");
expect(mainDiv).toHaveClass("flex h-14 w-full items-center justify-end bg-slate-50 px-6");
// Check if the mocked child component is rendered
expect(screen.getByTestId("top-control-buttons")).toBeInTheDocument();
@@ -17,7 +17,9 @@ export const TopControlBar = ({
projectPermission,
}: SideBarProps) => {
return (
<div className="fixed inset-0 top-0 z-30 flex h-14 w-full items-center justify-end bg-slate-50 px-6">
<div
className="flex h-14 w-full items-center justify-end bg-slate-50 px-6"
data-testid="fb__global-top-control-bar">
<div className="shadow-xs z-10">
<div className="flex w-fit items-center space-x-2 py-2">
<TopControlButtons
@@ -7,6 +7,7 @@ import { TSurvey } from "@/modules/survey/list/types/surveys";
import { Button } from "@/modules/ui/components/button";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { useTranslate } from "@tolgee/react";
import { useRouter } from "next/navigation";
import { useCallback, useEffect, useMemo, useState } from "react";
import { wrapThrows } from "@formbricks/types/error-handlers";
import { TProjectConfigChannel } from "@formbricks/types/project";
@@ -43,6 +44,7 @@ export const SurveysList = ({
currentProjectChannel,
locale,
}: SurveysListProps) => {
const router = useRouter();
const [surveys, setSurveys] = useState<TSurvey[]>([]);
const [isFetching, setIsFetching] = useState(true);
const [hasMore, setHasMore] = useState<boolean>(true);
@@ -124,7 +126,10 @@ export const SurveysList = ({
const handleDeleteSurvey = async (surveyId: string) => {
const newSurveys = surveys.filter((survey) => survey.id !== surveyId);
setSurveys(newSurveys);
if (newSurveys.length === 0) setIsFetching(true);
if (newSurveys.length === 0) {
setIsFetching(true);
router.refresh();
}
};
const triggerRefresh = useCallback(() => {
+388
View File
@@ -0,0 +1,388 @@
import { TEnvironmentAuth } from "@/modules/environments/types/environment-auth";
import "@testing-library/jest-dom/vitest";
import { cleanup, render, screen } from "@testing-library/react";
import { Session } from "next-auth";
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import { TEnvironment } from "@formbricks/types/environment";
import { TProject } from "@formbricks/types/project";
import { TTemplateRole } from "@formbricks/types/templates";
import { SurveysPage } from "./page";
// Mock all dependencies
vi.mock("@/lib/constants", () => ({
DEFAULT_LOCALE: "en-US",
SURVEYS_PER_PAGE: 12,
}));
vi.mock("@/lib/getPublicUrl", () => ({
getPublicDomain: vi.fn(),
}));
vi.mock("@/lib/user/service", () => ({
getUserLocale: vi.fn(),
}));
vi.mock("@/modules/environments/lib/utils", () => ({
getEnvironmentAuth: vi.fn(),
}));
vi.mock("@/modules/survey/lib/project", () => ({
getProjectWithTeamIdsByEnvironmentId: vi.fn(),
}));
vi.mock("@/modules/survey/list/components/survey-list", () => ({
SurveysList: vi.fn(
({ environmentId, isReadOnly, publicDomain, userId, surveysPerPage, currentProjectChannel, locale }) => (
<div
data-testid="surveys-list"
data-environment-id={environmentId}
data-readonly={isReadOnly}
data-public-domain={publicDomain}
data-user-id={userId}
data-surveys-per-page={surveysPerPage}
data-channel={currentProjectChannel}
data-locale={locale}>
Surveys List
</div>
)
),
}));
vi.mock("@/modules/survey/list/lib/survey", () => ({
getSurveyCount: vi.fn(),
}));
vi.mock("@/modules/survey/templates/components/template-container", () => ({
TemplateContainerWithPreview: vi.fn(
({ userId, environment, project, prefilledFilters, isTemplatePage }) => (
<div
data-testid="template-container"
data-user-id={userId}
data-environment-id={environment.id}
data-project-id={project.id}
data-prefilled-filters={JSON.stringify(prefilledFilters)}
data-is-template-page={isTemplatePage}>
Template Container
</div>
)
),
}));
vi.mock("@/modules/ui/components/button", () => ({
Button: vi.fn(({ size, asChild, children }) => (
<button data-testid="create-survey-button" type="button" data-size={size} data-as-child={asChild}>
{children}
</button>
)),
}));
vi.mock("@/modules/ui/components/page-content-wrapper", () => ({
PageContentWrapper: vi.fn(({ children }) => <div data-testid="page-content-wrapper">{children}</div>),
}));
vi.mock("@/modules/ui/components/page-header", () => ({
PageHeader: vi.fn(({ pageTitle, cta }) => (
<div data-testid="page-header">
<span data-testid="page-title">{pageTitle}</span>
{cta}
</div>
)),
}));
vi.mock("@/tolgee/server", () => ({
getTranslate: vi.fn(),
}));
vi.mock("next/link", () => ({
default: vi.fn(({ href, children }) => (
<a href={href} data-testid="link">
{children}
</a>
)),
}));
describe("SurveysPage", () => {
afterEach(() => {
cleanup();
vi.clearAllMocks();
});
const mockSession: Session = {
user: {
id: "user-123",
},
expires: "2024-12-31T23:59:59.999Z",
};
const mockEnvironment: TEnvironment = {
id: "env-123",
createdAt: new Date(),
updatedAt: new Date(),
type: "development",
projectId: "project-123",
appSetupCompleted: true,
};
const mockProject: TProject = {
id: "project-123",
name: "Test Project",
createdAt: new Date(),
updatedAt: new Date(),
organizationId: "org-123",
config: {
channel: "website",
industry: "other",
},
styling: {
brandColor: {
light: "#000000",
},
},
} as TProject;
const mockEnvironmentAuth: TEnvironmentAuth = {
session: mockSession,
environment: mockEnvironment,
project: mockProject,
organization: {
id: "org-123",
name: "Test Organization",
createdAt: new Date(),
updatedAt: new Date(),
billing: null,
} as any,
currentUserMembership: {
userId: "user-123",
organizationId: "org-123",
accepted: true,
role: "admin",
} as any,
projectPermission: null,
isMember: true,
isOwner: true,
isManager: false,
isBilling: false,
hasReadAccess: true,
hasReadWriteAccess: true,
hasManageAccess: true,
isReadOnly: false,
};
const mockTranslate = vi.fn((key: string) => key);
const mockGetPublicDomain = vi.fn();
const mockGetUserLocale = vi.fn();
const mockGetEnvironmentAuth = vi.fn();
const mockGetProjectWithTeamIdsByEnvironmentId = vi.fn();
const mockGetSurveyCount = vi.fn();
const mockGetTranslate = vi.fn();
beforeEach(async () => {
mockGetPublicDomain.mockReturnValue("https://app.formbricks.com");
mockGetUserLocale.mockResolvedValue("en-US");
mockGetEnvironmentAuth.mockResolvedValue(mockEnvironmentAuth);
mockGetProjectWithTeamIdsByEnvironmentId.mockResolvedValue(mockProject);
mockGetSurveyCount.mockResolvedValue(5);
mockGetTranslate.mockResolvedValue(mockTranslate);
// Set up mocks
const { getPublicDomain } = await import("@/lib/getPublicUrl");
const { getUserLocale } = await import("@/lib/user/service");
const { getEnvironmentAuth } = await import("@/modules/environments/lib/utils");
const { getProjectWithTeamIdsByEnvironmentId } = await import("@/modules/survey/lib/project");
const { getSurveyCount } = await import("@/modules/survey/list/lib/survey");
const { getTranslate } = await import("@/tolgee/server");
vi.mocked(getPublicDomain).mockImplementation(mockGetPublicDomain);
vi.mocked(getUserLocale).mockImplementation(mockGetUserLocale);
vi.mocked(getEnvironmentAuth).mockImplementation(mockGetEnvironmentAuth);
vi.mocked(getProjectWithTeamIdsByEnvironmentId).mockImplementation(
mockGetProjectWithTeamIdsByEnvironmentId
);
vi.mocked(getSurveyCount).mockImplementation(mockGetSurveyCount);
vi.mocked(getTranslate).mockImplementation(mockGetTranslate);
});
test("throws error when project is not found", async () => {
mockGetProjectWithTeamIdsByEnvironmentId.mockResolvedValue(null);
mockTranslate.mockReturnValue("Project not found");
const params = Promise.resolve({ environmentId: "env-123" });
const searchParams = Promise.resolve({});
await expect(SurveysPage({ params, searchParams })).rejects.toThrow("Project not found");
expect(mockGetProjectWithTeamIdsByEnvironmentId).toHaveBeenCalledWith("env-123");
expect(mockTranslate).toHaveBeenCalledWith("common.project_not_found");
});
test("redirects to billing when isBilling is true", async () => {
const { redirect } = await import("next/navigation");
const mockRedirect = vi.mocked(redirect);
mockGetEnvironmentAuth.mockResolvedValue({
...mockEnvironmentAuth,
isBilling: true,
});
const params = Promise.resolve({ environmentId: "env-123" });
const searchParams = Promise.resolve({});
await SurveysPage({ params, searchParams });
expect(mockRedirect).toHaveBeenCalledWith("/environments/env-123/settings/billing");
});
test("renders TemplateContainerWithPreview when survey count is 0", async () => {
mockGetSurveyCount.mockResolvedValue(0);
const params = Promise.resolve({ environmentId: "env-123" });
const searchParams = Promise.resolve({ role: "product_manager" as TTemplateRole });
const result = await SurveysPage({ params, searchParams });
render(result);
expect(screen.getByTestId("template-container")).toBeInTheDocument();
expect(screen.getByTestId("template-container")).toHaveAttribute("data-user-id", "user-123");
expect(screen.getByTestId("template-container")).toHaveAttribute("data-environment-id", "env-123");
expect(screen.getByTestId("template-container")).toHaveAttribute("data-project-id", "project-123");
expect(screen.getByTestId("template-container")).toHaveAttribute("data-is-template-page", "false");
const prefilledFilters = JSON.parse(
screen.getByTestId("template-container").getAttribute("data-prefilled-filters") || "[]"
);
expect(prefilledFilters).toEqual(["website", "other", "product_manager"]);
});
test("renders surveys list when survey count is greater than 0", async () => {
mockGetSurveyCount.mockResolvedValue(5);
const params = Promise.resolve({ environmentId: "env-123" });
const searchParams = Promise.resolve({});
const result = await SurveysPage({ params, searchParams });
render(result);
expect(screen.getByTestId("page-content-wrapper")).toBeInTheDocument();
expect(screen.getByTestId("page-header")).toBeInTheDocument();
expect(screen.getByTestId("page-title")).toHaveTextContent("common.surveys");
expect(screen.getByTestId("create-survey-button")).toBeInTheDocument();
expect(screen.getByTestId("surveys-list")).toBeInTheDocument();
// Check SurveysList props
expect(screen.getByTestId("surveys-list")).toHaveAttribute("data-environment-id", "env-123");
expect(screen.getByTestId("surveys-list")).toHaveAttribute("data-readonly", "false");
expect(screen.getByTestId("surveys-list")).toHaveAttribute(
"data-public-domain",
"https://app.formbricks.com"
);
expect(screen.getByTestId("surveys-list")).toHaveAttribute("data-user-id", "user-123");
expect(screen.getByTestId("surveys-list")).toHaveAttribute("data-surveys-per-page", "12");
expect(screen.getByTestId("surveys-list")).toHaveAttribute("data-channel", "website");
expect(screen.getByTestId("surveys-list")).toHaveAttribute("data-locale", "en-US");
});
test("does not render create survey button when user is read-only", async () => {
mockGetEnvironmentAuth.mockResolvedValue({
...mockEnvironmentAuth,
isReadOnly: true,
});
mockGetSurveyCount.mockResolvedValue(5);
const params = Promise.resolve({ environmentId: "env-123" });
const searchParams = Promise.resolve({});
const result = await SurveysPage({ params, searchParams });
render(result);
expect(screen.getByTestId("page-header")).toBeInTheDocument();
expect(screen.queryByTestId("create-survey-button")).not.toBeInTheDocument();
expect(screen.getByTestId("surveys-list")).toHaveAttribute("data-readonly", "true");
});
test("renders TemplateContainer when user is read-only and no surveys exist", async () => {
mockGetEnvironmentAuth.mockResolvedValue({
...mockEnvironmentAuth,
isReadOnly: true,
});
mockGetSurveyCount.mockResolvedValue(0);
const params = Promise.resolve({ environmentId: "env-123" });
const searchParams = Promise.resolve({});
const result = await SurveysPage({ params, searchParams });
render(result);
// When survey count is 0, it should render TemplateContainer regardless of read-only status
expect(screen.getByTestId("template-container")).toBeInTheDocument();
expect(screen.getByTestId("template-container")).toHaveAttribute("data-user-id", "user-123");
expect(screen.getByTestId("template-container")).toHaveAttribute("data-environment-id", "env-123");
});
test("handles project with null channel and industry", async () => {
const projectWithNullConfig = {
...mockProject,
config: {
channel: null,
industry: null,
},
};
mockGetProjectWithTeamIdsByEnvironmentId.mockResolvedValue(projectWithNullConfig);
mockGetSurveyCount.mockResolvedValue(0);
const params = Promise.resolve({ environmentId: "env-123" });
const searchParams = Promise.resolve({});
const result = await SurveysPage({ params, searchParams });
render(result);
expect(screen.getByTestId("template-container")).toBeInTheDocument();
const prefilledFilters = JSON.parse(
screen.getByTestId("template-container").getAttribute("data-prefilled-filters") || "[]"
);
expect(prefilledFilters).toEqual([null, null, null]);
});
test("handles project with null styling", async () => {
const projectWithNullStyling = {
...mockProject,
styling: null,
};
mockGetProjectWithTeamIdsByEnvironmentId.mockResolvedValue(projectWithNullStyling);
mockGetSurveyCount.mockResolvedValue(0);
const params = Promise.resolve({ environmentId: "env-123" });
const searchParams = Promise.resolve({});
const result = await SurveysPage({ params, searchParams });
render(result);
expect(screen.getByTestId("template-container")).toBeInTheDocument();
// Should handle null styling gracefully
});
test("handles getUserLocale returning null", async () => {
mockGetUserLocale.mockResolvedValue(null);
mockGetSurveyCount.mockResolvedValue(5);
const params = Promise.resolve({ environmentId: "env-123" });
const searchParams = Promise.resolve({});
const result = await SurveysPage({ params, searchParams });
render(result);
expect(screen.getByTestId("surveys-list")).toHaveAttribute("data-locale", "en-US");
});
test("creates survey button with correct link", async () => {
mockGetSurveyCount.mockResolvedValue(5);
const params = Promise.resolve({ environmentId: "env-123" });
const searchParams = Promise.resolve({});
const result = await SurveysPage({ params, searchParams });
render(result);
expect(screen.getByTestId("link")).toHaveAttribute("href", "/environments/env-123/surveys/templates");
expect(screen.getByTestId("create-survey-button")).toBeInTheDocument();
});
});
+12 -15
View File
@@ -2,10 +2,10 @@ import { DEFAULT_LOCALE, SURVEYS_PER_PAGE } from "@/lib/constants";
import { getPublicDomain } from "@/lib/getPublicUrl";
import { getUserLocale } from "@/lib/user/service";
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
import { TemplateList } from "@/modules/survey/components/template-list";
import { getProjectWithTeamIdsByEnvironmentId } from "@/modules/survey/lib/project";
import { SurveysList } from "@/modules/survey/list/components/survey-list";
import { getSurveyCount } from "@/modules/survey/list/lib/survey";
import { TemplateContainerWithPreview } from "@/modules/survey/templates/components/template-container";
import { Button } from "@/modules/ui/components/button";
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
import { PageHeader } from "@/modules/ui/components/page-header";
@@ -73,6 +73,17 @@ export const SurveysPage = async ({
highlightBorderColor: null,
};
if (surveyCount === 0)
return (
<TemplateContainerWithPreview
userId={session.user.id}
environment={environment}
project={projectWithRequiredProps}
prefilledFilters={prefilledFilters}
isTemplatePage={false}
/>
);
let content;
if (surveyCount > 0) {
content = (
@@ -101,20 +112,6 @@ export const SurveysPage = async ({
</h2>
</>
);
} else {
content = (
<>
<h1 className="px-6 text-3xl font-extrabold text-slate-700">
{t("environments.surveys.all_set_time_to_create_first_survey")}
</h1>
<TemplateList
environmentId={environment.id}
project={projectWithRequiredProps}
userId={session.user.id}
prefilledFilters={prefilledFilters}
/>
</>
);
}
return <PageContentWrapper>{content}</PageContentWrapper>;
@@ -0,0 +1,183 @@
import { Project } from "@prisma/client";
import "@testing-library/jest-dom/vitest";
import { cleanup, render, screen } from "@testing-library/react";
import { afterEach, describe, expect, test, vi } from "vitest";
import { TProjectConfigChannel, TProjectConfigIndustry } from "@formbricks/types/project";
import { TTemplateRole } from "@formbricks/types/templates";
import { TemplateContainerWithPreview } from "./template-container";
// Mock dependencies
vi.mock("@/app/lib/templates", () => ({
customSurveyTemplate: vi.fn(() => ({
preset: {
questions: [{ id: "q1" }],
},
})),
}));
vi.mock("@/modules/survey/components/template-list", () => ({
TemplateList: vi.fn(() => <div data-testid="template-list">Template List</div>),
}));
vi.mock("@/modules/survey/templates/components/menu-bar", () => ({
MenuBar: vi.fn(() => <div data-testid="menu-bar">Menu Bar</div>),
}));
vi.mock("@/modules/ui/components/preview-survey", () => ({
PreviewSurvey: vi.fn(() => <div data-testid="preview-survey">Preview Survey</div>),
}));
vi.mock("@/modules/ui/components/search-bar", () => ({
SearchBar: vi.fn(({ placeholder, onChange, value }) => (
<input
data-testid="search-bar"
placeholder={placeholder}
onChange={(e) => onChange(e.target.value)}
value={value}
/>
)),
}));
vi.mock("../lib/minimal-survey", () => ({
getMinimalSurvey: vi.fn(() => ({})),
}));
const mockProject = {
id: "project1",
name: "Test Project",
createdAt: new Date(),
updatedAt: new Date(),
organizationId: "org1",
config: {
channel: "website" as TProjectConfigChannel,
industry: "technology" as TProjectConfigIndustry,
},
} as Project;
const mockEnvironment = {
id: "env1",
appSetupCompleted: true,
};
const mockPrefilledFilters: (TProjectConfigChannel | TProjectConfigIndustry | TTemplateRole | null)[] = [];
describe("TemplateContainerWithPreview", () => {
afterEach(() => {
cleanup();
});
test("renders MenuBar when isTemplatePage is true", () => {
render(
<TemplateContainerWithPreview
project={mockProject}
environment={mockEnvironment}
userId="user1"
prefilledFilters={mockPrefilledFilters}
isTemplatePage={true}
/>
);
expect(screen.getByTestId("menu-bar")).toBeInTheDocument();
});
test("does not render MenuBar when isTemplatePage is false", () => {
render(
<TemplateContainerWithPreview
project={mockProject}
environment={mockEnvironment}
userId="user1"
prefilledFilters={mockPrefilledFilters}
isTemplatePage={false}
/>
);
expect(screen.queryByTestId("menu-bar")).not.toBeInTheDocument();
});
test("displays correct title when isTemplatePage is true", () => {
render(
<TemplateContainerWithPreview
project={mockProject}
environment={mockEnvironment}
userId="user1"
prefilledFilters={mockPrefilledFilters}
isTemplatePage={true}
/>
);
expect(screen.getByText("environments.surveys.templates.create_a_new_survey")).toBeInTheDocument();
});
test("displays correct title when isTemplatePage is false", () => {
render(
<TemplateContainerWithPreview
project={mockProject}
environment={mockEnvironment}
userId="user1"
prefilledFilters={mockPrefilledFilters}
isTemplatePage={false}
/>
);
expect(screen.getByText("environments.surveys.all_set_time_to_create_first_survey")).toBeInTheDocument();
});
test("renders SearchBar with correct placeholder", () => {
render(
<TemplateContainerWithPreview
project={mockProject}
environment={mockEnvironment}
userId="user1"
prefilledFilters={mockPrefilledFilters}
isTemplatePage={true}
/>
);
const searchBar = screen.getByTestId("search-bar");
expect(searchBar).toBeInTheDocument();
expect(searchBar).toHaveAttribute("placeholder", "common.search");
});
test("renders TemplateList component", () => {
render(
<TemplateContainerWithPreview
project={mockProject}
environment={mockEnvironment}
userId="user1"
prefilledFilters={mockPrefilledFilters}
isTemplatePage={true}
/>
);
expect(screen.getByTestId("template-list")).toBeInTheDocument();
});
test("renders PreviewSurvey component in aside", () => {
render(
<TemplateContainerWithPreview
project={mockProject}
environment={mockEnvironment}
userId="user1"
prefilledFilters={mockPrefilledFilters}
isTemplatePage={true}
/>
);
expect(screen.getByTestId("preview-survey")).toBeInTheDocument();
});
test("has correct container structure with h-full class", () => {
render(
<TemplateContainerWithPreview
project={mockProject}
environment={mockEnvironment}
userId="user1"
prefilledFilters={mockPrefilledFilters}
isTemplatePage={true}
/>
);
const container = screen.getByTestId("menu-bar").parentElement;
expect(container).toHaveClass("flex", "h-full", "flex-col");
});
});
@@ -18,6 +18,7 @@ type TemplateContainerWithPreviewProps = {
environment: Pick<Environment, "id" | "appSetupCompleted">;
userId: string;
prefilledFilters: (TProjectConfigChannel | TProjectConfigIndustry | TTemplateRole | null)[];
isTemplatePage?: boolean;
};
export const TemplateContainerWithPreview = ({
@@ -25,6 +26,7 @@ export const TemplateContainerWithPreview = ({
environment,
userId,
prefilledFilters,
isTemplatePage = true,
}: TemplateContainerWithPreviewProps) => {
const { t } = useTranslate();
const initialTemplate = customSurveyTemplate(t);
@@ -34,12 +36,14 @@ export const TemplateContainerWithPreview = ({
return (
<div className="flex h-full flex-col">
<MenuBar />
{isTemplatePage && <MenuBar />}
<div className="relative z-0 flex flex-1 overflow-hidden">
<div className="flex-1 flex-col overflow-auto bg-slate-50">
<div className="mb-3 ml-6 mt-6 flex flex-col items-center justify-between md:flex-row md:items-end">
<h1 className="text-2xl font-bold text-slate-800">
{t("environments.surveys.templates.create_a_new_survey")}
{isTemplatePage
? t("environments.surveys.templates.create_a_new_survey")
: t("environments.surveys.all_set_time_to_create_first_survey")}
</h1>
<div className="px-6">
<SearchBar
@@ -17,32 +17,4 @@ describe("PageContentWrapper", () => {
expect(getByText("Test Content")).toBeInTheDocument();
});
test("applies default classes", () => {
const { container } = render(
<PageContentWrapper>
<div>Test Content</div>
</PageContentWrapper>
);
const wrapper = container.firstChild as HTMLElement;
expect(wrapper).toHaveClass("h-full");
expect(wrapper).toHaveClass("space-y-6");
expect(wrapper).toHaveClass("p-6");
});
test("applies additional className when provided", () => {
const { container } = render(
<PageContentWrapper className="rounded-lg bg-gray-100">
<div>Test Content</div>
</PageContentWrapper>
);
const wrapper = container.firstChild as HTMLElement;
expect(wrapper).toHaveClass("h-full");
expect(wrapper).toHaveClass("space-y-6");
expect(wrapper).toHaveClass("p-6");
expect(wrapper).toHaveClass("bg-gray-100");
expect(wrapper).toHaveClass("rounded-lg");
});
});
@@ -6,5 +6,5 @@ interface PageContentWrapperProps {
}
export const PageContentWrapper = ({ children, className }: PageContentWrapperProps) => {
return <div className={cn("h-full space-y-6 p-6", className)}>{children}</div>;
return <div className={cn("min-h-full space-y-6 p-6", className)}>{children}</div>;
};