From 71329fe353212e92411fdbbea7efd62f70068151 Mon Sep 17 00:00:00 2001 From: Nisha Yerunkar Date: Thu, 13 Feb 2025 14:18:21 -0800 Subject: [PATCH] [SR] Add aria-labels for x- and y-axis labels (#2221) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary: Right now if a person using a screen reader traverses through the graph, they hear "x, math" and "y, math" for the axis labels, or whatever the x and y labels are updated to by the content authors. We need to add a description for this so people know what x and y are referring to. - Added "X-axis" and "Y-axis" strings as `aria-label`s for the `AxisLabel` elements. - This means that it reads the actual label as a child of this axis label group - This is my preferred approach so that it already handles math speech wehen reading the TeX label, and we don't have to manually use the speech rule engine again redundantly Issue: https://khanacademy.atlassian.net/browse/LEMS-2844 ## Test plan: `yarn jest packages/perseus/src/widgets/interactive-graphs/mafs-graph.test.tsx` Storybook - Go to any interactive graph editor story (http://localhost:6006/iframe.html?globals=&args=&id=perseuseditor-widgets-interactive-graph--interactive-graph-segment&viewMode=story) - Use the screen reader to confirm that the axis labels now say "X-axis, group" - Continue using the screen reader and make sure that the actual axis label is read - Update the x and y labels to have some kind of math TeX like `\frac{1}{2}` - Repeat the above steps and confirm that the screen reader reads the math correctly Author: nishasy Reviewers: nishasy, SonicScrewdriver, catandthemachines Required Reviewers: Approved By: SonicScrewdriver Checks: ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x) Pull Request URL: https://github.com/Khan/perseus/pull/2221 --- .changeset/slimy-schools-brake.md | 5 + packages/perseus/src/strings.ts | 6 + .../interactive-graph.test.tsx.snap | 2 + .../backgrounds/axis-labels.tsx | 6 +- .../interactive-graphs/mafs-graph.test.tsx | 134 ++++++------------ .../widgets/interactive-graphs/mafs-graph.tsx | 2 +- 6 files changed, 64 insertions(+), 91 deletions(-) create mode 100644 .changeset/slimy-schools-brake.md diff --git a/.changeset/slimy-schools-brake.md b/.changeset/slimy-schools-brake.md new file mode 100644 index 0000000000..5dce7512a3 --- /dev/null +++ b/.changeset/slimy-schools-brake.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/perseus": patch +--- + +[SR] Add aria-labels for x- and y-axis labels diff --git a/packages/perseus/src/strings.ts b/packages/perseus/src/strings.ts index a5d269a617..c25bad1bc8 100644 --- a/packages/perseus/src/strings.ts +++ b/packages/perseus/src/strings.ts @@ -134,6 +134,8 @@ export type PerseusStrings = { simulationLocaleWarning: string; selectAnAnswer: string; // The following strings are used for interactive graph SR descriptions. + xAxis: string; + yAxis: string; addPoint: string; removePoint: string; graphKeyboardPrompt: string; @@ -645,6 +647,8 @@ export const strings = { // translation tickets after all interactive graph SR strings have // been finalized. Remove this comment after the tickets have been // created. + xAxis: "X-axis", + yAxis: "Y-axis", srPointAtCoordinates: "Point %(num)s at %(x)s comma %(y)s.", srCircleGraph: "A circle on a coordinate plane.", srCircleShape: @@ -902,6 +906,8 @@ export const mockStrings: PerseusStrings = { selectAnAnswer: "Select an answer", // The following strings are used for interactive graph SR descriptions. + xAxis: "X-axis", + yAxis: "Y-axis", graphKeyboardPrompt: "Press Shift + Enter to interact with the graph", addPoint: "Add Point", removePoint: "Remove Point", diff --git a/packages/perseus/src/widgets/interactive-graphs/__snapshots__/interactive-graph.test.tsx.snap b/packages/perseus/src/widgets/interactive-graphs/__snapshots__/interactive-graph.test.tsx.snap index ef0ae4b361..0ab18ac5df 100644 --- a/packages/perseus/src/widgets/interactive-graphs/__snapshots__/interactive-graph.test.tsx.snap +++ b/packages/perseus/src/widgets/interactive-graphs/__snapshots__/interactive-graph.test.tsx.snap @@ -26,6 +26,7 @@ exports[`Interactive Graph interactive-graph widget A none-type graph renders pr class="default_xu2jcg-o_O-inlineStyles_16155wj" > {replaceOutsideTeX(xAxisLabelText)} { ], }; - const baseMafsGraphProps = getBaseMafsGraphPropsForTests(); + const baseMafsGraphProps = baseMafsProps; render( { it("renders TeX in axis Labels", () => { const basePropsWithTexLabels = { - ...getBaseMafsGraphPropsForTests(), + ...baseMafsProps, labels: ["$1/2$", "$3/4$"], }; @@ -179,7 +181,7 @@ describe("MafsGraph", () => { it("renders plain text in axis Labels", () => { const basePropsWithTexLabels = { - ...getBaseMafsGraphPropsForTests(), + ...baseMafsProps, labels: ["4/5", "5/6"], }; @@ -188,6 +190,20 @@ describe("MafsGraph", () => { expect(screen.getByText("\\text{5/6}")).toBeInTheDocument(); }); + it("includes aria-labels for the axes labels", () => { + const basePropsWithTexLabels = { + ...baseMafsProps, + }; + + render(); + + const xAxisLabel = screen.getByLabelText("X-axis"); + const yAxisLabel = screen.getByLabelText("Y-axis"); + + expect(xAxisLabel).toBeInTheDocument(); + expect(yAxisLabel).toBeInTheDocument(); + }); + it("renders ARIA labels for each point (segment)", () => { const state: InteractiveGraphState = { type: "segment", @@ -206,11 +222,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); expectLabelInDoc("Endpoint 1 at 0 comma 0."); @@ -239,11 +251,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); expectLabelInDoc("Endpoint 1 on segment 1 at 0 comma 0."); @@ -268,11 +276,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); expectLabelInDoc("Point 1 at 0 comma 0."); @@ -301,11 +305,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); expectLabelInDoc("Point 1 on line 1 at 0 comma 0."); @@ -330,11 +330,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); expectLabelInDoc("Endpoint at 0 comma 0."); @@ -355,11 +351,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); // Circle's radius point has a special label @@ -383,11 +375,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); const points = screen.getAllByRole("button"); @@ -420,11 +408,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); expectLabelInDoc("Point 1 at -1 comma 1."); @@ -452,11 +436,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); expectLabelInDoc("Point 1 at -1 comma 1."); @@ -488,11 +468,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); expectLabelInDoc("Point 1 at -1 comma 1."); @@ -522,11 +498,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); expectLabelInDoc("Point 1, terminal side at -1 comma 1"); @@ -557,11 +529,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); expectLabelInDoc("Point 1, terminal side at 7 comma 0"); @@ -621,11 +589,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); const angleGraph = screen.getByLabelText( "An angle on a coordinate plane.", @@ -655,11 +619,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); const angleGraph = screen.getByLabelText( @@ -691,11 +651,7 @@ describe("MafsGraph", () => { }; render( - {}} - />, + {}} />, ); expect( @@ -727,7 +683,7 @@ describe("MafsGraph", () => { coords: [[2, 2]], }; - const baseMafsGraphProps = getBaseMafsGraphPropsForTests(); + const baseMafsGraphProps = baseMafsProps; const {rerender} = render( { initialState, ); - const baseMafsGraphProps = getBaseMafsGraphPropsForTests(); + const baseMafsGraphProps = baseMafsProps; render( { initialState, ); - const baseMafsGraphProps = getBaseMafsGraphPropsForTests(); + const baseMafsGraphProps = baseMafsProps; render( { initialState, ); - const baseMafsGraphProps = getBaseMafsGraphPropsForTests(); + const baseMafsGraphProps = baseMafsProps; render( { initialState, ); - const baseMafsGraphProps = getBaseMafsGraphPropsForTests(); + const baseMafsGraphProps = baseMafsProps; render( { }; const baseMafsGraphProps: MafsGraphProps = { - ...getBaseMafsGraphPropsForTests(), + ...baseMafsProps, markings: "none", }; @@ -1029,7 +985,7 @@ describe("MafsGraph", () => { }; const baseMafsGraphProps: MafsGraphProps = { - ...getBaseMafsGraphPropsForTests(), + ...baseMafsProps, markings: "none", }; @@ -1067,7 +1023,7 @@ describe("MafsGraph", () => { }; const baseMafsGraphProps: MafsGraphProps = { - ...getBaseMafsGraphPropsForTests(), + ...baseMafsProps, markings: "none", }; @@ -1113,7 +1069,7 @@ describe("MafsGraph", () => { }; const baseMafsGraphProps: MafsGraphProps = { - ...getBaseMafsGraphPropsForTests(), + ...baseMafsProps, markings: "none", }; @@ -1163,7 +1119,7 @@ describe("MafsGraph", () => { }; const baseMafsGraphProps: MafsGraphProps = { - ...getBaseMafsGraphPropsForTests(), + ...baseMafsProps, markings: "none", }; @@ -1214,7 +1170,7 @@ describe("MafsGraph", () => { }; const baseMafsGraphProps: MafsGraphProps = { - ...getBaseMafsGraphPropsForTests(), + ...baseMafsProps, markings: "none", }; diff --git a/packages/perseus/src/widgets/interactive-graphs/mafs-graph.tsx b/packages/perseus/src/widgets/interactive-graphs/mafs-graph.tsx index 038ecee65e..96f3338ca0 100644 --- a/packages/perseus/src/widgets/interactive-graphs/mafs-graph.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/mafs-graph.tsx @@ -230,7 +230,7 @@ export const MafsGraph = (props: MafsGraphProps) => { {(props.markings === "graph" || props.markings === "axes") && ( <> - + )}