mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-10-07 16:08:23 +08:00
fix: use SPA navigation for sidebar Automations button (#217)
This commit is contained in:
@@ -1,14 +1,39 @@
|
||||
import { createEvent, fireEvent, render, screen } from "@testing-library/react";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { AutomationsButton } from "#/components/shared/buttons/automations-button";
|
||||
import {
|
||||
NavigationProvider,
|
||||
type NavigationContextValue,
|
||||
} from "#/context/navigation-context";
|
||||
|
||||
vi.mock("#/components/shared/buttons/styled-tooltip", () => ({
|
||||
StyledTooltip: ({ children }: { children: unknown }) => children,
|
||||
}));
|
||||
|
||||
function renderAutomationsButton(
|
||||
props: { disabled?: boolean } = {},
|
||||
overrides: Partial<NavigationContextValue> = {},
|
||||
) {
|
||||
const value: NavigationContextValue = {
|
||||
currentPath: "/",
|
||||
conversationId: null,
|
||||
isNavigating: false,
|
||||
navigate: vi.fn(),
|
||||
...overrides,
|
||||
};
|
||||
|
||||
const result = render(
|
||||
<NavigationProvider value={value}>
|
||||
<AutomationsButton {...props} />
|
||||
</NavigationProvider>,
|
||||
);
|
||||
|
||||
return { ...result, navigate: value.navigate };
|
||||
}
|
||||
|
||||
describe("AutomationsButton", () => {
|
||||
it("should render a link to /automations", () => {
|
||||
render(<AutomationsButton />);
|
||||
renderAutomationsButton();
|
||||
|
||||
const link = screen.getByTestId("automations-button");
|
||||
expect(link).toBeInTheDocument();
|
||||
@@ -16,15 +41,26 @@ describe("AutomationsButton", () => {
|
||||
});
|
||||
|
||||
it("should be focusable and accessible when enabled", () => {
|
||||
render(<AutomationsButton />);
|
||||
renderAutomationsButton();
|
||||
|
||||
const link = screen.getByTestId("automations-button");
|
||||
expect(link).toHaveAttribute("tabIndex", "0");
|
||||
expect(link).toHaveAttribute("aria-label", "SIDEBAR$AUTOMATIONS");
|
||||
});
|
||||
|
||||
it("should navigate via SPA routing without a full page reload when clicked", () => {
|
||||
const { navigate } = renderAutomationsButton();
|
||||
|
||||
const link = screen.getByTestId("automations-button");
|
||||
const clickEvent = createEvent.click(link);
|
||||
fireEvent(link, clickEvent);
|
||||
|
||||
expect(navigate).toHaveBeenCalledWith("/automations", { replace: false });
|
||||
expect(clickEvent.defaultPrevented).toBe(true);
|
||||
});
|
||||
|
||||
it("should prevent navigation and remove from tab order when disabled", () => {
|
||||
render(<AutomationsButton disabled />);
|
||||
const { navigate } = renderAutomationsButton({ disabled: true });
|
||||
|
||||
const link = screen.getByTestId("automations-button");
|
||||
expect(link).toHaveAttribute("tabIndex", "-1");
|
||||
@@ -32,5 +68,6 @@ describe("AutomationsButton", () => {
|
||||
const clickEvent = createEvent.click(link);
|
||||
fireEvent(link, clickEvent);
|
||||
expect(clickEvent.defaultPrevented).toBe(true);
|
||||
expect(navigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { I18nKey } from "#/i18n/declaration";
|
||||
import { NavigationLink } from "#/components/shared/navigation-link";
|
||||
import { StyledTooltip } from "#/components/shared/buttons/styled-tooltip";
|
||||
import AutomationsIcon from "#/icons/automations.svg?react";
|
||||
import { cn } from "#/utils/utils";
|
||||
@@ -17,8 +18,8 @@ export function AutomationsButton({
|
||||
|
||||
return (
|
||||
<StyledTooltip content={label} placement="right">
|
||||
<a
|
||||
href="/automations"
|
||||
<NavigationLink
|
||||
to="/automations"
|
||||
data-testid="automations-button"
|
||||
aria-label={label}
|
||||
tabIndex={disabled ? -1 : 0}
|
||||
@@ -32,7 +33,7 @@ export function AutomationsButton({
|
||||
})}
|
||||
>
|
||||
<AutomationsIcon width={24} height={24} />
|
||||
</a>
|
||||
</NavigationLink>
|
||||
</StyledTooltip>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user