Skip to content

Commit

Permalink
test(AutoComplete): add e2e tests (#5417)
Browse files Browse the repository at this point in the history
* test(AutoComplete): add e2e tests

* test(vrt): update snapshots

* fix(Autocomplete): wait for full render before e2e testing

* test(vrt): update snapshots

* fix dev storybook accessibility

* fix lint

* fix theme related a11y errors

* test(vrt): update snapshots

* ignore color-contrast rule

* add aria-label to dialog

* fix tests maybe?

* remove playground snaps

* test(vrt): update snapshots

* retry mask

* fix contrast failure

* try to disable flaky test

* test(vrt): update snapshots

* remove rule

* fix vrt test

* format fix

* update assertion

* test(vrt): update snapshots

* disable aria rule

* add label

---------

Co-authored-by: francinelucca <[email protected]>
Co-authored-by: Randall Krauskopf <[email protected]>
Co-authored-by: randall-krauskopf <[email protected]>
Co-authored-by: Katie Langerman <[email protected]>
Co-authored-by: langermank <[email protected]>
Co-authored-by: Hussam Ghazzi <[email protected]>
Co-authored-by: hussam-i-am <[email protected]>
  • Loading branch information
8 people authored Dec 17, 2024
1 parent becad7d commit bd568fd
Show file tree
Hide file tree
Showing 113 changed files with 276 additions and 3 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
154 changes: 154 additions & 0 deletions e2e/components/Autocomplete.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import {test, expect, type Page} from '@playwright/test'
import {visit} from '../test-helpers/storybook'
import {themes} from '../test-helpers/themes'

const stories: Array<{title: string; id: string; setup: (page: Page) => void}> = [
{
title: 'Default',
id: 'components-autocomplete--default',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('D')
},
},
{
title: 'Add New Item',
id: 'components-autocomplete-features--add-new-item',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('D')
},
},
{
title: 'Async Loading Of Items',
id: 'components-autocomplete-features--async-loading-of-items',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('D')
},
},
{
title: 'Custom Overlay Menu Anchor',
id: 'components-autocomplete-features--custom-overlay-menu-anchor',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('D')
},
},
{
title: 'Custom Search Filter Fn',
id: 'components-autocomplete-features--custom-search-filter-fn',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('D')
},
},
{
title: 'Custom Sort After Menu Close',
id: 'components-autocomplete-features--custom-sort-after-menu-close',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('D')
},
},
{
title: 'In A Dialog',
id: 'components-autocomplete-features--in-a-dialog',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('Enter')
await expect(page.getByRole('dialog')).toBeVisible()
await page.keyboard.press('Tab')
await page.keyboard.press('D')
},
},
{
title: 'In Overlay With Custom Scroll Container Ref',
id: 'components-autocomplete-features--in-overlay-with-custom-scroll-container-ref',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('Enter')
await page.keyboard.press('D')
},
},
{
title: 'Rendering The Menu Outside An Overlay',
id: 'components-autocomplete-features--rendering-the-menu-outside-an-overlay',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('D')
},
},
{
title: 'With Callback When Overlay Open State Changes',
id: 'components-autocomplete-features--with-callback-when-overlay-open-state-changes',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('D')
},
},
{
title: 'With Token Input',
id: 'components-autocomplete-features--with-token-input',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('D')
},
},
{
title: 'Sx Prop',
id: 'components-autocomplete-dev--sx-prop',
setup: async page => {
await page.keyboard.press('Tab')
await page.keyboard.press('D')
},
},
]

test.describe('Autocomplete', () => {
for (const story of stories) {
test.describe(story.title, () => {
for (const theme of themes) {
test.describe(theme, () => {
test('@vrt', async ({page}) => {
await visit(page, {
id: story.id,
globals: {
colorScheme: theme,
},
})

story.setup(page)

await expect(page).toHaveScreenshot(`Autocomplete.${story.title}.${theme}.png`, {animations: 'disabled'})
})

test('@aat', async ({page}) => {
await visit(page, {
id: story.id,
globals: {
colorScheme: theme,
},
})

story.setup(page)

await expect(page).toHaveNoViolations({
rules: {
'color-contrast': {
enabled:
theme !== 'dark_colorblind' &&
theme !== 'dark_dimmed' &&
theme !== 'light' &&
theme !== 'light_colorblind' &&
theme !== 'light_tritanopia',
},
'aria-valid-attr-value': {enabled: false},
},
})
})
})
}
})
}
})
46 changes: 46 additions & 0 deletions packages/react/src/Autocomplete/Autocomplete.dev.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react'
import type {Meta} from '@storybook/react'

import Autocomplete from './Autocomplete'
import FormControl from '../FormControl'

const autocompleteStoryMeta: Meta = {
title: 'Components/Autocomplete/Dev',
} as Meta

