Skip to content

Commit

Permalink
[Axe] Run axe across all stories (#5592)
Browse files Browse the repository at this point in the history
* Run storybook axe scans on CI

* test

* clean

* remove console

* rephrase id

* unused

* edits

* try

* test

* test

* store

* store

* store

* fic

* fix vrt

* fix axe violation

* fix

* test

* test

* ActionMenu story fix

* Header axe violations

* fix aria-label

* Eanable SelectPanel feature flag for FilteredActionList Story

* format + lint + remove cli changes

* lint

* lint

* unique aria-labels on banner

* replace link with button on deprecated storybook example

* ts-ignore message

* ts-ignore message

* remove parantheses from file names

* Potential fix for code scanning alert no. 8: Replacement of a substring with itself

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* remove /

* remove /

* remove space

* Update e2e/components/Axe.test.ts

Co-authored-by: Josh Black <[email protected]>

* add test skip

* add test skip

* add progressbar fix

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Josh Black <[email protected]>
  • Loading branch information
3 people authored Jan 31, 2025
1 parent 59e0efa commit 92d7771
Show file tree
Hide file tree
Showing 15 changed files with 92 additions and 55 deletions.
51 changes: 51 additions & 0 deletions e2e/components/Axe.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {test, expect} from '@playwright/test'
// @ts-ignore since this file is generated in the ci to generate this file run npx build storybook in packages/react
import componentsConfig from '../../packages/react/storybook-static/index.json'
import {visit} from '../test-helpers/storybook'
import {themes} from '../test-helpers/themes'

/**
* These stories should not be tested in the CI because they are stress-tests and
* perform slowly
*/
const SKIPPED_TESTS = [
'components-treeview-features--stress-test',
'components-treeview-features--contain-intrinsic-size',
'components-flash-features--with-icon-action-dismiss', // TODO: Remove once color-contrast issues have been resolved
'components-flash-features--with-icon-and-action', // TODO: Remove once color-contrast issues have been resolved
]

type Component = {
name: string
}

const {entries} = componentsConfig

test.describe('@aat', () => {
for (const [id, entry] of Object.entries(entries as Record<string, Component>)) {
if (SKIPPED_TESTS.includes(id)) {
continue
}

const {name} = entry
// remove parentheses and slashes from the name to avoid playwright file issues
// eslint-disable-next-line no-useless-escape
const cleanedName = name.replaceAll(/[\(\)\/]/g, '')

test.describe(id, () => {
for (const theme of themes) {
test.describe(theme, () => {
test(`${cleanedName} @aat`, async ({page}) => {
await visit(page, {
id,
globals: {
colorScheme: theme,
},
})
await expect(page).toHaveNoViolations()
})
})
}
})
}
})
16 changes: 8 additions & 8 deletions packages/react/src/ActionMenu/ActionMenu.examples.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -410,15 +410,15 @@ export const MultipleSections = () => {
</ActionMenu.Anchor>
<ActionMenu.Overlay width="small">
<ActionList>
<ActionList.Group selectionVariant="multiple">
<ActionList.Group>
<ActionList.GroupHeading>Raw file content</ActionList.GroupHeading>
<ActionList.Item onSelect={() => alert('Workflows clicked')}>Download</ActionList.Item>
<ActionList.Item onClick={() => alert('Workflows clicked')}>Download</ActionList.Item>
<ActionList.Divider />
<ActionList.Item onSelect={() => alert('Workflows clicked')}>Jump to line</ActionList.Item>
<ActionList.Item onSelect={() => alert('Workflows clicked')}>Find in file</ActionList.Item>
<ActionList.Item onClick={() => alert('Workflows clicked')}>Jump to line</ActionList.Item>
<ActionList.Item onClick={() => alert('Workflows clicked')}>Find in file</ActionList.Item>
<ActionList.Divider />
<ActionList.Item onSelect={() => alert('Workflows clicked')}>Copy path</ActionList.Item>
<ActionList.Item onSelect={() => alert('Workflows clicked')}>Copy permalink</ActionList.Item>
<ActionList.Item onClick={() => alert('Workflows clicked')}>Copy path</ActionList.Item>
<ActionList.Item onClick={() => alert('Workflows clicked')}>Copy permalink</ActionList.Item>
</ActionList.Group>
<ActionList.Divider />
<ActionList.Group selectionVariant="multiple">
Expand All @@ -434,9 +434,9 @@ export const MultipleSections = () => {
))}
</ActionList.Group>
<ActionList.Divider />
<ActionList.Group selectionVariant="multiple">
<ActionList.Group>
<ActionList.GroupHeading>View options</ActionList.GroupHeading>
<ActionList.Item onSelect={() => alert('Delete file')} variant="danger">
<ActionList.Item onClick={() => alert('Delete file')} variant="danger">
Delete file
</ActionList.Item>
</ActionList.Group>
Expand Down
5 changes: 2 additions & 3 deletions packages/react/src/ActionMenu/ActionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,8 @@ const Anchor = React.forwardRef<HTMLElement, ActionMenuAnchorProps>(({children:
})

/** this component is syntactical sugar 🍭 */
export type ActionMenuButtonProps = Omit<ButtonProps, 'children'> & {
children: React.ReactNode
}
export type ActionMenuButtonProps = ButtonProps

const MenuButton = React.forwardRef(({...props}, anchorRef) => {
return (
<Anchor ref={anchorRef}>
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/Banner/Banner.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const Playground: StoryObj<typeof Banner> = {
<PageLayout>
<PageLayout.Pane divider="line" position="start">
<Banner
aria-label="Pane level banner"
onDismiss={onDismiss ? action('onDismiss') : undefined}
primaryAction={primaryAction ? <Banner.PrimaryAction>{primaryAction}</Banner.PrimaryAction> : null}
secondaryAction={
Expand All @@ -49,6 +50,7 @@ export const Playground: StoryObj<typeof Banner> = {

<PageLayout.Content>
<Banner
aria-label="Content level banner"
onDismiss={onDismiss ? action('onDismiss') : undefined}
primaryAction={primaryAction ? <Banner.PrimaryAction>{primaryAction}</Banner.PrimaryAction> : null}
secondaryAction={
Expand Down
3 changes: 2 additions & 1 deletion packages/react/src/Button/ButtonBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ const ButtonBase = forwardRef(
if (
innerRef.current &&
!(innerRef.current instanceof HTMLButtonElement) &&
!((innerRef.current as unknown) instanceof HTMLAnchorElement)
!((innerRef.current as unknown) instanceof HTMLAnchorElement) &&
!((innerRef.current as HTMLElement).tagName === 'SUMMARY')
) {
// eslint-disable-next-line no-console
console.warn('This component should be an instanceof a semantic button or anchor')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const InactiveButtonsGroup = () => {
)

const secondaryButton = (
<IconButton aria-label="Secondary Button Aria Label" aria-disabled={true} inactive={true} icon={DashIcon} />
<IconButton aria-label="Secondary Button" aria-disabled={true} inactive={true} icon={DashIcon} />
)

return (
Expand All @@ -84,7 +84,7 @@ export const InactiveButtonsGroup = () => {

<ActionMenu open={false} onOpenChange={() => {}}>
<ActionMenu.Anchor>
<Tooltip text="this button is inactive" direction="ne" type="label">
<Tooltip text="this button is inactive" direction="ne" type="description">
{secondaryButton}
</Tooltip>
</ActionMenu.Anchor>
Expand All @@ -111,7 +111,7 @@ export const DropdownSplit = () => {
{selectedAction}
</Button>
<ActionMenu>
<ActionMenu.Button icon={TriangleDownIcon}>More options</ActionMenu.Button>
<ActionMenu.Button aria-label="More options" icon={TriangleDownIcon} />
<ActionMenu.Overlay>
<ActionList>
{actions.map((action, index) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {ThemeProvider} from '..'
import {FilteredActionList} from '../FilteredActionList'
import BaseStyles from '../BaseStyles'
import Box from '../Box'
import {FeatureFlags} from '../FeatureFlags'

const meta: Meta = {
title: 'Components/FilteredActionList',
Expand Down Expand Up @@ -57,7 +58,7 @@ export function Default(): JSX.Element {
const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase()))

return (
<>
<FeatureFlags flags={{primer_react_select_panel_with_modern_action_list: true}}>
<h1>Filtered Action List</h1>
<div>Please select labels that describe your issue:</div>
<FilteredActionList
Expand All @@ -66,6 +67,6 @@ export function Default(): JSX.Element {
onFilterChange={setFilter}
sx={{border: '1px solid', padding: '8px'}}
/>
</>
</FeatureFlags>
)
}
6 changes: 4 additions & 2 deletions packages/react/src/Header/Header.dev.module.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
.HeaderDev {
background-color: var(--label-olive-bgColor-active);
color: var(--color-prettylights-syntax-carriage-return-text);
/* stylelint-disable-next-line primer/no-display-colors */
background-color: var(--display-pine-bgColor-emphasis);
}

.HeaderDevItem {
padding-left: var(--base-size-24);
}

.HeaderDevLink {
color: var(--color-prettylights-syntax-markup-inserted-text);
color: var(--color-prettylights-syntax-carriage-return-text);
}
6 changes: 3 additions & 3 deletions packages/react/src/Header/Header.dev.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const WithCss = () => (
primer_react_css_modules_ga: true,
}}
>
<Header as="summary" className={classes.HeaderDev}>
<Header className={classes.HeaderDev}>
<Header.Item id="github">
<Header.Link href="#" className={classes.HeaderDevLink}>
<Octicon icon={MarkGithubIcon} size={32} sx={{mr: 2}} />
Expand All @@ -38,7 +38,7 @@ export const WithCss = () => (
)

export const WithSx = () => (
<Header as="summary" sx={{backgroundColor: 'blue'}}>
<Header sx={{backgroundColor: 'blue', color: 'white'}}>
<Header.Item id="github">
<Header.Link href="#" sx={{fontSize: 3}}>
<Octicon icon={MarkGithubIcon} size={32} sx={{mr: 2}} />
Expand All @@ -60,7 +60,7 @@ export const WithSxAndCSS = () => (
primer_react_css_modules_ga: true,
}}
>
<Header as="summary" className={classes.HeaderDev} sx={{backgroundColor: 'orange'}}>
<Header className={classes.HeaderDev} sx={{backgroundColor: 'orange', color: 'black'}}>
<Header.Item id="github">
<Header.Link href="#" className={classes.HeaderDevLink} sx={{p: 0, color: 'black'}}>
<Octicon icon={MarkGithubIcon} size={32} sx={{mr: 2}} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ export const Inline = () => <ProgressBar inline progress="66" sx={{width: '100px
export const Color = () => <ProgressBar progress="66" bg="done.emphasis" aria-label="Upload test.png" />

export const MultipleItems = () => (
<ProgressBar aria-valuenow={70} aria-label="Upload test.png">
<ProgressBar.Item progress={33} sx={{bg: 'accent.emphasis'}} />
<ProgressBar.Item progress={23} bg={'danger.emphasis'} />
<ProgressBar.Item progress={14} bg={'severe.emphasis'} />
<ProgressBar>
<ProgressBar.Item progress={33} aria-label="Photo Usage" sx={{bg: 'accent.emphasis'}} />
<ProgressBar.Item progress={23} aria-label="Application Usage" bg={'danger.emphasis'} />
<ProgressBar.Item progress={14} aria-label="Music Usage" bg={'severe.emphasis'} />
</ProgressBar>
)

Expand Down
17 changes: 0 additions & 17 deletions packages/react/src/UnderlineNav/UnderlineNav.dev.stories.tsx

This file was deleted.

1 change: 0 additions & 1 deletion packages/react/src/__tests__/ActionMenu.types.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {ActionMenu} from '..'
import React from 'react'

export function actionButtonWithoutProps() {
// @ts-expect-error requires children
return <ActionMenu.Button />
}

Expand Down
9 changes: 8 additions & 1 deletion packages/react/src/__tests__/storybook.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import fs from 'node:fs'
import path from 'node:path'

const ROOT_DIRECTORY = path.resolve(__dirname, '..', '..')

// Components opted into the new story format
// TODO: Remove this allowlist when all components use the new story format
const allowlist = [
Expand Down Expand Up @@ -56,6 +57,7 @@ const allowlist = [
'Token',
'UnderlineNav2',
]

const stories = glob
.sync('src/**/*.stories.tsx', {
cwd: ROOT_DIRECTORY,
Expand All @@ -72,7 +74,12 @@ const stories = glob
const type = path.basename(filepath, '.stories.tsx').endsWith('features') ? 'feature' : 'default'
const name = type === 'feature' ? path.basename(file, '.features.stories.tsx') : path.basename(file, '.stories.tsx')

return {name, story: require(filepath), type, relativeFilepath: path.relative(ROOT_DIRECTORY, filepath)}
return {
name,
story: require(filepath),
type,
relativeFilepath: path.relative(ROOT_DIRECTORY, filepath),
}
})

const components = Object.entries(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ const meta: Meta<typeof UnderlinePanels> = {
name: 'string',
},
},
'aria-labelledby': {
type: {
name: 'string',
},
},
id: {
type: {
name: 'string',
Expand All @@ -34,7 +29,6 @@ const meta: Meta<typeof UnderlinePanels> = {
},
args: {
'aria-label': 'Select a tab',
'aria-labelledby': 'tab',
id: 'test',
loadingCounters: false,
},
Expand Down
6 changes: 2 additions & 4 deletions packages/react/src/stories/deprecated/ActionMenu.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ import type {Meta} from '@storybook/react'
import React, {useCallback, useState, useRef} from 'react'
import styled from 'styled-components'
import {ThemeProvider} from '../..'
import type {LinkProps} from '../../Link'
import Link from '../../Link'
import type {ActionMenuProps} from '../../deprecated'
import {ActionMenu, ActionList} from '../../deprecated'
import type {ItemProps} from '../../deprecated/ActionList'
import BaseStyles from '../../BaseStyles'
import {Button} from '../../Button'
import {Button, type ButtonProps} from '../../Button'

const meta: Meta = {
title: 'Deprecated/Components/ActionMenu',
Expand Down Expand Up @@ -233,7 +231,7 @@ export function ComplexListStory(): JSX.Element {
ComplexListStory.storyName = 'Complex List'

export function CustomTrigger(): JSX.Element {
const customAnchor = (props: LinkProps) => <Link {...props} sx={{cursor: 'pointer'}} />
const customAnchor = (props: ButtonProps) => <Button {...props} sx={{cursor: 'pointer'}} />
const [option, setOption] = useState('Select an option')
const onAction = useCallback((itemProps: ItemProps) => {
setOption(itemProps.text || '')
Expand Down

0 comments on commit 92d7771

Please sign in to comment.