chore: Remove HeadSeo everywhere (#20272)
This commit is contained in:
1 parent
78ddf71823
commit
4606fc6ace
28 files changed
+20
-356
No files matched your search
@@ -1,11 +1,7 @@
|
||||
import Shell from "@calcom/features/shell/Shell";
|
||||
|
||||
const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<Shell withoutSeo={true} withoutMain={true}>
|
||||
{children}
|
||||
</Shell>
|
||||
);
|
||||
return <Shell withoutMain={true}>{children}</Shell>;
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
@@ -41,7 +41,7 @@ const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
|
||||
const Component = await routingFormsComponents[mainPage as keyof typeof routingFormsComponents]();
|
||||
const FinalComponent = () => (
|
||||
<FormProvider>
|
||||
<Component {...props as any} />
|
||||
<Component {...(props as any)} />
|
||||
</FormProvider>
|
||||
);
|
||||
|
||||
@@ -50,7 +50,7 @@ const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Shell withoutMain withoutSeo>
|
||||
<Shell withoutMain>
|
||||
<FinalComponent />
|
||||
</Shell>
|
||||
);
|
||||
|
||||
@@ -8,7 +8,7 @@ export default async function InsightsLayout({ children }: { children: React.Rea
|
||||
const t = await getTranslate();
|
||||
return (
|
||||
<div>
|
||||
<Shell withoutMain={false} withoutSeo={true} heading={t("insights")} subtitle={t("insights_subtitle")}>
|
||||
<Shell withoutMain={false} heading={t("insights")} subtitle={t("insights_subtitle")}>
|
||||
<UpgradeTipWrapper>{children}</UpgradeTipWrapper>
|
||||
</Shell>
|
||||
</div>
|
||||
|
||||
-1
@@ -740,7 +740,6 @@ export default function SettingsLayoutAppDirClient({
|
||||
|
||||
return (
|
||||
<Shell
|
||||
withoutSeo={true}
|
||||
flexChildrenContainer
|
||||
{...rest}
|
||||
SidebarContainer={
|
||||
|
||||
@@ -44,7 +44,7 @@ export default function EnterprisePage() {
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<Shell heading={t("enterprise")} subtitle={t("enterprise_description")} withoutSeo={true}>
|
||||
<Shell heading={t("enterprise")} subtitle={t("enterprise_description")}>
|
||||
<UpgradeTip
|
||||
plan="enterprise"
|
||||
title={t("create_your_org")}
|
||||
|
||||
@@ -12,7 +12,7 @@ const ShellHeading = () => {
|
||||
|
||||
export default function WrappedApp(props: AppPageProps) {
|
||||
return (
|
||||
<Shell smallHeading isPublic heading={<ShellHeading />} backPath="/apps" withoutSeo>
|
||||
<Shell smallHeading isPublic heading={<ShellHeading />} backPath="/apps">
|
||||
{props.licenseRequired ? (
|
||||
<LicenseRequired>
|
||||
<AppPage {...props} />
|
||||
|
||||
@@ -16,7 +16,6 @@ export default function Apps({ apps, category }: CategoryDataProps) {
|
||||
<>
|
||||
<Shell
|
||||
isPublic
|
||||
withoutSeo
|
||||
backPath="/apps"
|
||||
title={t("app_store")}
|
||||
description={t("app_store_description")}
|
||||
|
||||
@@ -16,7 +16,7 @@ export default function Apps({ categories }: PageProps) {
|
||||
const { t, isLocaleReady } = useLocale();
|
||||
|
||||
return (
|
||||
<Shell isPublic large title={t("app_store")} description={t("app_store_description")} withoutSeo>
|
||||
<Shell isPublic large title={t("app_store")} description={t("app_store_description")}>
|
||||
<div className="text-md flex items-center gap-1 px-4 pb-3 pt-3 font-normal md:px-8 lg:px-0 lg:pt-0">
|
||||
<Link
|
||||
href="/apps"
|
||||
|
||||
@@ -11,7 +11,6 @@ const MembersPage: React.FC = () => {
|
||||
withoutMain={false}
|
||||
title={t("organization_members")}
|
||||
description={t("organization_description")}
|
||||
withoutSeo
|
||||
subtitle={t("organization_description")}>
|
||||
<MembersView />
|
||||
</Shell>
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
export default function MorePage() {
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<Shell withoutSeo={true}>
|
||||
<Shell>
|
||||
<div className="max-w-screen-lg">
|
||||
<MobileNavigationMoreItems />
|
||||
<p className="text-subtle mt-6 text-xs leading-tight md:hidden">{t("more_page_footer")}</p>
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function PlatformBillingUpgrade() {
|
||||
if (!isPlatformUser)
|
||||
return (
|
||||
<div>
|
||||
<Shell withoutSeo={true} isPlatformUser={true} withoutMain={false} SidebarContainer={<></>}>
|
||||
<Shell isPlatformUser={true} withoutMain={false} SidebarContainer={<></>}>
|
||||
<NoPlatformPlan />
|
||||
</Shell>
|
||||
</div>
|
||||
@@ -68,7 +68,6 @@ export default function PlatformBillingUpgrade() {
|
||||
heading={t("platform_billing")}
|
||||
title={t("platform_billing")}
|
||||
withoutMain={false}
|
||||
withoutSeo={true}
|
||||
subtitle={t("manage_billing_description")}
|
||||
isPlatformUser={true}>
|
||||
<>
|
||||
|
||||
@@ -68,7 +68,7 @@ export default function EditOAuthClient() {
|
||||
if (isPlatformUser && isPaidUser) {
|
||||
return (
|
||||
<div>
|
||||
<Shell withoutSeo={true} title={t("oAuth_client_updation_form")} isPlatformUser={true}>
|
||||
<Shell title={t("oAuth_client_updation_form")} isPlatformUser={true}>
|
||||
<div className="m-2 md:mx-14 md:mx-5">
|
||||
<div className="border-subtle mx-auto block justify-between rounded-t-lg border px-4 py-6 sm:flex sm:px-6">
|
||||
<div className="flex w-full flex-col">
|
||||
@@ -116,7 +116,7 @@ export default function EditOAuthClient() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Shell withoutSeo={true} isPlatformUser={true} withoutMain={false} SidebarContainer={<></>}>
|
||||
<Shell isPlatformUser={true} withoutMain={false} SidebarContainer={<></>}>
|
||||
<NoPlatformPlan />
|
||||
</Shell>
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -42,7 +42,7 @@ export default function EditOAuthClientWebhooks() {
|
||||
if (isPlatformUser && isPaidUser) {
|
||||
return (
|
||||
<div>
|
||||
<Shell withoutSeo={true} title={t("webhook_update_form")} isPlatformUser={true}>
|
||||
<Shell title={t("webhook_update_form")} isPlatformUser={true}>
|
||||
<div className="m-2 md:mx-5">
|
||||
<div className="border-subtle mx-auto block justify-between rounded-t-lg border px-4 py-6 sm:flex sm:px-6">
|
||||
<div className="flex w-full flex-col">
|
||||
@@ -126,7 +126,7 @@ export default function EditOAuthClientWebhooks() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Shell withoutSeo={true} isPlatformUser={true} withoutMain={false} SidebarContainer={<></>}>
|
||||
<Shell isPlatformUser={true} withoutMain={false} SidebarContainer={<></>}>
|
||||
<NoPlatformPlan />
|
||||
</Shell>
|
||||
</div>
|
||||
|
||||
@@ -64,7 +64,7 @@ export default function CreateOAuthClient() {
|
||||
if (isPlatformUser && isPaidUser) {
|
||||
return (
|
||||
<div>
|
||||
<Shell title={t("oAuth_client_creation_form")} isPlatformUser={true} withoutSeo={true}>
|
||||
<Shell title={t("oAuth_client_creation_form")} isPlatformUser={true}>
|
||||
<div className="m-2 md:mx-5">
|
||||
<div className="border-subtle mx-auto block justify-between rounded-t-lg border px-4 py-6 sm:flex sm:px-6">
|
||||
<div className="flex w-full flex-col">
|
||||
@@ -85,7 +85,7 @@ export default function CreateOAuthClient() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Shell withoutSeo={true} isPlatformUser={true} withoutMain={false} SidebarContainer={<></>}>
|
||||
<Shell isPlatformUser={true} withoutMain={false} SidebarContainer={<></>}>
|
||||
<NoPlatformPlan />
|
||||
</Shell>
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,6 @@ export default function PlatformPlans() {
|
||||
<div>
|
||||
<Shell
|
||||
backPath
|
||||
withoutSeo={true}
|
||||
isPlatformUser={true}
|
||||
heading={
|
||||
<h1 className="mx-2 mt-4 text-center text-xl md:text-2xl">
|
||||
|
||||
@@ -71,7 +71,6 @@ export default function Platform() {
|
||||
subtitle={t("platform_description")}
|
||||
title={t("platform")}
|
||||
description={t("platform_description")}
|
||||
withoutSeo={true}
|
||||
withoutMain={false}
|
||||
isPlatformUser={true}>
|
||||
<HelpCards />
|
||||
@@ -89,7 +88,6 @@ export default function Platform() {
|
||||
// hence we pass isPlatformUser boolean as prop
|
||||
isPlatformUser={true}
|
||||
withoutMain={false}
|
||||
withoutSeo={true}
|
||||
SidebarContainer={<></>}>
|
||||
<NoPlatformPlan />
|
||||
</Shell>
|
||||
|
||||
@@ -151,10 +151,6 @@ vi.mock("@calcom/trpc/react", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("@calcom/ui/components/head-seo", () => ({
|
||||
HeadSeo: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@calcom/ui/styles", () => ({
|
||||
useCalcomTheme: vi.fn(),
|
||||
}));
|
||||
|
||||
@@ -30,7 +30,7 @@ export default function UpgradePage() {
|
||||
const doesUserHaveOrgToUpgrade = trpc.viewer.organizations.checkIfOrgNeedsUpgrade.useQuery();
|
||||
|
||||
return (
|
||||
<Shell withoutSeo={true}>
|
||||
<Shell >
|
||||
<div className="max-w-screen-lg">
|
||||
{doesUserHaveOrgToUpgrade.data ? (
|
||||
<EmptyScreen
|
||||
|
||||
@@ -3,7 +3,6 @@ import { describe, it, vi } from "vitest";
|
||||
|
||||
import { getOrgFullOrigin } from "@calcom/ee/organizations/lib/orgDomains";
|
||||
import { useRouterQuery } from "@calcom/lib/hooks/useRouterQuery";
|
||||
import { HeadSeo } from "@calcom/ui/components/head-seo";
|
||||
|
||||
import UserPage from "./users-public-view";
|
||||
|
||||
@@ -56,7 +55,7 @@ function mockedUserPageComponentProps(props: Partial<React.ComponentProps<typeof
|
||||
}
|
||||
|
||||
describe("UserPage Component", () => {
|
||||
it("should render HeadSeo with correct props", () => {
|
||||
it("should render with no throw", () => {
|
||||
const mockData = {
|
||||
props: mockedUserPageComponentProps({
|
||||
entity: {
|
||||
@@ -74,7 +73,6 @@ describe("UserPage Component", () => {
|
||||
uid: "uid",
|
||||
});
|
||||
|
||||
render(<UserPage {...mockData.props} />);
|
||||
expect(HeadSeo).not.toHaveBeenCalled();
|
||||
expect(() => render(<UserPage {...mockData.props} />)).not.toThrow();
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,6 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { Switch } from "@calcom/ui/components/form";
|
||||
import { HeadSeo } from "@calcom/ui/components/head-seo";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
@@ -204,7 +203,6 @@ function HitPaySetupPage(props: IHitPaySetupProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeadSeo nextSeoProps={{ noindex: true, nofollow: true }} title="HitPay" description="" />
|
||||
<div className="bg-default flex h-screen items-center justify-center">
|
||||
{showContent ? (
|
||||
<div className="flex w-full w-full max-w-[43em] flex-col items-center justify-center space-y-4 p-4 lg:space-y-5">
|
||||
|
||||
@@ -66,7 +66,7 @@ function WorkflowsPage({ filteredList }: PageProps) {
|
||||
});
|
||||
|
||||
return (
|
||||
<Shell withoutMain withoutSeo={true}>
|
||||
<Shell withoutMain>
|
||||
<LicenseRequired>
|
||||
<ShellMain
|
||||
heading={t("workflows")}
|
||||
|
||||
@@ -229,7 +229,7 @@ function WorkflowPage({
|
||||
});
|
||||
|
||||
return session.data ? (
|
||||
<Shell withoutSeo={true} withoutMain backPath="/workflows">
|
||||
<Shell withoutMain backPath="/workflows">
|
||||
<LicenseRequired>
|
||||
<Form
|
||||
form={form}
|
||||
|
||||
@@ -100,7 +100,6 @@ function EventTypeSingleLayout({
|
||||
backPath="/event-types"
|
||||
title={`${eventType.title} | ${t("event_type")}`}
|
||||
heading={eventType.title}
|
||||
withoutSeo={!isPlatform} // Metadata is handled by App Router Metadata API for Event Type Web Page
|
||||
CTA={
|
||||
<div className="flex items-center justify-end">
|
||||
{!formMethods.getValues("metadata")?.managedEventConfig && (
|
||||
|
||||
@@ -10,13 +10,11 @@ import { useRedirectToLoginIfUnauthenticated } from "@calcom/features/auth/lib/h
|
||||
import { useRedirectToOnboardingIfNeeded } from "@calcom/features/auth/lib/hooks/useRedirectToOnboardingIfNeeded";
|
||||
import { KBarContent, KBarRoot } from "@calcom/features/kbar/Kbar";
|
||||
import TimezoneChangeDialog from "@calcom/features/settings/TimezoneChangeDialog";
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
import { useFormbricks } from "@calcom/lib/formbricks-client";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { ErrorBoundary } from "@calcom/ui/components/errorBoundary";
|
||||
import { HeadSeo } from "@calcom/ui/components/head-seo";
|
||||
import { SkeletonText } from "@calcom/ui/components/skeleton";
|
||||
|
||||
import { SideBarContainer } from "./SideBar";
|
||||
@@ -30,19 +28,11 @@ const Layout = (props: LayoutProps) => {
|
||||
const { banners, bannersHeight } = useBanners();
|
||||
const pathname = usePathname();
|
||||
const isFullPageWithoutSidebar = pathname?.startsWith("/apps/routing-forms/reporting/");
|
||||
const pageTitle = typeof props.heading === "string" && !props.title ? props.heading : props.title;
|
||||
const withoutSeo = props.withoutSeo ?? props.withoutMain ?? false;
|
||||
|
||||
useFormbricks();
|
||||
|
||||
return (
|
||||
<>
|
||||
{!withoutSeo && (
|
||||
<HeadSeo
|
||||
title={pageTitle ?? APP_NAME}
|
||||
description={props.description ?? props.subtitle?.toString() ?? ""}
|
||||
/>
|
||||
)}
|
||||
<div>
|
||||
<Toaster position="bottom-right" />
|
||||
</div>
|
||||
@@ -91,8 +81,6 @@ export type LayoutProps = {
|
||||
flexChildrenContainer?: boolean;
|
||||
isPublic?: boolean;
|
||||
withoutMain?: boolean;
|
||||
// Gives you the option to skip HeadSEO and render your own.
|
||||
withoutSeo?: boolean;
|
||||
// Gives the ability to include actions to the right of the heading
|
||||
actions?: JSX.Element;
|
||||
beforeCTAactions?: JSX.Element;
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import type { NextSeoProps } from "next-seo";
|
||||
import { NextSeo } from "next-seo";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
import type { AppImageProps, MeetingImageProps } from "@calcom/lib/OgImages";
|
||||
import { constructAppImage, constructGenericImage, constructMeetingImage } from "@calcom/lib/OgImages";
|
||||
import { APP_NAME, CAL_URL } from "@calcom/lib/constants";
|
||||
import { buildCanonical, getSeoImage, seoConfig } from "@calcom/lib/next-seo.config";
|
||||
import { truncateOnWord } from "@calcom/lib/text";
|
||||
|
||||
export type HeadSeoProps = {
|
||||
title: string;
|
||||
description: string;
|
||||
siteName?: string;
|
||||
url?: string;
|
||||
canonical?: string;
|
||||
nextSeoProps?: NextSeoProps;
|
||||
app?: AppImageProps;
|
||||
meeting?: MeetingImageProps;
|
||||
isBrandingHidden?: boolean;
|
||||
origin?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Build full seo tags from title, desc, canonical and url
|
||||
*/
|
||||
const buildSeoMeta = (pageProps: {
|
||||
title: string;
|
||||
description: string;
|
||||
image: string;
|
||||
siteName?: string;
|
||||
url?: string;
|
||||
canonical?: string;
|
||||
}) => {
|
||||
const { title, description, image, canonical, siteName = seoConfig.headSeo.siteName } = pageProps;
|
||||
return {
|
||||
title: title,
|
||||
canonical: canonical,
|
||||
openGraph: {
|
||||
site_name: siteName,
|
||||
type: "website",
|
||||
title: title,
|
||||
description: description,
|
||||
images: [
|
||||
{
|
||||
url: image,
|
||||
},
|
||||
],
|
||||
},
|
||||
additionalMetaTags: [
|
||||
{
|
||||
property: "name",
|
||||
content: title,
|
||||
},
|
||||
{
|
||||
property: "description",
|
||||
content: description,
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
content: description,
|
||||
},
|
||||
{
|
||||
property: "image",
|
||||
content: image,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
export const HeadSeo = (props: HeadSeoProps): JSX.Element => {
|
||||
const path = usePathname();
|
||||
|
||||
// The below code sets the defaultUrl for our canonical tags
|
||||
// Get the router's path
|
||||
// Set the default URL to either the current URL (if self-hosted) or https://cal.com canonical URL
|
||||
const defaultUrl = buildCanonical({ path, origin: props.origin || CAL_URL });
|
||||
|
||||
const {
|
||||
title,
|
||||
description,
|
||||
siteName,
|
||||
canonical = defaultUrl,
|
||||
nextSeoProps = {},
|
||||
app,
|
||||
meeting,
|
||||
isBrandingHidden,
|
||||
} = props;
|
||||
|
||||
const image = getSeoImage("ogImage") + constructGenericImage({ title, description });
|
||||
const truncatedDescription = truncateOnWord(description, 158);
|
||||
const pageTitle = `${title}${isBrandingHidden ? "" : ` | ${APP_NAME}`}`;
|
||||
let seoObject = buildSeoMeta({
|
||||
title: pageTitle,
|
||||
image,
|
||||
description: truncatedDescription,
|
||||
canonical,
|
||||
siteName,
|
||||
});
|
||||
|
||||
if (meeting) {
|
||||
const pageImage = getSeoImage("ogImage") + constructMeetingImage(meeting);
|
||||
seoObject = buildSeoMeta({
|
||||
title: pageTitle,
|
||||
description: truncatedDescription,
|
||||
image: pageImage,
|
||||
canonical,
|
||||
siteName,
|
||||
});
|
||||
}
|
||||
|
||||
if (app) {
|
||||
const pageImage =
|
||||
getSeoImage("ogImage") + constructAppImage({ ...app, description: truncatedDescription });
|
||||
seoObject = buildSeoMeta({
|
||||
title: pageTitle,
|
||||
description: truncatedDescription,
|
||||
image: pageImage,
|
||||
canonical,
|
||||
siteName,
|
||||
});
|
||||
}
|
||||
|
||||
// Instead of doing a blackbox deep merge which can be tricky implementation wise and need a good implementation, we should generate the object manually as we know the properties
|
||||
// Goal is to avoid big dependency
|
||||
const seoProps: NextSeoProps = {
|
||||
...nextSeoProps,
|
||||
...seoObject,
|
||||
openGraph: {
|
||||
...nextSeoProps.openGraph,
|
||||
...seoObject.openGraph,
|
||||
images: [...(nextSeoProps.openGraph?.images || []), ...seoObject.openGraph.images],
|
||||
},
|
||||
additionalMetaTags: [...(nextSeoProps.additionalMetaTags || []), ...seoObject.additionalMetaTags],
|
||||
};
|
||||
|
||||
return <NextSeo {...seoProps} />;
|
||||
};
|
||||
|
||||
export default HeadSeo;
|
||||
@@ -1,160 +0,0 @@
|
||||
import { render, waitFor } from "@testing-library/react";
|
||||
import type { NextSeoProps } from "next-seo";
|
||||
import type { OpenGraph } from "next/dist/lib/metadata/types/opengraph-types";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { vi } from "vitest";
|
||||
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
|
||||
import type { HeadSeoProps } from "./HeadSeo";
|
||||
import HeadSeo from "./HeadSeo";
|
||||
|
||||
vi.mock("next/navigation", () => {
|
||||
return {
|
||||
usePathname: vi.fn(),
|
||||
};
|
||||
});
|
||||
vi.mock("@calcom/lib/constants", () => {
|
||||
return {
|
||||
SEO_IMG_DEFAULT: "",
|
||||
SEO_IMG_OGIMG: "",
|
||||
APP_NAME: "Cal.com",
|
||||
CAL_URL: "http://cal.com",
|
||||
};
|
||||
});
|
||||
vi.mock("next-seo", () => {
|
||||
return {
|
||||
NextSeo: (props: NextSeoProps) => {
|
||||
const { images, ...restOpenGraph } = props.openGraph as OpenGraph & { images: Array<{ url: string }> };
|
||||
const mockedProps = {
|
||||
...restOpenGraph,
|
||||
canonical: props.canonical,
|
||||
image: images[0].url,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any;
|
||||
return <div id="mocked-next-seo" {...mockedProps} />;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("@calcom/lib/OgImages", async () => {
|
||||
return {
|
||||
constructAppImage() {
|
||||
return "constructAppImage";
|
||||
},
|
||||
constructGenericImage() {
|
||||
return "constructGenericImage";
|
||||
},
|
||||
constructMeetingImage() {
|
||||
return "constructMeetingImage";
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const basicProps = {
|
||||
image: "image.png",
|
||||
siteName: "calcomsite",
|
||||
url: "calcom.com",
|
||||
canonical: "test canonical",
|
||||
title: "Test Title",
|
||||
description: "Test Description",
|
||||
};
|
||||
|
||||
describe("Tests for HeadSeo component", () => {
|
||||
test("Should render mocked NextSeo", async () => {
|
||||
const { container } = render(<HeadSeo {...basicProps} />);
|
||||
await waitFor(async () => {
|
||||
const mockedNextSeoEl = container.querySelector("#mocked-next-seo");
|
||||
expect(mockedNextSeoEl?.getAttribute("canonical")).toEqual(basicProps.canonical);
|
||||
expect(mockedNextSeoEl?.getAttribute("description")).toEqual(basicProps.description);
|
||||
expect(mockedNextSeoEl?.getAttribute("site_name")).toEqual(basicProps.siteName);
|
||||
expect(mockedNextSeoEl?.getAttribute("image")).toContain("constructGenericImage");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Canonical Url", () => {
|
||||
test("Should provide `canonical` prop to NextSeo derived from `origin` prop if provided", async () => {
|
||||
const props = {
|
||||
title: "Test Title",
|
||||
description: "Test Description",
|
||||
origin: "http://acme.cal.local",
|
||||
siteName: "Cal.com",
|
||||
};
|
||||
vi.mocked(usePathname).mockReturnValue("/mocked-path");
|
||||
const { container } = render(<HeadSeo {...props} />);
|
||||
await waitFor(async () => {
|
||||
const mockedNextSeoEl = container.querySelector("#mocked-next-seo");
|
||||
expect(mockedNextSeoEl?.getAttribute("canonical")).toEqual(`${props.origin}/mocked-path`);
|
||||
expect(mockedNextSeoEl?.getAttribute("description")).toEqual(props.description);
|
||||
expect(mockedNextSeoEl?.getAttribute("site_name")).toEqual(props.siteName);
|
||||
expect(mockedNextSeoEl?.getAttribute("image")).toContain("constructGenericImage");
|
||||
});
|
||||
});
|
||||
test("Should provide `canonical` prop to NextSeo derived from `CAL_URL` prop if origin not provided", async () => {
|
||||
const props = {
|
||||
title: "Test Title",
|
||||
description: "Test Description",
|
||||
siteName: "Cal.com",
|
||||
};
|
||||
vi.mocked(usePathname).mockReturnValue("/mocked-path");
|
||||
const { container } = render(<HeadSeo {...props} />);
|
||||
await waitFor(async () => {
|
||||
const mockedNextSeoEl = container.querySelector("#mocked-next-seo");
|
||||
expect(mockedNextSeoEl?.getAttribute("canonical")).toEqual(`${CAL_URL}/mocked-path`);
|
||||
expect(mockedNextSeoEl?.getAttribute("description")).toEqual(props.description);
|
||||
expect(mockedNextSeoEl?.getAttribute("site_name")).toEqual(props.siteName);
|
||||
expect(mockedNextSeoEl?.getAttribute("image")).toContain("constructGenericImage");
|
||||
});
|
||||
});
|
||||
test("Should provide `canonical` prop to NextSeo from canonical prop if provided", async () => {
|
||||
const props = {
|
||||
title: "Test Title",
|
||||
description: "Test Description",
|
||||
siteName: "Cal.com",
|
||||
origin: "http://acme.cal.local",
|
||||
canonical: "http://acme.cal.local/some-path",
|
||||
};
|
||||
vi.mocked(usePathname).mockReturnValue("/mocked-path");
|
||||
const { container } = render(<HeadSeo {...props} />);
|
||||
await waitFor(async () => {
|
||||
const mockedNextSeoEl = container.querySelector("#mocked-next-seo");
|
||||
expect(mockedNextSeoEl?.getAttribute("canonical")).toEqual(props.canonical);
|
||||
expect(mockedNextSeoEl?.getAttribute("description")).toEqual(props.description);
|
||||
expect(mockedNextSeoEl?.getAttribute("site_name")).toEqual(props.siteName);
|
||||
expect(mockedNextSeoEl?.getAttribute("image")).toContain("constructGenericImage");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("Should render title with brand", async () => {
|
||||
const { container } = render(<HeadSeo {...basicProps} />);
|
||||
await waitFor(async () => {
|
||||
const mockedNextSeoEl = container.querySelector("#mocked-next-seo");
|
||||
expect(mockedNextSeoEl?.getAttribute("title")).toEqual(`${basicProps.title} | Cal.com`);
|
||||
});
|
||||
});
|
||||
|
||||
test("Should render title without brand", async () => {
|
||||
const { container } = render(<HeadSeo {...basicProps} isBrandingHidden />);
|
||||
await waitFor(async () => {
|
||||
const mockedNextSeoEl = container.querySelector("#mocked-next-seo");
|
||||
expect(mockedNextSeoEl?.getAttribute("title")).toEqual(`${basicProps.title}`);
|
||||
});
|
||||
});
|
||||
|
||||
test("Should render with app props", async () => {
|
||||
const { container } = render(<HeadSeo {...basicProps} app={{} as HeadSeoProps["app"]} />);
|
||||
await waitFor(async () => {
|
||||
const mockedNextSeoEl = container.querySelector("#mocked-next-seo");
|
||||
expect(mockedNextSeoEl?.getAttribute("image")).toContain("constructAppImage");
|
||||
});
|
||||
});
|
||||
|
||||
test("Should render with meeting props", async () => {
|
||||
const { container } = render(<HeadSeo {...basicProps} meeting={{} as HeadSeoProps["meeting"]} />);
|
||||
await waitFor(async () => {
|
||||
const mockedNextSeoEl = container.querySelector("#mocked-next-seo");
|
||||
expect(mockedNextSeoEl?.getAttribute("image")).toContain("constructMeetingImage");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
export { HeadSeo } from "./HeadSeo";
|
||||
@@ -32,7 +32,6 @@
|
||||
"./components/errorBoundary": "./components/errorBoundary/index.ts",
|
||||
"./components/form": "./components/form/index.ts",
|
||||
"./components/form/timezone-select": "./components/form/timezone-select/index.ts",
|
||||
"./components/head-seo": "./components/head-seo/index.ts",
|
||||
"./components/hover-card": "./components/hover-card/index.tsx",
|
||||
"./components/image-uploader": "./components/image-uploader/index.ts",
|
||||
"./components/layout": "./components/layout/index.ts",
|
||||
|
||||
Reference in new issue
Block a user