Skip to content

Commit e4f420f

Browse files
olayinkaadelakunOlayinka Adelakunautofix-ci[bot]Olayinka Adelakun
authored
fix(a11y): fix aria-allowed-attr, invalid sidebar list structure, and session filter label mismatch on flow editor (#13668)
* fix(a11y): fix aria-allowed-attr, invalid sidebar list structure, and session filter label mismatch on flow editor * [autofix.ci] apply automated fixes * improve translations * remove app-header-a11y --------- Co-authored-by: Olayinka Adelakun <olayinkaadelakun@Olayinkas-MacBook-Pro.local> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Olayinka Adelakun <olayinkaadelakun@mac.war.can.ibm.com>
1 parent bac8a7b commit e4f420f

16 files changed

Lines changed: 194 additions & 148 deletions

File tree

src/frontend/src/components/core/appHeaderComponent/__tests__/app-header-a11y.test.tsx

Lines changed: 0 additions & 111 deletions
This file was deleted.

src/frontend/src/components/core/appHeaderComponent/components/FlowMenu/__tests__/FlowMenu.spec.tsx

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jest.mock("@/customization/hooks/use-custom-navigate", () => ({
4242
}));
4343
jest.mock("@/stores/flowsManagerStore", () => ({
4444
__esModule: true,
45-
default: (sel) =>
45+
default: (sel: (s: object) => unknown) =>
4646
sel({
4747
autoSaving: false,
4848
saveLoading: false,
@@ -51,11 +51,11 @@ jest.mock("@/stores/flowsManagerStore", () => ({
5151
}));
5252
jest.mock("@/stores/alertStore", () => ({
5353
__esModule: true,
54-
default: (sel) => sel({ setSuccessData: jest.fn() }),
54+
default: (sel: (s: object) => unknown) => sel({ setSuccessData: jest.fn() }),
5555
}));
5656
jest.mock("@/stores/flowStore", () => ({
5757
__esModule: true,
58-
default: (sel) =>
58+
default: jest.fn((sel: (s: object) => unknown) =>
5959
sel({
6060
onFlowPage: true,
6161
isBuilding: false,
@@ -68,19 +68,44 @@ jest.mock("@/stores/flowStore", () => ({
6868
locked: false,
6969
},
7070
}),
71+
),
7172
}));
7273
jest.mock("@/stores/shortcuts", () => ({
7374
__esModule: true,
74-
useShortcutsStore: (sel) => sel({ changesSave: "mod+s" }),
75+
useShortcutsStore: (sel: (s: object) => unknown) =>
76+
sel({ changesSave: "mod+s" }),
7577
}));
7678

7779
// Avoid pulling utils that depend on darkStore
7880
jest.mock("@/utils/utils", () => ({
7981
__esModule: true,
80-
cn: (...args) => args.filter(Boolean).join(" "),
82+
cn: (...args: unknown[]) => (args.filter(Boolean) as string[]).join(" "),
8183
getNumberFromString: () => 0,
8284
}));
8385

86+
jest.mock("@/components/ui/popover", () => ({
87+
Popover: ({ children }: { children: React.ReactNode }) => <>{children}</>,
88+
PopoverAnchor: ({ children }: { children: React.ReactNode }) => (
89+
<>{children}</>
90+
),
91+
PopoverTrigger: ({ children }: { children: React.ReactNode }) => (
92+
<>{children}</>
93+
),
94+
PopoverContent: ({
95+
children,
96+
"aria-label": ariaLabel,
97+
}: {
98+
children: React.ReactNode;
99+
"aria-label"?: string;
100+
}) => (
101+
<div data-testid="popover-content" aria-label={ariaLabel}>
102+
{children}
103+
</div>
104+
),
105+
}));
106+
107+
import React from "react";
108+
84109
// styleUtils imports lucide dynamic icons; stub to avoid resolution
85110
jest.mock("lucide-react/dynamicIconImports", () => ({}), { virtual: true });
86111

@@ -101,4 +126,64 @@ describe("FlowMenu MenuBar", () => {
101126
fireEvent.click(screen.getByTestId("save-flow-button"));
102127
expect(mockSave).toHaveBeenCalled();
103128
});
129+
130+
describe("Accessibility — aria labels", () => {
131+
const flowStoreMock = jest.requireMock("@/stores/flowStore");
132+
133+
afterEach(() => {
134+
flowStoreMock.default.mockReset();
135+
flowStoreMock.default.mockImplementation((sel: (s: object) => unknown) =>
136+
sel({
137+
onFlowPage: true,
138+
isBuilding: false,
139+
currentFlow: {
140+
id: "1",
141+
name: "Flow",
142+
folder_id: "f1",
143+
icon: "Workflow",
144+
gradient: "0",
145+
locked: false,
146+
},
147+
}),
148+
);
149+
});
150+
151+
it("menu_bar_display is a button element for keyboard and screen reader access", () => {
152+
render(<MenuBar />);
153+
const trigger = screen.getByTestId("menu_bar_display");
154+
expect(trigger.tagName).toBe("BUTTON");
155+
});
156+
157+
it("menu_bar_display button has aria-label matching the flow name", () => {
158+
render(<MenuBar />);
159+
const trigger = screen.getByTestId("menu_bar_display");
160+
expect(trigger).toHaveAttribute("aria-label", "Flow");
161+
});
162+
163+
it("menu_bar_display aria-label falls back to untitled flow when name is absent", () => {
164+
flowStoreMock.default.mockImplementation((sel: (s: object) => unknown) =>
165+
sel({
166+
onFlowPage: true,
167+
isBuilding: false,
168+
currentFlow: {
169+
id: "1",
170+
name: undefined,
171+
folder_id: "f1",
172+
icon: "Workflow",
173+
gradient: "0",
174+
locked: false,
175+
},
176+
}),
177+
);
178+
render(<MenuBar />);
179+
const trigger = screen.getByTestId("menu_bar_display");
180+
expect(trigger).toHaveAttribute("aria-label", "Untitled Flow");
181+
});
182+
183+
it("popover content has an aria-label of 'Flow settings' for screen readers", () => {
184+
render(<MenuBar />);
185+
const content = screen.getByTestId("popover-content");
186+
expect(content).toHaveAttribute("aria-label", "Flow settings");
187+
});
188+
});
104189
});

src/frontend/src/components/core/appHeaderComponent/components/FlowMenu/index.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,11 @@ export const MenuBar = memo((): JSX.Element => {
130130
/>
131131
</div>
132132
<PopoverTrigger asChild>
133-
<div
133+
<button
134+
type="button"
134135
className="group relative -mr-5 flex shrink-0 cursor-pointer items-center gap-2 text-sm sm:whitespace-normal"
135136
data-testid="menu_bar_display"
137+
aria-label={currentFlowName || t("flow.untitledFlow")}
136138
>
137139
<span
138140
ref={measureRef}
@@ -150,7 +152,7 @@ export const MenuBar = memo((): JSX.Element => {
150152
"sm:group-hover:translate-x-0 sm:group-hover:opacity-100",
151153
)}
152154
/>
153-
</div>
155+
</button>
154156
</PopoverTrigger>
155157
<div className={"ml-5 hidden shrink-0 items-center sm:flex"}>
156158
{!autoSaving && (
@@ -195,6 +197,7 @@ export const MenuBar = memo((): JSX.Element => {
195197
className="flex w-96 flex-col gap-4 p-4"
196198
align="center"
197199
sideOffset={15}
200+
aria-label={t("flow.flowSettings")}
198201
>
199202
<FlowSettingsComponent
200203
close={() => setOpenSettings(false)}

src/frontend/src/locales/de.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,5 +2074,6 @@
20742074
"flows.selectFlow": "Select {{name}}",
20752075
"flows.moreOptions": "More options for {{name}}",
20762076
"folder.optionsFor": "Options for {{name}}",
2077-
"paginator.pageLabel": "Page"
2077+
"paginator.pageLabel": "Page",
2078+
"flow.flowSettings": "Flow settings"
20782079
}

src/frontend/src/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"stepper.nextStep": "Next Step",
5959
"stepper.back": "Back",
6060
"stepper.needHelp": "Need Help?",
61+
"flow.flowSettings": "Flow settings",
6162
"flow.menu.editDetails": "Edit details",
6263
"flow.menu.export": "Export",
6364
"flow.menu.duplicate": "Duplicate",

src/frontend/src/locales/es.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,5 +2074,6 @@
20742074
"flows.selectFlow": "Select {{name}}",
20752075
"flows.moreOptions": "More options for {{name}}",
20762076
"folder.optionsFor": "Options for {{name}}",
2077-
"paginator.pageLabel": "Page"
2077+
"paginator.pageLabel": "Page",
2078+
"flow.flowSettings": "Flow settings"
20782079
}

src/frontend/src/locales/fr.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,5 +2074,6 @@
20742074
"flows.selectFlow": "Select {{name}}",
20752075
"flows.moreOptions": "More options for {{name}}",
20762076
"folder.optionsFor": "Options for {{name}}",
2077-
"paginator.pageLabel": "Page"
2077+
"paginator.pageLabel": "Page",
2078+
"flow.flowSettings": "Flow settings"
20782079
}

src/frontend/src/locales/ja.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,5 +2074,6 @@
20742074
"flows.selectFlow": "Select {{name}}",
20752075
"flows.moreOptions": "More options for {{name}}",
20762076
"folder.optionsFor": "Options for {{name}}",
2077-
"paginator.pageLabel": "Page"
2077+
"paginator.pageLabel": "Page",
2078+
"flow.flowSettings": "Flow settings"
20782079
}

src/frontend/src/locales/pt.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,5 +2074,6 @@
20742074
"flows.selectFlow": "Select {{name}}",
20752075
"flows.moreOptions": "More options for {{name}}",
20762076
"folder.optionsFor": "Options for {{name}}",
2077-
"paginator.pageLabel": "Page"
2077+
"paginator.pageLabel": "Page",
2078+
"flow.flowSettings": "Flow settings"
20782079
}

src/frontend/src/locales/zh-Hans.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,5 +2074,6 @@
20742074
"flows.selectFlow": "Select {{name}}",
20752075
"flows.moreOptions": "More options for {{name}}",
20762076
"folder.optionsFor": "Options for {{name}}",
2077-
"paginator.pageLabel": "Page"
2077+
"paginator.pageLabel": "Page",
2078+
"flow.flowSettings": "Flow settings"
20782079
}

0 commit comments

Comments
 (0)