From abe4bff09ee889f0f316d9d83e3d474e114d2f82 Mon Sep 17 00:00:00 2001
From: adilallo <39313955+adilallo@users.noreply.github.com>
Date: Mon, 2 Feb 2026 09:24:03 -0700
Subject: [PATCH] Implement Alert and Tooltip components
---
app/components-preview/page.tsx | 184 +++++++++++++++++++
app/components/Alert/Alert.container.tsx | 124 +++++++++++++
app/components/Alert/Alert.types.ts | 26 +++
app/components/Alert/Alert.view.tsx | 86 +++++++++
app/components/Alert/index.tsx | 2 +
app/components/Tooltip/Tooltip.container.tsx | 57 ++++++
app/components/Tooltip/Tooltip.types.ts | 15 ++
app/components/Tooltip/Tooltip.view.tsx | 45 +++++
app/components/Tooltip/index.tsx | 2 +
lib/assetUtils.ts | 7 +
public/assets/Icon_Alert.svg | 3 +
public/assets/Icon_Close.svg | 8 +
public/assets/Icon_Pointer.svg | 3 +
stories/Alert.stories.js | 154 ++++++++++++++++
stories/Tooltip.stories.js | 85 +++++++++
tests/components/Alert.test.tsx | 28 +++
tests/components/Tooltip.test.tsx | 60 ++++++
17 files changed, 889 insertions(+)
create mode 100644 app/components-preview/page.tsx
create mode 100644 app/components/Alert/Alert.container.tsx
create mode 100644 app/components/Alert/Alert.types.ts
create mode 100644 app/components/Alert/Alert.view.tsx
create mode 100644 app/components/Alert/index.tsx
create mode 100644 app/components/Tooltip/Tooltip.container.tsx
create mode 100644 app/components/Tooltip/Tooltip.types.ts
create mode 100644 app/components/Tooltip/Tooltip.view.tsx
create mode 100644 app/components/Tooltip/index.tsx
create mode 100644 public/assets/Icon_Alert.svg
create mode 100644 public/assets/Icon_Close.svg
create mode 100644 public/assets/Icon_Pointer.svg
create mode 100644 stories/Alert.stories.js
create mode 100644 stories/Tooltip.stories.js
create mode 100644 tests/components/Alert.test.tsx
create mode 100644 tests/components/Tooltip.test.tsx
diff --git a/app/components-preview/page.tsx b/app/components-preview/page.tsx
new file mode 100644
index 0000000..c0d241e
--- /dev/null
+++ b/app/components-preview/page.tsx
@@ -0,0 +1,184 @@
+"use client";
+
+import { useState } from "react";
+import Tooltip from "../components/Tooltip";
+import Alert from "../components/Alert";
+import Button from "../components/Button";
+
+export default function ComponentsPreview() {
+ const [alertVisible, setAlertVisible] = useState({
+ default: true,
+ positive: true,
+ warning: true,
+ danger: true,
+ banner: true,
+ });
+
+ return (
+
+
+
+
+ {/* Tooltip Section */}
+
+
+ Tooltip Component
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Alert Section */}
+
+
+ Alert Component
+
+
+
+ {/* Toast Alerts */}
+
+
+ Toast Alerts
+
+
+ {alertVisible.default && (
+
+ setAlertVisible({ ...alertVisible, default: false })
+ }
+ />
+ )}
+
+ {alertVisible.positive && (
+
+ setAlertVisible({ ...alertVisible, positive: false })
+ }
+ />
+ )}
+
+ {alertVisible.warning && (
+
+ setAlertVisible({ ...alertVisible, warning: false })
+ }
+ />
+ )}
+
+ {alertVisible.danger && (
+
+ setAlertVisible({ ...alertVisible, danger: false })
+ }
+ />
+ )}
+
+
+ {/* Banner Alerts */}
+
+
+ Banner Alerts
+
+
+ {alertVisible.banner && (
+
+ setAlertVisible({ ...alertVisible, banner: false })
+ }
+ />
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/components/Alert/Alert.container.tsx b/app/components/Alert/Alert.container.tsx
new file mode 100644
index 0000000..b937ddf
--- /dev/null
+++ b/app/components/Alert/Alert.container.tsx
@@ -0,0 +1,124 @@
+"use client";
+
+import { memo } from "react";
+import { AlertView } from "./Alert.view";
+import type { AlertProps } from "./Alert.types";
+
+const AlertContainer = memo(
+ ({
+ title,
+ description,
+ status = "default",
+ type = "toast",
+ onClose,
+ className = "",
+ }) => {
+ // Determine background and border colors based on status and type
+ const getStatusStyles = () => {
+ switch (status) {
+ case "positive":
+ return {
+ background: "bg-[var(--color-kiwi-kiwi0)]",
+ borderColor:
+ type === "toast"
+ ? "var(--color-border-invert-positive-primary)"
+ : undefined,
+ titleColor: "text-[var(--color-content-invert-primary)]",
+ descriptionColor: "text-[var(--color-content-invert-secondary)]",
+ iconColor: "var(--color-kiwi-kiwi500)",
+ closeButtonColor: "text-[var(--color-content-invert-primary)]",
+ closeButtonIconColor: "var(--color-content-invert-primary)",
+ };
+ case "warning":
+ return {
+ background: "bg-[var(--color-yellow-yellow0)]",
+ borderColor:
+ type === "toast"
+ ? "var(--color-border-invert-warning-primary)"
+ : undefined,
+ titleColor: "text-[var(--color-content-invert-primary)]",
+ descriptionColor: "text-[var(--color-content-invert-secondary)]",
+ iconColor: "var(--color-yellow-yellow500)",
+ closeButtonColor: "text-[var(--color-content-invert-primary)]",
+ closeButtonIconColor: "var(--color-content-invert-primary)",
+ };
+ case "danger":
+ return {
+ background: "bg-[var(--color-red-red0)]",
+ borderColor:
+ type === "toast"
+ ? "var(--color-border-invert-negative-primary)"
+ : undefined,
+ titleColor: "text-[var(--color-content-invert-negative-primary)]",
+ descriptionColor: "text-[var(--color-content-invert-negative-primary)]",
+ iconColor: "var(--color-red-red500)",
+ closeButtonColor: "text-[var(--color-content-invert-negative-primary)]",
+ closeButtonIconColor: "var(--color-content-invert-primary)",
+ };
+ default:
+ return {
+ background: "bg-[var(--color-surface-default-tertiary)]",
+ borderColor:
+ type === "toast"
+ ? "var(--color-border-default-primary)"
+ : undefined,
+ titleColor: "text-[var(--color-content-default-primary)]",
+ descriptionColor: "text-[var(--color-content-default-primary)]",
+ iconColor: "var(--color-content-default-brand-primary)",
+ closeButtonColor: "text-[var(--color-content-default-primary)]",
+ closeButtonIconColor: "var(--color-content-default-brand-primary)",
+ };
+ }
+ };
+
+ const statusStyles = getStatusStyles();
+
+ const containerClasses = `flex gap-[var(--space-300)] items-center ${
+ type === "toast"
+ ? `pb-[var(--space-500)] pt-[var(--space-400)] px-[var(--space-1200)] rounded-tl-[var(--radius-200,8px)] rounded-tr-[var(--radius-200,8px)]`
+ : `px-[var(--spacing-scale-024)] py-[var(--spacing-scale-016)] rounded-[var(--radius-200,8px)]`
+ } ${statusStyles.background} border-solid`;
+
+ const containerStyle =
+ type === "toast" && statusStyles.borderColor
+ ? {
+ borderBottomWidth: "var(--border-large)",
+ borderBottomColor: statusStyles.borderColor,
+ }
+ : undefined;
+
+ const titleClasses =
+ type === "banner"
+ ? `font-inter text-[16px] leading-[20px] font-medium tracking-[0%] ${statusStyles.titleColor} relative shrink-0 w-full`
+ : `font-inter text-[18px] leading-[24px] font-medium tracking-[0%] ${statusStyles.titleColor} relative shrink-0 w-full`;
+
+ const descriptionClasses =
+ type === "banner"
+ ? `font-inter text-[16px] leading-[24px] font-normal tracking-[0%] ${statusStyles.descriptionColor} relative shrink-0 w-full mt-[var(--spacing-scale-004)]`
+ : `font-inter text-[18px] leading-[23.4px] font-normal tracking-[0%] ${statusStyles.descriptionColor} relative shrink-0 w-full mt-[var(--spacing-scale-004)]`;
+
+ const closeButtonClasses = `flex gap-[var(--spacing-scale-006)] items-center justify-center overflow-clip p-[var(--spacing-scale-012)] rounded-[var(--radius-full)] shrink-0 hover:bg-[var(--color-surface-default-secondary)] transition-colors ${statusStyles.closeButtonColor}`;
+
+ return (
+
+ );
+ },
+);
+
+AlertContainer.displayName = "Alert";
+
+export default AlertContainer;
diff --git a/app/components/Alert/Alert.types.ts b/app/components/Alert/Alert.types.ts
new file mode 100644
index 0000000..1515d5f
--- /dev/null
+++ b/app/components/Alert/Alert.types.ts
@@ -0,0 +1,26 @@
+import type { ReactNode } from "react";
+
+export interface AlertProps {
+ title: string;
+ description?: string;
+ status?: "default" | "positive" | "warning" | "danger";
+ type?: "toast" | "banner";
+ onClose?: () => void;
+ className?: string;
+}
+
+export interface AlertViewProps {
+ title: string;
+ description?: string;
+ status: "default" | "positive" | "warning" | "danger";
+ type: "toast" | "banner";
+ className: string;
+ containerClasses: string;
+ containerStyle?: React.CSSProperties;
+ titleClasses: string;
+ descriptionClasses: string;
+ iconColor: string;
+ closeButtonClasses: string;
+ closeButtonIconColor: string;
+ onClose?: () => void;
+}
diff --git a/app/components/Alert/Alert.view.tsx b/app/components/Alert/Alert.view.tsx
new file mode 100644
index 0000000..2a49bbb
--- /dev/null
+++ b/app/components/Alert/Alert.view.tsx
@@ -0,0 +1,86 @@
+import { getAssetPath, ASSETS } from "../../lib/assetUtils";
+import type { AlertViewProps } from "./Alert.types";
+
+export function AlertView({
+ title,
+ description,
+ status,
+ type,
+ className,
+ containerClasses,
+ containerStyle,
+ titleClasses,
+ descriptionClasses,
+ iconColor,
+ closeButtonClasses,
+ closeButtonIconColor,
+ onClose,
+}: AlertViewProps) {
+ const getIcon = () => {
+ // Use the Icon_Alert.svg with dynamic fill color
+ // The SVG has a fill that we'll override with the iconColor
+ // Icon is 19x19px with 2.5px spacing in a 24x24px bounding box
+ return (
+
+ );
+ };
+
+ return (
+
+
+ {getIcon()}
+
+
+
{title}
+ {description &&
{description}
}
+
+
+
+ );
+}
diff --git a/app/components/Alert/index.tsx b/app/components/Alert/index.tsx
new file mode 100644
index 0000000..9f65e51
--- /dev/null
+++ b/app/components/Alert/index.tsx
@@ -0,0 +1,2 @@
+export { default } from "./Alert.container";
+export type { AlertProps } from "./Alert.types";
diff --git a/app/components/Tooltip/Tooltip.container.tsx b/app/components/Tooltip/Tooltip.container.tsx
new file mode 100644
index 0000000..b58d37b
--- /dev/null
+++ b/app/components/Tooltip/Tooltip.container.tsx
@@ -0,0 +1,57 @@
+"use client";
+
+import { memo, useState } from "react";
+import { TooltipView } from "./Tooltip.view";
+import type { TooltipProps } from "./Tooltip.types";
+
+const TooltipContainer = memo(
+ ({
+ children,
+ text,
+ position = "top",
+ className = "",
+ disabled = false,
+ }) => {
+ const [isVisible, setIsVisible] = useState(false);
+
+ if (disabled) {
+ return <>{children}>;
+ }
+
+ const tooltipClasses = `absolute z-50 bg-[var(--color-surface-default-primary)] px-[var(--space-300)] py-[var(--space-200)] rounded-[var(--radius-300,12px)] shadow-[0px_0px_48px_0px_rgba(0,0,0,0.1)] flex items-center whitespace-nowrap ${
+ position === "top" ? "bottom-full mb-[7px]" : "top-full mt-[7px]"
+ } left-1/2 -translate-x-1/2 ${isVisible ? "opacity-100 visible" : "opacity-0 invisible pointer-events-none"} transition-all duration-200`;
+
+ // Pointer positioning: 10px tall, 7px sticks out, 3px inside tooltip
+ // For bottom tooltip: pointer at top, pointing up, 7px above tooltip
+ // For top tooltip: pointer at bottom, pointing down, 7px below tooltip
+ const pointerClasses = `absolute ${
+ position === "top" ? "bottom-[-7px]" : "top-[-7px]"
+ } left-1/2 -translate-x-1/2`;
+
+ const tooltipId = `tooltip-${text.replace(/\s+/g, "-").toLowerCase()}`;
+
+ return (
+ setIsVisible(true)}
+ onMouseLeave={() => setIsVisible(false)}
+ onFocus={() => setIsVisible(true)}
+ onBlur={() => setIsVisible(false)}
+ >
+ {children}
+
+
+ );
+ },
+);
+
+TooltipContainer.displayName = "Tooltip";
+
+export default TooltipContainer;
diff --git a/app/components/Tooltip/Tooltip.types.ts b/app/components/Tooltip/Tooltip.types.ts
new file mode 100644
index 0000000..b746924
--- /dev/null
+++ b/app/components/Tooltip/Tooltip.types.ts
@@ -0,0 +1,15 @@
+export interface TooltipProps {
+ children: React.ReactNode;
+ text: string;
+ position?: "top" | "bottom";
+ className?: string;
+ disabled?: boolean;
+}
+
+export interface TooltipViewProps {
+ text: string;
+ position: "top" | "bottom";
+ className: string;
+ tooltipClasses: string;
+ pointerClasses: string;
+}
diff --git a/app/components/Tooltip/Tooltip.view.tsx b/app/components/Tooltip/Tooltip.view.tsx
new file mode 100644
index 0000000..e5e13fd
--- /dev/null
+++ b/app/components/Tooltip/Tooltip.view.tsx
@@ -0,0 +1,45 @@
+import type { TooltipViewProps } from "./Tooltip.types";
+
+export function TooltipView({
+ text,
+ position,
+ className,
+ tooltipClasses,
+ pointerClasses,
+}: TooltipViewProps) {
+ // Pointer is 10px tall with 7px sticking out
+ // Icon_Pointer.svg is 14x8, scale to 10px height = 17.5px width
+ const pointerWidth = 17.5;
+ const pointerHeight = 10;
+ const pointerRotation = position === "top" ? "rotate-180" : "rotate-0";
+
+ return (
+
+ );
+}
diff --git a/app/components/Tooltip/index.tsx b/app/components/Tooltip/index.tsx
new file mode 100644
index 0000000..e85f0ee
--- /dev/null
+++ b/app/components/Tooltip/index.tsx
@@ -0,0 +1,2 @@
+export { default } from "./Tooltip.container";
+export type { TooltipProps } from "./Tooltip.types";
diff --git a/lib/assetUtils.ts b/lib/assetUtils.ts
index 074c9dd..95087b1 100644
--- a/lib/assetUtils.ts
+++ b/lib/assetUtils.ts
@@ -55,4 +55,11 @@ export const ASSETS = {
// Content page decorative shapes
CONTENT_SHAPE_1: "assets/Content_Shape_1.svg",
CONTENT_SHAPE_2: "assets/Content_Shape_2.svg",
+
+ // Alert icons
+ ICON_ALERT: "assets/Icon_Alert.svg",
+ ICON_CLOSE: "assets/Icon_Close.svg",
+
+ // Tooltip icons
+ ICON_POINTER: "assets/Icon_Pointer.svg",
} as const;
diff --git a/public/assets/Icon_Alert.svg b/public/assets/Icon_Alert.svg
new file mode 100644
index 0000000..a69b14d
--- /dev/null
+++ b/public/assets/Icon_Alert.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/assets/Icon_Close.svg b/public/assets/Icon_Close.svg
new file mode 100644
index 0000000..040915a
--- /dev/null
+++ b/public/assets/Icon_Close.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/assets/Icon_Pointer.svg b/public/assets/Icon_Pointer.svg
new file mode 100644
index 0000000..507656b
--- /dev/null
+++ b/public/assets/Icon_Pointer.svg
@@ -0,0 +1,3 @@
+
diff --git a/stories/Alert.stories.js b/stories/Alert.stories.js
new file mode 100644
index 0000000..1e91c44
--- /dev/null
+++ b/stories/Alert.stories.js
@@ -0,0 +1,154 @@
+import React, { useState } from "react";
+import Alert from "../app/components/Alert";
+
+export default {
+ title: "Components/Alert",
+ component: Alert,
+ argTypes: {
+ status: {
+ control: { type: "select" },
+ options: ["default", "positive", "warning", "danger"],
+ },
+ type: {
+ control: { type: "select" },
+ options: ["toast", "banner"],
+ },
+ title: {
+ control: { type: "text" },
+ },
+ description: {
+ control: { type: "text" },
+ },
+ },
+};
+
+const Template = (args) => {
+ const [isVisible, setIsVisible] = useState(true);
+ if (!isVisible) return Alert closed
;
+ return (
+
+
setIsVisible(false)} />
+
+ );
+};
+
+export const Default = Template.bind({});
+Default.args = {
+ title: "Short alert banner message goes here",
+ description: "Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
+ status: "default",
+ type: "toast",
+};
+
+export const Positive = Template.bind({});
+Positive.args = {
+ title: "Short alert banner message goes here",
+ description: "Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
+ status: "positive",
+ type: "toast",
+};
+
+export const Warning = Template.bind({});
+Warning.args = {
+ title: "Short alert banner message goes here",
+ description: "Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
+ status: "warning",
+ type: "toast",
+};
+
+export const Danger = Template.bind({});
+Danger.args = {
+ title: "Short alert banner message goes here",
+ description: "Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
+ status: "danger",
+ type: "toast",
+};
+
+export const Banner = Template.bind({});
+Banner.args = {
+ title: "Short alert banner message goes here",
+ description: "Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
+ status: "default",
+ type: "banner",
+};
+
+export const BannerPositive = Template.bind({});
+BannerPositive.args = {
+ title: "Short alert banner message goes here",
+ description: "Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
+ status: "positive",
+ type: "banner",
+};
+
+export const BannerWarning = Template.bind({});
+BannerWarning.args = {
+ title: "Short alert banner message goes here",
+ description: "Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
+ status: "warning",
+ type: "banner",
+};
+
+export const BannerDanger = Template.bind({});
+BannerDanger.args = {
+ title: "Short alert banner message goes here",
+ description: "Nascetur ipsum a nisi tempor cras nam neque volutpat. Aliquam id est faucibus nunc quis. Eleifend suspendisse.",
+ status: "danger",
+ type: "banner",
+};
+
+export const TitleOnly = Template.bind({});
+TitleOnly.args = {
+ title: "Short alert banner message goes here",
+ status: "default",
+ type: "toast",
+};
+
+export const AllStatuses = () => {
+ const [visible, setVisible] = useState({
+ default: true,
+ positive: true,
+ warning: true,
+ danger: true,
+ });
+
+ return (
+
+ {visible.default && (
+
setVisible({ ...visible, default: false })}
+ />
+ )}
+ {visible.positive && (
+ setVisible({ ...visible, positive: false })}
+ />
+ )}
+ {visible.warning && (
+ setVisible({ ...visible, warning: false })}
+ />
+ )}
+ {visible.danger && (
+ setVisible({ ...visible, danger: false })}
+ />
+ )}
+
+ );
+};
diff --git a/stories/Tooltip.stories.js b/stories/Tooltip.stories.js
new file mode 100644
index 0000000..5fa8261
--- /dev/null
+++ b/stories/Tooltip.stories.js
@@ -0,0 +1,85 @@
+import React from "react";
+import Tooltip from "../app/components/Tooltip";
+import Button from "../app/components/Button";
+
+export default {
+ title: "Components/Tooltip",
+ component: Tooltip,
+ argTypes: {
+ position: {
+ control: { type: "select" },
+ options: ["top", "bottom"],
+ },
+ disabled: {
+ control: { type: "boolean" },
+ },
+ text: {
+ control: { type: "text" },
+ },
+ },
+};
+
+const Template = (args) => (
+
+
+
+
+
+);
+
+export const Default = Template.bind({});
+Default.args = {
+ text: "Tooltip text goes here",
+ position: "top",
+ disabled: false,
+};
+
+export const Top = Template.bind({});
+Top.args = {
+ text: "Tooltip positioned at top",
+ position: "top",
+};
+
+export const Bottom = Template.bind({});
+Bottom.args = {
+ text: "Tooltip positioned at bottom",
+ position: "bottom",
+};
+
+export const Disabled = Template.bind({});
+Disabled.args = {
+ text: "This tooltip is disabled",
+ disabled: true,
+};
+
+export const LongText = Template.bind({});
+LongText.args = {
+ text: "This is a longer tooltip text that demonstrates how the component handles multiple words and extended content",
+ position: "top",
+};
+
+export const WithIcon = () => (
+
+);
diff --git a/tests/components/Alert.test.tsx b/tests/components/Alert.test.tsx
new file mode 100644
index 0000000..c9f78b3
--- /dev/null
+++ b/tests/components/Alert.test.tsx
@@ -0,0 +1,28 @@
+import React from "react";
+import Alert from "../../app/components/Alert";
+import { componentTestSuite } from "../utils/componentTestSuite";
+
+type AlertProps = React.ComponentProps;
+
+componentTestSuite({
+ component: Alert,
+ name: "Alert",
+ props: {
+ title: "Alert title",
+ description: "Alert description",
+ } as AlertProps,
+ requiredProps: ["title"],
+ optionalProps: {
+ description: "Optional description",
+ status: "positive",
+ type: "banner",
+ },
+ primaryRole: "alert",
+ testCases: {
+ renders: true,
+ accessibility: true,
+ keyboardNavigation: false, // Alert is not directly keyboard navigable
+ disabledState: false,
+ errorState: false,
+ },
+});
diff --git a/tests/components/Tooltip.test.tsx b/tests/components/Tooltip.test.tsx
new file mode 100644
index 0000000..76b0c29
--- /dev/null
+++ b/tests/components/Tooltip.test.tsx
@@ -0,0 +1,60 @@
+import React from "react";
+import { describe, it, expect } from "vitest";
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import "@testing-library/jest-dom/vitest";
+import Tooltip from "../../app/components/Tooltip";
+import { componentTestSuite } from "../utils/componentTestSuite";
+
+type TooltipProps = React.ComponentProps;
+
+componentTestSuite({
+ component: Tooltip,
+ name: "Tooltip",
+ props: {
+ children: ,
+ text: "Tooltip text",
+ } as TooltipProps,
+ requiredProps: ["children", "text"],
+ optionalProps: {
+ position: "bottom",
+ disabled: true,
+ },
+ primaryRole: "button",
+ testCases: {
+ renders: true,
+ accessibility: true,
+ keyboardNavigation: true,
+ disabledState: false, // Tooltip disabled state is handled in behavioral tests
+ errorState: false,
+ },
+});
+
+describe("Tooltip (behavioral tests)", () => {
+ it("shows tooltip on hover", async () => {
+ const user = userEvent.setup();
+ render(
+
+
+ ,
+ );
+
+ const button = screen.getByRole("button", { name: "Hover me" });
+ await user.hover(button);
+
+ const tooltip = screen.getByRole("tooltip");
+ expect(tooltip).toBeInTheDocument();
+ expect(tooltip).toHaveTextContent("Tooltip text");
+ });
+
+ it("hides tooltip when disabled", () => {
+ render(
+
+
+ ,
+ );
+
+ const tooltip = screen.queryByRole("tooltip");
+ expect(tooltip).not.toBeInTheDocument();
+ });
+});