-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update render method for tooltips accessible description (#3806)
* add test story to validate SR experience * update tooltip renderChild method and somantic element validation * update tooltip tests to check valid accessible properties * increase test coverage for aria-describedby scenarios * move animation duration tests into own test file * remove now redundant test story * add changeset * split semantic role into util and add unit test
- Loading branch information
1 parent
52e3d1f
commit c8cf582
Showing
7 changed files
with
261 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
--- | ||
"@kaizen/draft-tooltip": patch | ||
--- | ||
|
||
Updates tooltip to pass accessible descriptions only into native or custom semantic components and only when in the DOM | ||
- aria-describedby should not be attach to non semantic elements, ie: div and spans | ||
- id for aria-describedby is undefined until the tooltip is in the dom | ||
- This will stop the a11y error of pointing to an id of an element that does exists | ||
- Increases test coverage to validate semantic elements of the tooltip with receive aria-describedby | ||
- Moves tooltip animation tests to separate file so mock does not interfere with return value | ||
|
99 changes: 71 additions & 28 deletions
99
draft-packages/tooltip/KaizenDraft/Tooltip/Tooltip.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
draft-packages/tooltip/KaizenDraft/Tooltip/TooltipAnimation.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import React from "react" | ||
import { render } from "@testing-library/react" | ||
import * as AppearanceAnim from "./AppearanceAnim" | ||
import { Tooltip } from "./index" | ||
import "@testing-library/jest-dom" | ||
jest.mock("./AppearanceAnim") | ||
const AnimationProvider = AppearanceAnim.AnimationProvider as jest.Mock | ||
|
||
describe("<Tooltip /> animationDuration", () => { | ||
beforeEach(() => { | ||
AnimationProvider.mockReturnValue(<div />) | ||
}) | ||
describe("When no animationDuration prop is given", () => { | ||
it("animationDuration prop is passed to AnimationProvider as undefined", () => { | ||
render( | ||
<Tooltip text="Example"> | ||
<div /> | ||
</Tooltip> | ||
) | ||
expect(AnimationProvider).toHaveBeenCalledWith( | ||
expect.objectContaining({ | ||
animationDuration: undefined, | ||
}), | ||
{} | ||
) | ||
}) | ||
}) | ||
describe("When animationDuration prop is given", () => { | ||
it("animationDuration prop is passed to AnimationProvider", () => { | ||
render( | ||
<Tooltip text="Example" animationDuration={1000}> | ||
<div /> | ||
</Tooltip> | ||
) | ||
expect(AnimationProvider).toHaveBeenCalledWith( | ||
expect.objectContaining({ | ||
animationDuration: 1000, | ||
}), | ||
{} | ||
) | ||
}) | ||
}) | ||
}) |
68 changes: 68 additions & 0 deletions
68
draft-packages/tooltip/KaizenDraft/Tooltip/utils/isSemanticElement.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import React from "react" | ||
import { Button, IconButton } from "@kaizen/button" | ||
import { Icon } from "@kaizen/component-library" | ||
import ArrowIcon from "@kaizen/component-library/icons/arrow-right.icon.svg" | ||
import { isSemanticElement } from "./isSemanticElement" | ||
|
||
describe("isSemanticElement", () => { | ||
it("returns true if provided a native element with a semantic role", () => { | ||
expect( | ||
isSemanticElement( | ||
<button onClick={jest.fn()} type="button"> | ||
click | ||
</button> | ||
) | ||
).toBe(true) | ||
expect(isSemanticElement(<a href="/">link</a>)).toBe(true) | ||
}) | ||
|
||
it("returns false if provided a non-semantic element", () => { | ||
expect(isSemanticElement(<span>click</span>)).toBe(false) | ||
expect(isSemanticElement(<div>link</div>)).toBe(false) | ||
}) | ||
|
||
it("returns true if provided one of the Kaizen components from the allowed list", () => { | ||
expect(isSemanticElement(<Button label="Click" />)).toBe(true) | ||
expect(isSemanticElement(<IconButton label="click" />)).toBe(true) | ||
}) | ||
|
||
it("will return true if provided a non-semantic element with a semantic role", () => { | ||
expect( | ||
isSemanticElement( | ||
<span | ||
tabIndex={0} | ||
role="button" | ||
onKeyDown={jest.fn} | ||
onClick={jest.fn()} | ||
> | ||
custom semantic el | ||
</span> | ||
) | ||
).toBe(true) | ||
expect( | ||
isSemanticElement( | ||
<div tabIndex={0} role="button" onKeyDown={jest.fn} onClick={jest.fn()}> | ||
custom semantic el | ||
</div> | ||
) | ||
).toBe(true) | ||
expect( | ||
isSemanticElement( | ||
<div role="textbox" contentEditable="true" aria-multiline="true" /> | ||
) | ||
).toBe(true) | ||
}) | ||
|
||
it("returns false if provided an element using a role 'presentation' or 'none'", () => { | ||
expect( | ||
isSemanticElement(<Icon role="presentation" icon={ArrowIcon} />) | ||
).toBe(false) | ||
expect( | ||
isSemanticElement( | ||
<span role="none"> | ||
<Icon icon={ArrowIcon} /> | ||
</span> | ||
) | ||
).toBe(false) | ||
}) | ||
}) |
35 changes: 35 additions & 0 deletions
35
draft-packages/tooltip/KaizenDraft/Tooltip/utils/isSemanticElement.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import React, { ReactNode } from "react" | ||
|
||
// Noting that this is contingent on our displayName for our components - this something we control | ||
const allowedDisplayNames = ["Button", "IconButton", "FilterButtonBase"] | ||
|
||
export function extractDisplayName(type: React.FunctionComponent): string { | ||
return type.displayName || type.name || "Unknown" | ||
} | ||
|
||
/** | ||
* Validates implicit or explicitly semantic roles required to make `aria-describedby` announce predictably with screen readers | ||
*/ | ||
export const isSemanticElement = ( | ||
element: ReactNode | ||
): element is React.ReactElement => { | ||
if (!React.isValidElement(element)) return false | ||
|
||
const { props, type } = element | ||
|
||
if ("role" in props) { | ||
return props.role !== "presentation" && props.role !== "none" | ||
} | ||
|
||
if (typeof type !== "string") { | ||
// As we are only checking whether this matches to our allowedDisplayNames | ||
// type casting should be fine | ||
const displayName = extractDisplayName( | ||
type as unknown as React.FunctionComponent | ||
) | ||
|
||
return allowedDisplayNames.includes(displayName) | ||
} | ||
|
||
return !(type === "div" || type === "span") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters