feat: Add data-testid and id attributes to app header components for testing (#5724)
* 📝 (AccountMenu/index.tsx): Add span elements with data-testid and id attributes for menu buttons for better testing and accessibility 📝 (FlowMenu/index.tsx): Add data-testid and id attributes to div elements for menu buttons for better testing and accessibility 📝 (HeaderMenu/index.tsx): Add data-testid and id attributes to DropdownMenuTrigger for user menu button for better testing and accessibility 📝 (ThemeButtons/index.tsx): Add data-testid and id attributes to Button elements for theme change buttons for better testing and accessibility 📝 (flowToolbarComponent/index.tsx): Add data-testid and id attributes to div element for API button modal for better testing and accessibility * ✨ (FlowMenu/index.tsx): add data-testid attributes to elements for easier testing and debugging ✨ (AppHeaderComponent/index.tsx): add data-testid attributes to header sections for easier testing and debugging
This commit is contained in:
parent
e8dd2d4c18
commit
d428fb6cb5
6 changed files with 103 additions and 18 deletions
|
|
@ -57,7 +57,12 @@ export const AccountMenu = () => {
|
||||||
<HeaderMenuItemsSection>
|
<HeaderMenuItemsSection>
|
||||||
<div className="flex h-[46px] w-full items-center justify-between px-3">
|
<div className="flex h-[46px] w-full items-center justify-between px-3">
|
||||||
<div className="pl-1 text-xs text-zinc-500">
|
<div className="pl-1 text-xs text-zinc-500">
|
||||||
Version {version}
|
<span
|
||||||
|
data-testid="menu_version_button"
|
||||||
|
id="menu_version_button"
|
||||||
|
>
|
||||||
|
Version {version}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{!ENABLE_DATASTAX_LANGFLOW && <ThemeButtons />}
|
{!ENABLE_DATASTAX_LANGFLOW && <ThemeButtons />}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -72,25 +77,42 @@ export const AccountMenu = () => {
|
||||||
navigate("/settings");
|
navigate("/settings");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Settings
|
<span
|
||||||
|
data-testid="menu_settings_button"
|
||||||
|
id="menu_settings_button"
|
||||||
|
>
|
||||||
|
Settings
|
||||||
|
</span>
|
||||||
</HeaderMenuItemButton>
|
</HeaderMenuItemButton>
|
||||||
)}
|
)}
|
||||||
{!ENABLE_DATASTAX_LANGFLOW && (
|
{!ENABLE_DATASTAX_LANGFLOW && (
|
||||||
<>
|
<>
|
||||||
{isAdmin && !autoLogin && (
|
{isAdmin && !autoLogin && (
|
||||||
<HeaderMenuItemButton onClick={() => navigate("/admin")}>
|
<HeaderMenuItemButton onClick={() => navigate("/admin")}>
|
||||||
Admin Page
|
<span
|
||||||
|
data-testid="menu_admin_button"
|
||||||
|
id="menu_admin_button"
|
||||||
|
>
|
||||||
|
Admin Page
|
||||||
|
</span>
|
||||||
</HeaderMenuItemButton>
|
</HeaderMenuItemButton>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{ENABLE_DATASTAX_LANGFLOW ? (
|
{ENABLE_DATASTAX_LANGFLOW ? (
|
||||||
<HeaderMenuItemButton onClick={() => setIsFeedbackOpen(true)}>
|
<HeaderMenuItemButton onClick={() => setIsFeedbackOpen(true)}>
|
||||||
Feedback
|
<span
|
||||||
|
data-testid="menu_feedback_button"
|
||||||
|
id="menu_feedback_button"
|
||||||
|
>
|
||||||
|
Feedback
|
||||||
|
</span>
|
||||||
</HeaderMenuItemButton>
|
</HeaderMenuItemButton>
|
||||||
) : (
|
) : (
|
||||||
<HeaderMenuItemLink newPage href="https://docs.langflow.org">
|
<HeaderMenuItemLink newPage href="https://docs.langflow.org">
|
||||||
Docs
|
<span data-testid="menu_docs_button" id="menu_docs_button">
|
||||||
|
Docs
|
||||||
|
</span>
|
||||||
</HeaderMenuItemLink>
|
</HeaderMenuItemLink>
|
||||||
)}
|
)}
|
||||||
</HeaderMenuItemsSection>
|
</HeaderMenuItemsSection>
|
||||||
|
|
@ -110,14 +132,20 @@ export const AccountMenu = () => {
|
||||||
newPage
|
newPage
|
||||||
href="https://github.com/langflow-ai/langflow/discussions"
|
href="https://github.com/langflow-ai/langflow/discussions"
|
||||||
>
|
>
|
||||||
Share Feedback on Github
|
<span data-testid="menu_github_button" id="menu_github_button">
|
||||||
|
Share Feedback on Github
|
||||||
|
</span>
|
||||||
</HeaderMenuItemLink>
|
</HeaderMenuItemLink>
|
||||||
)}
|
)}
|
||||||
<HeaderMenuItemLink newPage href="https://twitter.com/langflow_ai">
|
<HeaderMenuItemLink newPage href="https://twitter.com/langflow_ai">
|
||||||
Follow Langflow on X
|
<span data-testid="menu_twitter_button" id="menu_twitter_button">
|
||||||
|
Follow Langflow on X
|
||||||
|
</span>
|
||||||
</HeaderMenuItemLink>
|
</HeaderMenuItemLink>
|
||||||
<HeaderMenuItemLink newPage href="https://discord.gg/EqksyE2EX9">
|
<HeaderMenuItemLink newPage href="https://discord.gg/EqksyE2EX9">
|
||||||
Join the Langflow Discord
|
<span data-testid="menu_discord_button" id="menu_discord_button">
|
||||||
|
Join the Langflow Discord
|
||||||
|
</span>
|
||||||
</HeaderMenuItemLink>
|
</HeaderMenuItemLink>
|
||||||
</HeaderMenuItemsSection>
|
</HeaderMenuItemsSection>
|
||||||
{ENABLE_DATASTAX_LANGFLOW ? (
|
{ENABLE_DATASTAX_LANGFLOW ? (
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,11 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
}
|
}
|
||||||
// return savedText;
|
// return savedText;
|
||||||
return (
|
return (
|
||||||
<div className="shrink-0 text-xs font-medium text-accent-emerald-foreground">
|
<div
|
||||||
|
data-testid="menu_status_saved_flow_button"
|
||||||
|
id="menu_status_saved_flow_button"
|
||||||
|
className="shrink-0 text-xs font-medium text-accent-emerald-foreground"
|
||||||
|
>
|
||||||
Saved
|
Saved
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -213,8 +217,15 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return currentFlow && onFlowPage ? (
|
return currentFlow && onFlowPage ? (
|
||||||
<div className="flex items-center justify-center gap-2 truncate">
|
<div
|
||||||
<div className="header-menu-bar hidden w-20 max-w-fit grow justify-end truncate md:flex">
|
className="flex items-center justify-center gap-2 truncate"
|
||||||
|
data-testid="menu_bar_wrapper"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="header-menu-bar hidden w-20 max-w-fit grow justify-end truncate md:flex"
|
||||||
|
data-testid="menu_flow_bar"
|
||||||
|
id="menu_flow_bar_navigation"
|
||||||
|
>
|
||||||
{currentFolder?.name && (
|
{currentFolder?.name && (
|
||||||
<div className="hidden truncate md:flex">
|
<div className="hidden truncate md:flex">
|
||||||
<div
|
<div
|
||||||
|
|
@ -232,12 +243,21 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="hidden w-fit shrink-0 select-none font-normal text-muted-foreground md:flex">
|
<div
|
||||||
|
className="hidden w-fit shrink-0 select-none font-normal text-muted-foreground md:flex"
|
||||||
|
data-testid="menu_bar_separator"
|
||||||
|
>
|
||||||
/
|
/
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="overflow-hidden truncate text-sm sm:whitespace-normal">
|
<div
|
||||||
<div className="header-menu-bar-display-2 truncate">
|
className="overflow-hidden truncate text-sm sm:whitespace-normal"
|
||||||
|
data-testid="menu_bar_display"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="header-menu-bar-display-2 truncate"
|
||||||
|
data-testid="menu_bar_display_wrapper"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className="header-menu-flow-name-2 truncate"
|
className="header-menu-flow-name-2 truncate"
|
||||||
data-testid="flow-configuration-button"
|
data-testid="flow-configuration-button"
|
||||||
|
|
@ -273,6 +293,7 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
<div
|
<div
|
||||||
className="truncate font-semibold text-primary"
|
className="truncate font-semibold text-primary"
|
||||||
data-testid="flow_name"
|
data-testid="flow_name"
|
||||||
|
id="flow_name"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setEditingName(true);
|
setEditingName(true);
|
||||||
setFlowName(currentFlow.name);
|
setFlowName(currentFlow.name);
|
||||||
|
|
@ -299,6 +320,8 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
handleAddFlow();
|
handleAddFlow();
|
||||||
}}
|
}}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
|
data-testid="menu_new_flow_button"
|
||||||
|
id="menu_new_flow_button"
|
||||||
>
|
>
|
||||||
<IconComponent name="Plus" className="header-menu-options" />
|
<IconComponent name="Plus" className="header-menu-options" />
|
||||||
New
|
New
|
||||||
|
|
@ -309,6 +332,8 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
setOpenSettings(true);
|
setOpenSettings(true);
|
||||||
}}
|
}}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
|
data-testid="menu_edit_flow_button"
|
||||||
|
id="menu_edit_flow_button"
|
||||||
>
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="SquarePen"
|
name="SquarePen"
|
||||||
|
|
@ -320,6 +345,8 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
|
data-testid="menu_save_flow_button"
|
||||||
|
id="menu_save_flow_button"
|
||||||
>
|
>
|
||||||
<ToolbarSelectItem
|
<ToolbarSelectItem
|
||||||
value="Save"
|
value="Save"
|
||||||
|
|
@ -338,6 +365,8 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
setOpenLogs(true);
|
setOpenLogs(true);
|
||||||
}}
|
}}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
|
data-testid="menu_logs_flow_button"
|
||||||
|
id="menu_logs_flow_button"
|
||||||
>
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="ScrollText"
|
name="ScrollText"
|
||||||
|
|
@ -361,6 +390,8 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
data-testid="menu_import_flow_button"
|
||||||
|
id="menu_import_flow_button"
|
||||||
>
|
>
|
||||||
<IconComponent name="FileUp" className="header-menu-options" />
|
<IconComponent name="FileUp" className="header-menu-options" />
|
||||||
Import
|
Import
|
||||||
|
|
@ -379,6 +410,8 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
undo();
|
undo();
|
||||||
}}
|
}}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
|
data-testid="menu_undo_flow_button"
|
||||||
|
id="menu_undo_flow_button"
|
||||||
>
|
>
|
||||||
<ToolbarSelectItem
|
<ToolbarSelectItem
|
||||||
value="Undo"
|
value="Undo"
|
||||||
|
|
@ -395,6 +428,8 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
redo();
|
redo();
|
||||||
}}
|
}}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
|
data-testid="menu_redo_flow_button"
|
||||||
|
id="menu_redo_flow_button"
|
||||||
>
|
>
|
||||||
<ToolbarSelectItem
|
<ToolbarSelectItem
|
||||||
value="Redo"
|
value="Redo"
|
||||||
|
|
@ -411,6 +446,8 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
||||||
handleReloadComponents();
|
handleReloadComponents();
|
||||||
}}
|
}}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
|
data-testid="menu_refresh_flow_button"
|
||||||
|
id="menu_refresh_flow_button"
|
||||||
>
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="RefreshCcw"
|
name="RefreshCcw"
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,11 @@ export const HeaderMenu = ({ children }) => (
|
||||||
);
|
);
|
||||||
|
|
||||||
export const HeaderMenuToggle = ({ children }) => (
|
export const HeaderMenuToggle = ({ children }) => (
|
||||||
<DropdownMenuTrigger className="group inline-flex w-full items-center justify-center gap-1 rounded-md pr-0">
|
<DropdownMenuTrigger
|
||||||
|
className="group inline-flex w-full items-center justify-center gap-1 rounded-md pr-0"
|
||||||
|
data-testid="user_menu_button"
|
||||||
|
id="user_menu_button"
|
||||||
|
>
|
||||||
<div className="flex items-center gap-1 rounded-lg px-2 py-1.5 group-hover:bg-muted">
|
<div className="flex items-center gap-1 rounded-lg px-2 py-1.5 group-hover:bg-muted">
|
||||||
{children}
|
{children}
|
||||||
<ChevronsUpDown
|
<ChevronsUpDown
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,8 @@ export const ThemeButtons = () => {
|
||||||
: "text-foreground hover:bg-amber-400 hover:text-background"
|
: "text-foreground hover:bg-amber-400 hover:text-background"
|
||||||
}`}
|
}`}
|
||||||
onClick={() => handleThemeChange("light")}
|
onClick={() => handleThemeChange("light")}
|
||||||
|
data-testid="menu_light_button"
|
||||||
|
id="menu_light_button"
|
||||||
>
|
>
|
||||||
<ForwardedIconComponent name="Sun" className="w-4" />
|
<ForwardedIconComponent name="Sun" className="w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -70,6 +72,8 @@ export const ThemeButtons = () => {
|
||||||
: "text-foreground hover:bg-purple-400 hover:text-background"
|
: "text-foreground hover:bg-purple-400 hover:text-background"
|
||||||
}`}
|
}`}
|
||||||
onClick={() => handleThemeChange("dark")}
|
onClick={() => handleThemeChange("dark")}
|
||||||
|
data-testid="menu_dark_button"
|
||||||
|
id="menu_dark_button"
|
||||||
>
|
>
|
||||||
<ForwardedIconComponent name="Moon" className="w-4" />
|
<ForwardedIconComponent name="Moon" className="w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -83,6 +87,8 @@ export const ThemeButtons = () => {
|
||||||
: "hover:bg-foreground hover:text-background"
|
: "hover:bg-foreground hover:text-background"
|
||||||
}`}
|
}`}
|
||||||
onClick={() => handleThemeChange("system")}
|
onClick={() => handleThemeChange("system")}
|
||||||
|
data-testid="menu_system_button"
|
||||||
|
id="menu_system_button"
|
||||||
>
|
>
|
||||||
<ForwardedIconComponent name="Monitor" className="w-4" />
|
<ForwardedIconComponent name="Monitor" className="w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,10 @@ export default function AppHeader(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-[62px] w-full items-center justify-between gap-2 border-b px-5 py-2.5 dark:bg-background">
|
<div className="flex h-[62px] w-full items-center justify-between gap-2 border-b px-5 py-2.5 dark:bg-background">
|
||||||
{/* Left Section */}
|
{/* Left Section */}
|
||||||
<div className={`flex items-center gap-2`}>
|
<div
|
||||||
|
className={`flex items-center gap-2`}
|
||||||
|
data-testid="header_left_section_wrapper"
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
unstyled
|
unstyled
|
||||||
onClick={() => navigate("/")}
|
onClick={() => navigate("/")}
|
||||||
|
|
@ -78,7 +81,10 @@ export default function AppHeader(): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right Section */}
|
{/* Right Section */}
|
||||||
<div className={`flex items-center gap-2`}>
|
<div
|
||||||
|
className={`flex items-center gap-2`}
|
||||||
|
data-testid="header_right_section_wrapper"
|
||||||
|
>
|
||||||
{!ENABLE_DATASTAX_LANGFLOW && (
|
{!ENABLE_DATASTAX_LANGFLOW && (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,11 @@ export default function FlowToolbar(): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
{ENABLE_API && (
|
{ENABLE_API && (
|
||||||
<>
|
<>
|
||||||
<div className="flex cursor-pointer items-center gap-2">
|
<div
|
||||||
|
className="flex cursor-pointer items-center gap-2"
|
||||||
|
data-testid="api_button_modal"
|
||||||
|
id="api_button_modal"
|
||||||
|
>
|
||||||
{currentFlow && currentFlow.data && (
|
{currentFlow && currentFlow.data && (
|
||||||
<ApiModal
|
<ApiModal
|
||||||
flow={currentFlow}
|
flow={currentFlow}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue