Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions packages/react/config/vitest/browser/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ import './global.css'
import {beforeEach} from 'vitest'
import {cleanup} from '@testing-library/react'
import '@testing-library/jest-dom/vitest'
import failOnConsole from 'vitest-fail-on-console'

// Fail tests on console.error and console.warn in CI
if (process.env.CI) {
failOnConsole()
}

beforeEach(() => {
cleanup()
Expand Down
3 changes: 2 additions & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@
"@figma/code-connect": "1.3.2",
"@primer/css": "^21.5.1",
"@primer/doc-gen": "^0.0.1",
"@tanstack/react-virtual": "^3.13.12",
"@rollup/plugin-babel": "6.1.0",
"@rollup/plugin-commonjs": "29.0.0",
"@rollup/plugin-json": "6.1.0",
Expand All @@ -119,6 +118,7 @@
"@storybook/addon-links": "^10.1.10",
"@storybook/icons": "^2.0.1",
"@storybook/react-vite": "^10.1.10",
"@tanstack/react-virtual": "^3.13.12",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.4.5",
"@testing-library/react": "^16.3.0",
Expand Down Expand Up @@ -182,6 +182,7 @@
"unist-util-find": "3.0.0",
"unist-util-find-before": "4.0.0",
"unist-util-flat-filter": "2.0.0",
"vitest-fail-on-console": "^0.10.1",
"yaml": "2.7.0"
},
"peerDependencies": {
Expand Down
6 changes: 5 additions & 1 deletion packages/react/src/ActionList/Group.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {describe, it, expect} from 'vitest'
import {describe, it, expect, vi} from 'vitest'
import {render as HTMLRender} from '@testing-library/react'
import BaseStyles from '../BaseStyles'
import {ActionList} from '.'
Expand All @@ -20,6 +20,7 @@ describe('ActionList.Group', () => {
implementsClassName(ActionList.GroupHeading, classes.GroupHeading)

it('should throw an error when ActionList.GroupHeading has an `as` prop when it is used within ActionMenu context', async () => {
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
expect(() =>
HTMLRender(
<BaseStyles>
Expand All @@ -38,6 +39,7 @@ describe('ActionList.Group', () => {
).toThrow(
"Looks like you are trying to set a heading level to a menu role. Group headings for menu type action lists are for representational purposes, and rendered as divs. Therefore they don't need a heading level.",
)
spy.mockRestore()
})

it('should render the ActionList.GroupHeading component as a heading with the given heading level', async () => {
Expand All @@ -54,6 +56,7 @@ describe('ActionList.Group', () => {
expect(heading).toHaveTextContent('Group Heading')
})
it('should throw an error if ActionList.GroupHeading is used without an `as` prop when no role is specified (for list role)', async () => {
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
expect(() =>
HTMLRender(
<ActionList>
Expand All @@ -67,6 +70,7 @@ describe('ActionList.Group', () => {
).toThrow(
"You are setting a heading for a list, that requires a heading level. Please use 'as' prop to set a proper heading level.",
)
spy.mockRestore()
})
it('should render the ActionList.GroupHeading component as a span (not a heading tag) when role is specified as listbox', async () => {
const container = HTMLRender(
Expand Down
4 changes: 3 additions & 1 deletion packages/react/src/ActionList/Heading.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {describe, it, expect} from 'vitest'
import {describe, it, expect, vi} from 'vitest'
import {render as HTMLRender} from '@testing-library/react'
import BaseStyles from '../BaseStyles'
import {ActionList} from '.'
Expand Down Expand Up @@ -42,6 +42,7 @@ describe('ActionList.Heading', () => {
})

it('should throw an error when ActionList.Heading is used within ActionMenu context', async () => {
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
expect(() =>
HTMLRender(
<BaseStyles>
Expand All @@ -59,5 +60,6 @@ describe('ActionList.Heading', () => {
).toThrow(
"ActionList.Heading shouldn't be used within an ActionMenu container. Menus are labelled by the menu button's name.",
)
spy.mockRestore()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ describe('Breadcrumbs', () => {
})

it('shows overflow menu during resize when items exceed container width', () => {
// Suppress act warnings from async state updates in the ResizeObserver callback
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
let resizeCallback: ((entries: ResizeObserverEntry[]) => void) | undefined

const mockResizeObserver = vi.fn().mockImplementation(function (callback) {
Expand Down Expand Up @@ -264,9 +266,12 @@ describe('Breadcrumbs', () => {

// Verify the navigation element is still present after resizes
expect(screen.getByRole('navigation')).toBeInTheDocument()
spy.mockRestore()
})

it('correctly populates overflow menu during resize events', async () => {
// Suppress act warnings from async state updates in the ResizeObserver callback
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
let resizeCallback: ((entries: ResizeObserverEntry[]) => void) | undefined

const mockResizeObserver = vi.fn().mockImplementation(function (callback) {
Expand Down Expand Up @@ -345,6 +350,7 @@ describe('Breadcrumbs', () => {

// Menu button should still be present (7 items > 5)
expect(screen.getByRole('button', {name: /more breadcrumb items/i})).toBeInTheDocument()
spy.mockRestore()

// Open menu again to verify it still works after resize
await user.click(screen.getByRole('button', {name: /more breadcrumb items/i}))
Expand Down Expand Up @@ -483,6 +489,8 @@ describe('Breadcrumbs', () => {
})

it('maintains focus on menu button when menu is closed', async () => {
// Suppress act warnings from async state updates in the ResizeObserver callback
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
const user = userEvent.setup()

renderWithTheme(
Expand Down Expand Up @@ -518,6 +526,7 @@ describe('Breadcrumbs', () => {

// Verify focus returns to button
expect(menuButton).toHaveFocus()
spy.mockRestore()
})
})

Expand Down
12 changes: 9 additions & 3 deletions packages/react/src/CircleBadge/CircleBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,18 @@ const sizeStyles = ({size, variant = 'medium'}: CircleBadgeProps<React.ElementTy
}
}

const CircleBadge = <As extends React.ElementType>({as: Component = 'div', ...props}: CircleBadgeProps<As>) => (
const CircleBadge = <As extends React.ElementType>({
as: Component = 'div',
inline,
size,
variant,
...props
}: CircleBadgeProps<As>) => (
<Component
{...props}
className={clsx(styles.CircleBadge, props.className)}
data-inline={props.inline ? '' : undefined}
style={sizeStyles(props)}
data-inline={inline ? '' : undefined}
style={sizeStyles({size, variant})}
/>
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,12 @@ exports[`CircleBadge > respects the variant prop 1`] = `
<div
class="prc-CircleBadge-CircleBadge-LZ7wp"
style="width: 128px; height: 128px;"
variant="large"
/>
`;

exports[`CircleBadge > uses the size prop to override the variant prop 1`] = `
<div
class="prc-CircleBadge-CircleBadge-LZ7wp"
size="20"
style="width: 20px; height: 20px;"
variant="large"
/>
`;
21 changes: 18 additions & 3 deletions packages/react/src/DataTable/__tests__/Pagination.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,11 @@ describe('Table.Pagination', () => {
})

it('should rerender many pages correctly', async () => {
// Suppress act warnings from async state updates in the Announce component
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
const onChange = vi.fn()

const {rerender} = render(
const {rerender, unmount} = render(
<Pagination aria-label="Test label" onChange={onChange} defaultPageIndex={0} pageSize={25} totalCount={25} />,
)
expect(getPages()).toHaveLength(1)
Expand All @@ -109,6 +111,9 @@ describe('Table.Pagination', () => {
expect(onChange).toHaveBeenCalledWith({
pageIndex: 2,
})
// Unmount before restoring to prevent late async callbacks
unmount()
spy.mockRestore()
})
})

Expand Down Expand Up @@ -284,9 +289,11 @@ describe('Table.Pagination', () => {
})

it('should rerender many pages correctly', async () => {
// Suppress act warnings from async state updates in the Announce component
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
const onChange = vi.fn()

const {rerender} = render(
const {rerender, unmount} = render(
<Pagination aria-label="Test label" onChange={onChange} defaultPageIndex={1} pageSize={25} totalCount={50} />,
)
expect(getPages()).toHaveLength(2)
Expand All @@ -302,6 +309,9 @@ describe('Table.Pagination', () => {
expect(onChange).toHaveBeenCalledWith({
pageIndex: 0,
})
// Unmount before restoring to prevent late async callbacks
unmount()
spy.mockRestore()
})
})

Expand Down Expand Up @@ -350,8 +360,10 @@ describe('Table.Pagination', () => {
})

it('should rerender many pages correctly', async () => {
// Suppress act warnings from async state updates in the Announce component
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
const onChange = vi.fn()
const {rerender} = render(
const {rerender, unmount} = render(
<Pagination aria-label="Test label" onChange={onChange} defaultPageIndex={1} pageSize={10} totalCount={1000} />,
)
expect(getPages()).toHaveLength(8)
Expand All @@ -367,6 +379,9 @@ describe('Table.Pagination', () => {
expect(onChange).toHaveBeenCalledWith({
pageIndex: 0,
})
// Unmount before restoring to prevent late async callbacks
unmount()
spy.mockRestore()
})

it('when rendering 3 pages and the second page is selected we should render a page number not ...', async () => {
Expand Down
4 changes: 3 additions & 1 deletion packages/react/src/TooltipV2/__tests__/Tooltip.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type React from 'react'
import {describe, expect, it} from 'vitest'
import {describe, expect, it, vi} from 'vitest'
import type {TooltipProps} from '../Tooltip'
import {Tooltip} from '../Tooltip'
import {render as HTMLRender} from '@testing-library/react'
Expand Down Expand Up @@ -125,6 +125,7 @@ describe('Tooltip', () => {
expect(triggerEL.getAttribute('aria-describedby')).toContain('custom-tooltip-id')
})
it('should throw an error if the trigger element is disabled', () => {
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
expect(() => {
HTMLRender(
<Tooltip text="Tooltip text" direction="n">
Expand All @@ -134,6 +135,7 @@ describe('Tooltip', () => {
}).toThrow(
'The `Tooltip` component expects a single React element that contains interactive content. Consider using a `<button>` or equivalent interactive element instead.',
)
spy.mockRestore()
})
it('should not throw an error when the trigger element is a button in a fieldset', () => {
const {getByRole} = HTMLRender(
Expand Down
17 changes: 15 additions & 2 deletions packages/react/src/TreeView/TreeView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1466,6 +1466,8 @@ describe('Asynchronous loading', () => {
})

it('moves focus from loading item to first child', async () => {
// Suppress act warnings from async state updates in the Announce component
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
function TestTree() {
const [state, setState] = React.useState<SubTreeState>('loading')

Expand All @@ -1487,7 +1489,7 @@ describe('Asynchronous loading', () => {
)
}

const {getByRole} = renderWithTheme(<TestTree />)
const {getByRole, unmount} = renderWithTheme(<TestTree />)

const parentItem = getByRole('treeitem', {name: 'Parent'})
const loadingItem = getByRole('treeitem', {name: 'Loading...'})
Expand Down Expand Up @@ -1516,6 +1518,9 @@ describe('Asynchronous loading', () => {

// First child should be focused
expect(firstChild).toHaveFocus()
// Unmount before restoring to prevent late async callbacks
unmount()
spy.mockRestore()
})

it('moves focus to parent item after closing error dialog', async () => {
Expand Down Expand Up @@ -1606,6 +1611,8 @@ describe('Asynchronous loading', () => {
})

it('should update `aria-expanded` if no content is loaded in', async () => {
// Suppress act warnings from async state updates in the Announce component
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
function Example() {
const [state, setState] = React.useState<SubTreeState>('loading')
const timeoutId = React.useRef<ReturnType<typeof setTimeout> | null>(null)
Expand Down Expand Up @@ -1637,7 +1644,7 @@ describe('Asynchronous loading', () => {
</TreeView>
)
}
const {getByLabelText, getByText} = renderWithTheme(<Example />)
const {getByLabelText, getByText, unmount} = renderWithTheme(<Example />)
const user = userEvent.setup()

const treeitem = getByLabelText('Item 1')
Expand All @@ -1654,6 +1661,9 @@ describe('Asynchronous loading', () => {

expect(treeitem).toHaveAttribute('aria-expanded', 'true')
expect(getByLabelText('No items found')).toBeInTheDocument()
// Unmount before restoring to prevent late async callbacks
unmount()
spy.mockRestore()
})

it('should have `aria-expanded` when directory is empty', async () => {
Expand Down Expand Up @@ -1775,6 +1785,8 @@ it('should have keyboard shortcut command as part of accessible name when using
})

it('should activate the dialog for trailing action when keyboard shortcut is used', async () => {
// Suppress act warnings from async state updates
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
userEvent.setup()
render(
<TreeView aria-label="Files changed">
Expand Down Expand Up @@ -1815,4 +1827,5 @@ it('should activate the dialog for trailing action when keyboard shortcut is use
fireEvent.keyDown(treeItem, {key: 'u', metaKey: true, shiftKey: true})

expect(screen.getByRole('dialog')).toBeInTheDocument()
spy.mockRestore()
})
2 changes: 2 additions & 0 deletions packages/react/src/UnderlineNav/UnderlineNav.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ describe('UnderlineNav', () => {
})

it('throws an error when there are multiple items that have aria-current', () => {
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
expect(() => {
render(
<UnderlineNav aria-label="Test Navigation">
Expand All @@ -166,6 +167,7 @@ describe('UnderlineNav', () => {
</UnderlineNav>,
)
}).toThrow('Only one current element is allowed')
spy.mockRestore()
})

it('should support icons passed in as an element', () => {
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/UnderlineNav/UnderlineNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@
counter,
'aria-current': ariaCurrent,
onSelect,
leadingVisual,

Check failure on line 376 in packages/react/src/UnderlineNav/UnderlineNav.tsx

View workflow job for this annotation

GitHub Actions / lint

'leadingVisual' is assigned a value but never used
icon,

Check failure on line 377 in packages/react/src/UnderlineNav/UnderlineNav.tsx

View workflow job for this annotation

GitHub Actions / lint

'icon' is assigned a value but never used
...menuItemProps
} = menuItem.props

Expand Down
Loading
Loading