diff --git a/packages/blade/src/components/Popover/__tests__/Popover.test.stories.tsx b/packages/blade/src/components/Popover/__tests__/Popover.test.stories.tsx
new file mode 100644
index 00000000000..82af3a52cc8
--- /dev/null
+++ b/packages/blade/src/components/Popover/__tests__/Popover.test.stories.tsx
@@ -0,0 +1,271 @@
+/* eslint-disable @typescript-eslint/explicit-function-return-type */
+/* eslint-disable import/no-extraneous-dependencies */
+import type { StoryFn } from '@storybook/react';
+import { within, userEvent } from '@storybook/testing-library';
+import { expect, jest } from '@storybook/jest';
+import React from 'react';
+import type { PopoverProps, PopoverTriggerProps } from '..';
+import { PopoverInteractiveWrapper, Popover as PopoverComponent } from '..';
+import { Button } from '~components/Button';
+import { Text } from '~components/Typography';
+import { Box } from '~components/Box';
+import { Badge } from '~components/Badge';
+import BaseBox from '~components/Box/BaseBox';
+
+const onOpenChange = jest.fn();
+
+const PopoverExample = (props: PopoverProps): React.ReactElement => {
+ return (
+
+
+
+ );
+};
+
+const sleep = (ms: number): Promise => new Promise((resolve) => setTimeout(resolve, ms));
+
+export const TestPopoverOpenClose: StoryFn = (
+ props,
+): React.ReactElement => {
+ onOpenChange.mockReset();
+ return ;
+};
+
+TestPopoverOpenClose.args = {
+ title: 'Hello World',
+ content: Some text,
+};
+TestPopoverOpenClose.play = async () => {
+ const { getByRole, queryByText } = within(document.body);
+ await expect(queryByText('Hello World')).not.toBeInTheDocument();
+ const showButton = getByRole('button', { name: 'Show Popover' });
+ // open
+ await userEvent.click(showButton);
+ await sleep(400);
+ await expect(onOpenChange).toBeCalledWith({ isOpen: true });
+ await expect(queryByText('Hello World')).toBeVisible();
+ // close
+ const closeButton = getByRole('button', { name: 'Close' });
+ await expect(closeButton).toHaveFocus();
+ await userEvent.click(closeButton);
+ await sleep(400);
+ await expect(onOpenChange).toBeCalledWith({ isOpen: false });
+ await expect(queryByText('Hello World')).not.toBeInTheDocument();
+ await expect(showButton).toHaveFocus();
+ await expect(onOpenChange).toBeCalledTimes(2);
+};
+
+// Controlled
+export const TestPopoverControlled: StoryFn = (): React.ReactElement => {
+ const [isOpen, setIsOpen] = React.useState(true);
+ const toggle = () => {
+ setIsOpen((prev) => !prev);
+ };
+ return (
+
+
+ Hello World
+
+
+ }
+ isOpen={isOpen}
+ onOpenChange={({ isOpen }) => setIsOpen(isOpen)}
+ >
+
+
+
+
+ );
+};
+
+TestPopoverControlled.play = async () => {
+ const { getByRole, queryByText } = within(document.body);
+ const popoverContent = 'Hello World';
+ const toggleButton = getByRole('button', { name: 'Controlled Show', hidden: true });
+ const internalButton = getByRole('button', { name: 'Internal Click', hidden: true });
+
+ await sleep(1000);
+ // open by default
+ await expect(queryByText(popoverContent)).toBeVisible();
+ // close
+ await userEvent.click(internalButton);
+ await sleep(1000);
+ await expect(queryByText(popoverContent)).not.toBeInTheDocument();
+ // open again
+ await userEvent.click(toggleButton);
+ await sleep(400);
+ await expect(queryByText(popoverContent)).toBeVisible();
+ // close via close button
+ const closeButton = getByRole('button', { name: 'Close' });
+ await expect(closeButton).toHaveFocus();
+ await userEvent.click(closeButton);
+ await sleep(400);
+ await expect(queryByText(popoverContent)).not.toBeInTheDocument();
+ await expect(toggleButton).toHaveFocus();
+};
+
+// Uncontrolled
+export const TestPopoverUncontrolled: StoryFn = (): React.ReactElement => {
+ return (
+
+ Hello World}
+ defaultIsOpen={true}
+ onOpenChange={onOpenChange}
+ >
+
+
+
+ );
+};
+
+TestPopoverUncontrolled.play = async () => {
+ onOpenChange.mockReset();
+ const { getByRole, queryByText } = within(document.body);
+ const popoverContent = 'Hello World';
+ const toggleButton = getByRole('button', { name: 'Show Popover', hidden: true });
+
+ await expect(onOpenChange).not.toBeCalled();
+ await sleep(600);
+ // open by default
+ await expect(queryByText(popoverContent)).toBeVisible();
+ // close
+ await userEvent.click(toggleButton);
+ await sleep(400);
+ await expect(queryByText(popoverContent)).not.toBeInTheDocument();
+ await expect(onOpenChange).toBeCalledWith({ isOpen: false });
+ // open
+ await userEvent.click(toggleButton);
+ await sleep(400);
+ await expect(queryByText(popoverContent)).toBeVisible();
+ await expect(onOpenChange).toBeCalledWith({ isOpen: true });
+ await expect(onOpenChange).toBeCalledTimes(2);
+};
+
+// PopoverInteractiveWrapper
+export const TestPopoverInteractiveWrapper: StoryFn<
+ typeof PopoverComponent
+> = (): React.ReactElement => {
+ onOpenChange.mockReset();
+ return (
+ New Badge Content} onOpenChange={onOpenChange}>
+
+ NEW
+
+
+ );
+};
+
+TestPopoverInteractiveWrapper.play = async () => {
+ const { getByRole, queryByText } = within(document.body);
+ const popoverContent = 'New Badge Content';
+ await expect(queryByText(popoverContent)).not.toBeInTheDocument();
+ const badge = getByRole('button', { name: 'NEW' });
+ // open
+ await userEvent.click(badge);
+ await sleep(400);
+ await expect(onOpenChange).toBeCalledWith({ isOpen: true });
+ await expect(queryByText(popoverContent)).toBeVisible();
+ // close
+ const closeButton = getByRole('button', { name: 'Close' });
+ await expect(closeButton).toHaveFocus();
+ await userEvent.click(closeButton);
+ await sleep(400);
+ await expect(onOpenChange).toBeCalledWith({ isOpen: false });
+ await expect(queryByText(popoverContent)).not.toBeInTheDocument();
+ await expect(badge).toHaveFocus();
+ await expect(onOpenChange).toBeCalledTimes(2);
+};
+
+// Custom Trigger
+const MyCustomTriggerButton = React.forwardRef<
+ HTMLDivElement,
+ { children: string } & PopoverTriggerProps
+>(({ children, onTouchEnd, ...props }, ref) => {
+ return (
+ // just spread the props
+
+ {children}
+
+ );
+});
+
+export const TestCustomTrigger: StoryFn = (): React.ReactElement => {
+ onOpenChange.mockReset();
+ return (
+ Hello Custom Trigger} onOpenChange={onOpenChange}>
+ Show Popover
+
+ );
+};
+TestCustomTrigger.play = async () => {
+ const { getByRole, queryByText } = within(document.body);
+ const popoverContent = 'Hello Custom Trigger';
+ await expect(queryByText(popoverContent)).not.toBeInTheDocument();
+ const badge = getByRole('button', { name: 'Show Popover' });
+ // open
+ await userEvent.click(badge);
+ await sleep(400);
+ await expect(onOpenChange).toBeCalledWith({ isOpen: true });
+ await expect(queryByText(popoverContent)).toBeVisible();
+ // close
+ const closeButton = getByRole('button', { name: 'Close' });
+ await expect(closeButton).toHaveFocus();
+ await userEvent.click(closeButton);
+ await sleep(400);
+ await expect(onOpenChange).toBeCalledWith({ isOpen: false });
+ await expect(queryByText(popoverContent)).not.toBeInTheDocument();
+ await expect(badge).toHaveFocus();
+ await expect(onOpenChange).toBeCalledTimes(2);
+};
+
+export const TestInitialFocus: StoryFn = (): React.ReactElement => {
+ onOpenChange.mockReset();
+ const initialRef = React.useRef(null);
+ return (
+
+ Hello Initial Focus
+
+
+ }
+ >
+
+
+ );
+};
+TestInitialFocus.play = async () => {
+ const { getByRole, queryByText } = within(document.body);
+ const popoverContent = 'Hello Initial Focus';
+ await sleep(600);
+ await expect(queryByText(popoverContent)).toBeVisible();
+ const focusedButton = getByRole('button', { name: 'Focus on me' });
+ await expect(focusedButton).toHaveFocus();
+};
+
+export default {
+ title: 'Components/Interaction Tests/Popover',
+ component: PopoverComponent,
+ parameters: {
+ controls: {
+ disable: true,
+ },
+ a11y: { disable: true },
+ essentials: { disable: true },
+ actions: { disable: true },
+ },
+};