/* eslint-disable playwright/missing-playwright-await */ import { render, screen, fireEvent } from "@testing-library/react"; import { useState } from "react"; import { vi } from "vitest"; import { Plus } from "@calcom/ui/components/icon"; import { Button, buttonClasses } from "./Button"; const observeMock = vi.fn(); window.ResizeObserver = vi.fn().mockImplementation(() => ({ disconnect: vi.fn(), observe: observeMock, unobserve: vi.fn(), })); vi.mock("../tooltip", async () => { const actual = (await vi.importActual("../tooltip")) as any; const TooltipMock = (props: object) => { const [open, setOpen] = useState(false); return ( { setOpen(isOpen); }} /> ); }; return { Tooltip: TooltipMock, }; }); describe("Tests for Button component", () => { test("Should apply the icon variant class", () => { render(); const buttonClass = screen.getByText("Test Button"); const buttonComponentClass = buttonClasses({ variant: "icon" }); const buttonClassArray = buttonClass.className.split(" "); const hasMatchingClassNames = buttonComponentClass .split(" ") .some((className) => buttonClassArray.includes(className)); expect(hasMatchingClassNames).toBe(true); }); test("Should apply the fab variant class", () => { render(); expect(screen.getByText("Test Button")).toHaveClass("hidden md:inline"); }); test("Should apply the secondary color class", () => { render(); const buttonClass = screen.getByText("Test Button"); const buttonComponentClass = buttonClasses({ color: "secondary" }); const buttonClassArray = buttonClass.className.split(" "); const hasMatchingClassNames = buttonComponentClass .split(" ") .some((className) => buttonClassArray.includes(className)); expect(hasMatchingClassNames).toBe(true); }); test("Should apply the minimal color class", () => { render(); const buttonClass = screen.getByText("Test Button"); const buttonComponentClass = buttonClasses({ color: "minimal" }); const buttonClassArray = buttonClass.className.split(" "); const hasMatchingClassNames = buttonComponentClass .split(" ") .some((className) => buttonClassArray.includes(className)); expect(hasMatchingClassNames).toBe(true); }); test("Should apply the sm size class", () => { render(); const buttonClass = screen.getByText("Test Button"); const buttonComponentClass = buttonClasses({ size: "sm" }); const buttonClassArray = buttonClass.className.split(" "); const hasMatchingClassNames = buttonComponentClass .split(" ") .some((className) => buttonClassArray.includes(className)); expect(hasMatchingClassNames).toBe(true); }); test("Should apply the base size class", () => { render(); const buttonClass = screen.getByText("Test Button"); const buttonComponentClass = buttonClasses({ size: "base" }); const buttonClassArray = buttonClass.className.split(" "); const hasMatchingClassNames = buttonComponentClass .split(" ") .some((className) => buttonClassArray.includes(className)); expect(hasMatchingClassNames).toBe(true); }); test("Should apply the lg size class", () => { render(); const buttonClass = screen.getByText("Test Button"); const buttonComponentClass = buttonClasses({ size: "lg" }); const buttonClassArray = buttonClass.className.split(" "); const hasMatchingClassNames = buttonComponentClass .split(" ") .some((className) => buttonClassArray.includes(className)); expect(hasMatchingClassNames).toBe(true); }); test("Should apply the loading class", () => { render(); const buttonClass = screen.getByText("Test Button"); const buttonComponentClass = buttonClasses({ loading: true }); const buttonClassArray = buttonClass.className.split(" "); const hasMatchingClassNames = buttonComponentClass .split(" ") .some((className) => buttonClassArray.includes(className)); expect(hasMatchingClassNames).toBe(true); }); test("Should apply the disabled class when disabled prop is true", () => { render(); const buttonClass = screen.getByText("Test Button").className; const expectedClassName = "disabled:cursor-not-allowed"; expect(buttonClass.includes(expectedClassName)).toBe(true); }); test("Should apply the custom class", () => { const className = "custom-class"; render(); expect(screen.getByText("Test Button")).toHaveClass(className); }); test("Should render as a button by default", () => { render(); const button = screen.getByText("Test Button"); expect(button.tagName).toBe("BUTTON"); }); test("Should render StartIcon and Plus icon if is fab variant", () => { render( ); expect(screen.getByTestId("start-icon")).toBeInTheDocument(); expect(screen.getByTestId("plus")).toBeInTheDocument(); }); test("Should render just StartIcon if is not fab variant", () => { render( ); expect(screen.getByTestId("start-icon")).toBeInTheDocument(); expect(screen.queryByTestId("plus")).not.toBeInTheDocument(); }); test("Should render EndIcon and Plus icon if is fab variant", () => { render( ); expect(screen.getByTestId("end-icon")).toBeInTheDocument(); expect(screen.getByTestId("plus")).toBeInTheDocument(); }); test("Should render just EndIcon if is not fab variant", () => { render( ); expect(screen.getByTestId("end-icon")).toBeInTheDocument(); expect(screen.queryByTestId("plus")).not.toBeInTheDocument(); }); test("Should render Link if have href", () => { render(); const buttonElement = screen.getByText("Test Button"); expect(buttonElement).toHaveAttribute("href", "/test"); expect(buttonElement.closest("a")).toBeInTheDocument(); test("Should render Wrapper if don't have href", () => { render(); expect(screen.queryByTestId("link-component")).not.toBeInTheDocument(); expect(screen.getByText("Test Button")).toBeInTheDocument(); }); test("Should render Tooltip if exists", () => { render(); const tooltip = screen.getByTestId("tooltip"); expect(tooltip.getAttribute("data-state")).toEqual("closed"); expect(tooltip.getAttribute("data-state")).toEqual("instant-open"); expect(observeMock).toBeCalledWith(tooltip); }); test("Should not render Tooltip if no exists", () => { render(); expect(screen.queryByTestId("tooltip")).not.toBeInTheDocument(); expect(screen.getByText("Test Button")).toBeInTheDocument(); }); test("Should render as a button with a custom type", () => { render(); const button = screen.getByText("Test Button"); expect(button.tagName).toBe("BUTTON"); expect(button).toHaveAttribute("type", "submit"); }); test("Should render as an anchor when href prop is provided", () => { render(); const button = screen.getByText("Test Button"); expect(button.tagName).toBe("A"); expect(button).toHaveAttribute("href", "/path"); }); test("Should call onClick callback when clicked", () => { const handleClick = vi.fn(); render(); const button = screen.getByText("Test Button"); fireEvent.click(button); expect(handleClick).toHaveBeenCalledTimes(1); }); test("Should render default button correctly", () => { render(); const buttonClass = screen.getByText("Default Button").className; const buttonComponentClass = buttonClasses({ variant: "button", color: "primary", size: "base" }); const buttonClassArray = buttonClass.split(" "); const hasMatchingClassNames = buttonComponentClass .split(" ") .every((className) => buttonClassArray.includes(className)); expect(hasMatchingClassNames).toBe(true); expect(screen.getByText("Default Button")).toHaveAttribute("type", "button"); }); test("Should pass the shallow prop to Link component when href prop is passed", () => { const href = "https://example.com"; render(