Visual regression tests refined
This commit is contained in:
@@ -0,0 +1,353 @@
|
||||
import Button from "../app/components/Button.js";
|
||||
import { within, userEvent } from "@storybook/testing-library";
|
||||
|
||||
export default {
|
||||
title: "Components/Button/Visual Regression",
|
||||
component: Button,
|
||||
parameters: {
|
||||
// Chromatic configuration for visual testing
|
||||
chromatic: {
|
||||
viewports: [320, 640, 1024, 1280],
|
||||
delay: 200,
|
||||
modes: {
|
||||
light: {},
|
||||
dark: {
|
||||
colorScheme: "dark",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
size: {
|
||||
control: { type: "select" },
|
||||
options: ["xsmall", "small", "medium", "large", "xlarge"],
|
||||
},
|
||||
variant: {
|
||||
control: { type: "select" },
|
||||
options: ["default", "home"],
|
||||
},
|
||||
disabled: {
|
||||
control: { type: "boolean" },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Default button states
|
||||
export const Default = {
|
||||
args: {
|
||||
children: "Default Button",
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Default button state for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Hover = {
|
||||
args: {
|
||||
children: "Hover Button",
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Button in hover state for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const button = canvas.getByRole("button");
|
||||
await userEvent.hover(button);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
},
|
||||
};
|
||||
|
||||
export const Focus = {
|
||||
args: {
|
||||
children: "Focus Button",
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Button in focus state for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const button = canvas.getByRole("button");
|
||||
button.focus();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
},
|
||||
};
|
||||
|
||||
export const Active = {
|
||||
args: {
|
||||
children: "Active Button",
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Button in active/pressed state for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const button = canvas.getByRole("button");
|
||||
await userEvent.click(button);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
},
|
||||
};
|
||||
|
||||
export const Disabled = {
|
||||
args: {
|
||||
children: "Disabled Button",
|
||||
disabled: true,
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Disabled button state for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Size variants
|
||||
export const XSmall = {
|
||||
args: {
|
||||
children: "XSmall Button",
|
||||
size: "xsmall",
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Extra small button size for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Small = {
|
||||
args: {
|
||||
children: "Small Button",
|
||||
size: "small",
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Small button size for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Medium = {
|
||||
args: {
|
||||
children: "Medium Button",
|
||||
size: "medium",
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Medium button size for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Large = {
|
||||
args: {
|
||||
children: "Large Button",
|
||||
size: "large",
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Large button size for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const XLarge = {
|
||||
args: {
|
||||
children: "XLarge Button",
|
||||
size: "xlarge",
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Extra large button size for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Variant styles
|
||||
export const HomeVariant = {
|
||||
args: {
|
||||
children: "Home Button",
|
||||
variant: "home",
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Home variant button for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Button with icon/content
|
||||
export const WithIcon = {
|
||||
args: {
|
||||
children: (
|
||||
<>
|
||||
<span>Button with Icon</span>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
|
||||
</svg>
|
||||
</>
|
||||
),
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Button with icon for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const LongText = {
|
||||
args: {
|
||||
children:
|
||||
"This is a button with very long text content that might wrap or overflow",
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Button with long text for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Button grid for comparison
|
||||
export const SizeComparison = {
|
||||
render: () => (
|
||||
<div className="space-y-4 p-4">
|
||||
<div className="flex flex-wrap gap-4 items-center">
|
||||
<Button size="xsmall">XSmall</Button>
|
||||
<Button size="small">Small</Button>
|
||||
<Button size="medium">Medium</Button>
|
||||
<Button size="large">Large</Button>
|
||||
<Button size="xlarge">XLarge</Button>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "All button sizes for comparison and visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const StateComparison = {
|
||||
render: () => (
|
||||
<div className="space-y-4 p-4">
|
||||
<div className="flex flex-wrap gap-4 items-center">
|
||||
<Button>Default</Button>
|
||||
<Button disabled>Disabled</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-4 items-center">
|
||||
<Button variant="home">Home Default</Button>
|
||||
<Button variant="home" disabled>
|
||||
Home Disabled
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Button states for comparison and visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Interactive states
|
||||
export const InteractiveStates = {
|
||||
render: () => (
|
||||
<div className="space-y-4 p-4">
|
||||
<div className="flex flex-wrap gap-4 items-center">
|
||||
<Button id="hover-test">Hover Me</Button>
|
||||
<Button id="focus-test">Focus Me</Button>
|
||||
<Button id="click-test">Click Me</Button>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Interactive button states for visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await step("Test hover state", async () => {
|
||||
const hoverButton = canvas.getByRole("button", { name: "Hover Me" });
|
||||
await userEvent.hover(hoverButton);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
});
|
||||
|
||||
await step("Test focus state", async () => {
|
||||
const focusButton = canvas.getByRole("button", { name: "Focus Me" });
|
||||
focusButton.focus();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
});
|
||||
|
||||
await step("Test click state", async () => {
|
||||
const clickButton = canvas.getByRole("button", { name: "Click Me" });
|
||||
await userEvent.click(clickButton);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// Edge cases
|
||||
export const EdgeCases = {
|
||||
render: () => (
|
||||
<div className="space-y-4 p-4">
|
||||
<div className="flex flex-wrap gap-4 items-center">
|
||||
<Button size="xsmall">Very Small</Button>
|
||||
<Button size="xlarge">Very Large</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-4 items-center">
|
||||
<Button>Normal</Button>
|
||||
<Button disabled>Disabled</Button>
|
||||
<Button variant="home">Home</Button>
|
||||
<Button variant="home" disabled>
|
||||
Home Disabled
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: "Edge cases for button visual regression testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,335 @@
|
||||
import Footer from "../app/components/Footer.js";
|
||||
import { within, userEvent } from "@storybook/testing-library";
|
||||
|
||||
export default {
|
||||
title: "Components/Footer/Responsive",
|
||||
component: Footer,
|
||||
parameters: {
|
||||
// Chromatic configuration for responsive testing
|
||||
chromatic: {
|
||||
viewports: [320, 360, 480, 640, 768, 1024, 1280, 1440, 1920],
|
||||
// Capture screenshots at each breakpoint
|
||||
delay: 200, // Increased delay to ensure layout is stable
|
||||
// Capture both light and dark themes if available
|
||||
modes: {
|
||||
light: {},
|
||||
dark: {
|
||||
// This will be used if dark mode is implemented
|
||||
colorScheme: "dark",
|
||||
},
|
||||
},
|
||||
},
|
||||
// Storybook viewport configuration
|
||||
viewport: {
|
||||
viewports: {
|
||||
xs: {
|
||||
name: "Extra Small (xs)",
|
||||
styles: {
|
||||
width: "360px",
|
||||
height: "700px",
|
||||
},
|
||||
},
|
||||
sm: {
|
||||
name: "Small (sm)",
|
||||
styles: {
|
||||
width: "640px",
|
||||
height: "700px",
|
||||
},
|
||||
},
|
||||
md: {
|
||||
name: "Medium (md)",
|
||||
styles: {
|
||||
width: "768px",
|
||||
height: "700px",
|
||||
},
|
||||
},
|
||||
lg: {
|
||||
name: "Large (lg)",
|
||||
styles: {
|
||||
width: "1024px",
|
||||
height: "700px",
|
||||
},
|
||||
},
|
||||
xl: {
|
||||
name: "Extra Large (xl)",
|
||||
styles: {
|
||||
width: "1280px",
|
||||
height: "700px",
|
||||
},
|
||||
},
|
||||
xxl: {
|
||||
name: "2XL (xxl)",
|
||||
styles: {
|
||||
width: "1440px",
|
||||
height: "700px",
|
||||
},
|
||||
},
|
||||
full: {
|
||||
name: "Full HD (full)",
|
||||
styles: {
|
||||
width: "1920px",
|
||||
height: "700px",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Default story - will be captured at all viewports by Chromatic
|
||||
export const Default = {
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Footer component at different breakpoints. Chromatic will capture screenshots at 320px, 360px, 480px, 640px, 768px, 1024px, 1280px, 1440px, and 1920px viewport widths to test responsive behavior.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Story for each breakpoint to make testing easier
|
||||
export const ExtraSmall = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: "xs",
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Footer at extra small breakpoint (360px). Tests mobile layout and stacking behavior.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Small = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: "sm",
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Footer at small breakpoint (640px). Tests tablet layout and responsive behavior.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Medium = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: "md",
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Footer at medium breakpoint (768px). Tests small desktop layout.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Large = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: "lg",
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story: "Footer at large breakpoint (1024px). Tests desktop layout.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ExtraLarge = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: "xl",
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Footer at extra large breakpoint (1280px). Tests large desktop layout.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const TwoXL = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: "xxl",
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Footer at 2XL breakpoint (1440px). Tests very large desktop layout.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const FullHD = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: "full",
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Footer at Full HD breakpoint (1920px). Tests maximum desktop layout.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Interactive story for testing user interactions
|
||||
export const Interactive = {
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Interactive footer for testing user interactions. Check the Actions panel to see triggered events.",
|
||||
},
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await step("Click footer links", async () => {
|
||||
const useCasesLink = canvas.getByRole("link", { name: /use cases/i });
|
||||
await userEvent.click(useCasesLink);
|
||||
|
||||
const learnLink = canvas.getByRole("link", { name: /learn/i });
|
||||
await userEvent.click(learnLink);
|
||||
|
||||
const aboutLink = canvas.getByRole("link", { name: /about/i });
|
||||
await userEvent.click(aboutLink);
|
||||
|
||||
const privacyLink = canvas.getByRole("link", { name: /privacy policy/i });
|
||||
await userEvent.click(privacyLink);
|
||||
|
||||
const termsLink = canvas.getByRole("link", { name: /terms of service/i });
|
||||
await userEvent.click(termsLink);
|
||||
});
|
||||
|
||||
await step("Click social media links", async () => {
|
||||
const blueskyLink = canvas.getByRole("link", {
|
||||
name: /follow us on bluesky/i,
|
||||
});
|
||||
await userEvent.click(blueskyLink);
|
||||
|
||||
const gitlabLink = canvas.getByRole("link", {
|
||||
name: /follow us on gitlab/i,
|
||||
});
|
||||
await userEvent.click(gitlabLink);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// Story for testing hover states
|
||||
export const HoverStates = {
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Footer with hover states visible. This story captures the visual appearance when elements are hovered.",
|
||||
},
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await step("Hover over footer links", async () => {
|
||||
const useCasesLink = canvas.getByRole("link", { name: /use cases/i });
|
||||
await userEvent.hover(useCasesLink);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
const learnLink = canvas.getByRole("link", { name: /learn/i });
|
||||
await userEvent.hover(learnLink);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
const aboutLink = canvas.getByRole("link", { name: /about/i });
|
||||
await userEvent.hover(aboutLink);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
});
|
||||
|
||||
await step("Hover over social media links", async () => {
|
||||
const blueskyLink = canvas.getByRole("link", {
|
||||
name: /follow us on bluesky/i,
|
||||
});
|
||||
await userEvent.hover(blueskyLink);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
const gitlabLink = canvas.getByRole("link", {
|
||||
name: /follow us on gitlab/i,
|
||||
});
|
||||
await userEvent.hover(gitlabLink);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// Story for testing with long content above
|
||||
export const WithLongContent = {
|
||||
render: () => (
|
||||
<div className="min-h-screen bg-[var(--color-surface-default-primary)]">
|
||||
<main className="p-8">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<h1 className="text-2xl font-bold text-white mb-4">
|
||||
Footer with Long Content Above
|
||||
</h1>
|
||||
<p className="text-white mb-4">
|
||||
This story tests how the footer looks with a lot of content above
|
||||
it. This helps ensure the footer maintains its visual integrity in
|
||||
real-world scenarios.
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{Array.from({ length: 20 }, (_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="bg-[var(--color-surface-default-secondary)] p-4 rounded-lg"
|
||||
>
|
||||
<h3 className="text-white font-semibold mb-2">
|
||||
Content Block {i + 1}
|
||||
</h3>
|
||||
<p className="text-[var(--color-content-default-secondary)] text-sm">
|
||||
This is example content to show how the footer integrates with
|
||||
page content. This block contains enough text to test layout
|
||||
behavior.
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Footer with long content above to test visual integration and layout stability.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Story for testing edge cases
|
||||
export const EdgeCases = {
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: "xs",
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Footer at the smallest breakpoint to test edge case behavior and ensure no layout issues.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -7,9 +7,17 @@ export default {
|
||||
parameters: {
|
||||
// Chromatic configuration for responsive testing
|
||||
chromatic: {
|
||||
viewports: [360, 640, 768, 1024, 1280],
|
||||
viewports: [320, 360, 480, 640, 768, 1024, 1280, 1440, 1920],
|
||||
// Capture screenshots at each breakpoint
|
||||
delay: 100, // Small delay to ensure layout is stable
|
||||
delay: 200, // Increased delay to ensure layout is stable
|
||||
// Capture both light and dark themes if available
|
||||
modes: {
|
||||
light: {},
|
||||
dark: {
|
||||
// This will be used if dark mode is implemented
|
||||
colorScheme: "dark",
|
||||
},
|
||||
},
|
||||
},
|
||||
// Storybook viewport configuration
|
||||
viewport: {
|
||||
@@ -49,6 +57,20 @@ export default {
|
||||
height: "700px",
|
||||
},
|
||||
},
|
||||
xxl: {
|
||||
name: "2XL (xxl)",
|
||||
styles: {
|
||||
width: "1440px",
|
||||
height: "700px",
|
||||
},
|
||||
},
|
||||
full: {
|
||||
name: "Full HD (full)",
|
||||
styles: {
|
||||
width: "1920px",
|
||||
height: "700px",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -198,3 +220,163 @@ export const Interactive = {
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// Story for testing hover states
|
||||
export const HoverStates = {
|
||||
args: {
|
||||
onToggle: () => console.log("Navigation toggled"),
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Header with hover states visible. This story captures the visual appearance when elements are hovered.",
|
||||
},
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await step("Hover over navigation items", async () => {
|
||||
const useCasesLink = canvas.getByRole("link", { name: /use cases/i });
|
||||
await userEvent.hover(useCasesLink);
|
||||
// Wait for hover state to be visible
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
const learnLink = canvas.getByRole("link", { name: /learn/i });
|
||||
await userEvent.hover(learnLink);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
const aboutLink = canvas.getByRole("link", { name: /about/i });
|
||||
await userEvent.hover(aboutLink);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
});
|
||||
|
||||
await step("Hover over authentication elements", async () => {
|
||||
const loginLink = canvas.getByRole("link", {
|
||||
name: /log in to your account/i,
|
||||
});
|
||||
await userEvent.hover(loginLink);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
const createRuleButton = canvas.getByRole("button", {
|
||||
name: /create a new rule with avatar decoration/i,
|
||||
});
|
||||
await userEvent.hover(createRuleButton);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// Story for testing focus states
|
||||
export const FocusStates = {
|
||||
args: {
|
||||
onToggle: () => console.log("Navigation toggled"),
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Header with focus states visible. This story captures the visual appearance when elements are focused.",
|
||||
},
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await step("Focus on navigation items", async () => {
|
||||
const useCasesLink = canvas.getByRole("link", { name: /use cases/i });
|
||||
useCasesLink.focus();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
const learnLink = canvas.getByRole("link", { name: /learn/i });
|
||||
learnLink.focus();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
const aboutLink = canvas.getByRole("link", { name: /about/i });
|
||||
aboutLink.focus();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
});
|
||||
|
||||
await step("Focus on authentication elements", async () => {
|
||||
const loginLink = canvas.getByRole("link", {
|
||||
name: /log in to your account/i,
|
||||
});
|
||||
loginLink.focus();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
const createRuleButton = canvas.getByRole("button", {
|
||||
name: /create a new rule with avatar decoration/i,
|
||||
});
|
||||
createRuleButton.focus();
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// Story for testing with long content
|
||||
export const WithLongContent = {
|
||||
args: {
|
||||
onToggle: () => console.log("Navigation toggled"),
|
||||
},
|
||||
render: () => (
|
||||
<div className="min-h-screen bg-[var(--color-surface-default-primary)]">
|
||||
<Header onToggle={() => console.log("Navigation toggled")} />
|
||||
<main className="p-8">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<h1 className="text-2xl font-bold text-white mb-4">
|
||||
Header with Long Content
|
||||
</h1>
|
||||
<p className="text-white mb-4">
|
||||
This story tests how the header looks with a lot of content below
|
||||
it. This helps ensure the header maintains its visual integrity in
|
||||
real-world scenarios.
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{Array.from({ length: 12 }, (_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="bg-[var(--color-surface-default-secondary)] p-4 rounded-lg"
|
||||
>
|
||||
<h3 className="text-white font-semibold mb-2">
|
||||
Content Block {i + 1}
|
||||
</h3>
|
||||
<p className="text-[var(--color-content-default-secondary)] text-sm">
|
||||
This is example content to show how the header integrates with
|
||||
page content. This block contains enough text to test layout
|
||||
behavior.
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Header with long content below to test visual integration and layout stability.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Story for testing edge cases
|
||||
export const EdgeCases = {
|
||||
args: {
|
||||
onToggle: () => console.log("Navigation toggled"),
|
||||
},
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: "xs",
|
||||
},
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Header at the smallest breakpoint to test edge case behavior and ensure no layout issues.",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user