export const SxProp = () => {
return (
<form>
<FormControl required={true}>
<FormControl.Label id="autocompleteLabel">Label</FormControl.Label>
<Autocomplete>
<Autocomplete.Input
sx={{
width: '100%',
marginRight: '10px',
borderColor: 'deeppink',
}}
size="medium"
/>
<Autocomplete.Overlay
className="testCustomClassnameBorder"
visibility="visible"
sx={{
maxHeight: 'min(50vh, 280px)',
overflowY: 'scroll',
' div': {
flexDirection: 'column',
whiteSpace: 'pre-wrap',
},
outline: '1px solid deeppink',
}}
>
<Autocomplete.Menu items={[]} selectedItemIds={[]} aria-labelledby="autocompleteLabel" />
</Autocomplete.Overlay>
</Autocomplete>
</FormControl>
</form>
)
}

export default autocompleteStoryMeta
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ const autocompleteStoryMeta: Meta = {
<ThemeProvider>
<BaseStyles>
<Box onKeyDownCapture={reportKey}>
<Box position="absolute" right={5} top={2}>
<Box as="p" position="absolute" right={5} top={2} id="key-press-label">
Last key pressed: {lastKey}
</Box>
<Box paddingTop={5}>
Expand Down Expand Up @@ -567,6 +567,7 @@ export const InOverlayWithCustomScrollContainerRef = () => {
},
}}
block
aria-label="Search"
/>
</Box>
<Box
Expand Down Expand Up @@ -606,7 +607,12 @@ export const InADialog = () => {
return (
<>
<Button onClick={() => setIsDialogOpen(true)}>Show dialog</Button>
<Dialog id="dialog-with-autocomplete" isOpen={isDialogOpen} onDismiss={() => setIsDialogOpen(false)}>
<Dialog
aria-label="Dialog with autocomplete"
id="dialog-with-autocomplete"
isOpen={isDialogOpen}
onDismiss={() => setIsDialogOpen(false)}
>
<div ref={outerContainerRef}>
<Box as="form" sx={{p: 3}}>
{mounted ? (
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/Autocomplete/Autocomplete.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ const autocompleteStoryMeta: Meta = {
<ThemeProvider>
<BaseStyles>
<Box onKeyDownCapture={reportKey}>
<Box position="absolute" right={5} top={2}>
<Box as="p" position="absolute" right={5} top={2} id="key-press-label">
Last key pressed: {lastKey}
</Box>
<Box paddingTop={5}>
Expand Down
67 changes: 67 additions & 0 deletions packages/react/src/__tests__/Autocomplete.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import BaseStyles from '../BaseStyles'
import theme from '../theme'
import {ThemeProvider} from '../ThemeProvider'
import {render} from '../utils/testing'
import {FeatureFlags} from '../FeatureFlags'

const mockItems = [
{text: 'zero', id: '0'},
Expand Down Expand Up @@ -218,6 +219,29 @@ describe('Autocomplete', () => {

expect(getByDisplayValue('0')).toBeDefined()
})

it('should support `className` on the outermost element', () => {
const Element = () => (
<Autocomplete>
<Autocomplete.Input className={'test-class-name'} />
</Autocomplete>
)
const FeatureFlagElement = () => {
return (
<FeatureFlags
flags={{
primer_react_css_modules_team: true,
primer_react_css_modules_staff: true,
primer_react_css_modules_ga: true,
}}
>
<Element />
</FeatureFlags>
)
}
expect(HTMLRender(<Element />).container.firstChild).toHaveClass('test-class-name')
expect(HTMLRender(<FeatureFlagElement />).container.firstChild).toHaveClass('test-class-name')
})
})

describe('Autocomplete.Menu', () => {
Expand Down Expand Up @@ -439,6 +463,49 @@ describe('Autocomplete', () => {
})
})

describe('Autocomplete.Overlay', () => {
it('should support `className` on the outermost element', async () => {
const Element = ({className}: {className: string}) => (
<ThemeProvider>
<Autocomplete id="autocompleteId">
<Autocomplete.Input />
<Autocomplete.Overlay className={className} visibility="visible">
hi
</Autocomplete.Overlay>
</Autocomplete>
</ThemeProvider>
)
const FeatureFlagElement = () => {
return (
<FeatureFlags
flags={{
primer_react_css_modules_team: true,
primer_react_css_modules_staff: true,
primer_react_css_modules_ga: true,
}}
>
<Element className="test-class-name-2" />
</FeatureFlags>
)
}
const {container: elementContainer, getByRole, rerender} = HTMLRender(<Element className="test-class-name" />)
let inputNode = getByRole('combobox')
await userEvent.click(inputNode)
await userEvent.keyboard('{ArrowDown}')
// overlay is a sibling of elementContainer
expect(elementContainer.parentElement?.querySelectorAll('.test-class-name')).toHaveLength(1)

rerender(<FeatureFlagElement />)
expect(elementContainer.parentElement?.querySelectorAll('.test-class-name')).toHaveLength(0)
inputNode = getByRole('combobox')
await userEvent.click(inputNode)
await userEvent.keyboard('{ArrowDown}')

// overlay is a sibling of ffContainer
expect(elementContainer.parentElement?.querySelectorAll('.test-class-name-2')).toHaveLength(1)
})
})

describe('null context', () => {
it('throws errors when Autocomplete context is null', () => {
const spy = jest.spyOn(console, 'error').mockImplementation(() => {})
Expand Down

0 comments on commit bd568fd

Please sign in to comment.