Skip to content

Commit de2ec57

Browse files
mshrivercursoragent
andcommitted
chore(Popover): Include OUIAProps for Popover
Add OUIA attribute support to Popover for better test automation. OUIA attributes are applied to the FocusTrap dialog root. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 8c89c01 commit de2ec57

3 files changed

Lines changed: 55 additions & 4 deletions

File tree

packages/react-core/src/components/Popover/Popover.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ import { PopoverCloseButton } from './PopoverCloseButton';
1111
import { PopoverArrow } from './PopoverArrow';
1212
import popoverMaxWidth from '@patternfly/react-tokens/dist/esm/c_popover_MaxWidth';
1313
import popoverMinWidth from '@patternfly/react-tokens/dist/esm/c_popover_MinWidth';
14-
import { FocusTrap } from '../../helpers';
14+
import { FocusTrap, useSSRSafeId, useOUIAProps, OUIAProps } from '../../helpers';
1515
import { Popper } from '../../helpers/Popper/Popper';
16-
import { useSSRSafeId } from '../../helpers';
1716

1817
export enum PopoverPosition {
1918
auto = 'auto',
@@ -35,7 +34,7 @@ export enum PopoverPosition {
3534
* that has a property specifically for passing in popover properties.
3635
*/
3736

38-
export interface PopoverProps {
37+
export interface PopoverProps extends OUIAProps {
3938
/** Text announced by screen reader when alert severity variant is set to indicate
4039
* severity level.
4140
*/
@@ -211,6 +210,10 @@ export interface PopoverProps {
211210
withFocusTrap?: boolean;
212211
/** The z-index of the popover. */
213212
zIndex?: number;
213+
/** Value to overwrite the randomly generated data-ouia-component-id.*/
214+
ouiaId?: number | string;
215+
/** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */
216+
ouiaSafe?: boolean;
214217
}
215218

216219
const alertStyle = {
@@ -272,12 +275,15 @@ export const Popover: React.FunctionComponent<PopoverProps> = ({
272275
hasNoPadding = false,
273276
hasAutoWidth = false,
274277
elementToFocus,
278+
ouiaId,
279+
ouiaSafe = true,
275280
...rest
276281
}: PopoverProps) => {
277282
// could make this a prop in the future (true | false | 'toggle')
278283
// const hideOnClick = true;
279284
const generatedId = useSSRSafeId();
280285
const uniqueId = id || generatedId;
286+
const ouiaProps = useOUIAProps(Popover.displayName, ouiaId, ouiaSafe);
281287
const triggerManually = isVisible !== null;
282288
const [visible, setVisible] = useState(false);
283289
const [focusTrapActive, setFocusTrapActive] = useState(Boolean(propWithFocusTrap));
@@ -473,6 +479,7 @@ export const Popover: React.FunctionComponent<PopoverProps> = ({
473479
maxWidth: hasCustomMaxWidth ? maxWidth : null
474480
}}
475481
{...rest}
482+
{...ouiaProps}
476483
>
477484
<PopoverArrow />
478485
<PopoverContent>

packages/react-core/src/components/Popover/__tests__/Popover.test.tsx

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { StrictMode } from 'react';
2-
import { render } from '@testing-library/react';
2+
import { render, screen } from '@testing-library/react';
33
import { Popover, PopoverPosition } from '../Popover';
44

55
test('popover renders close-button, header and body', () => {
@@ -9,6 +9,7 @@ test('popover renders close-button, header and body', () => {
99
position="top"
1010
isVisible
1111
hideOnOutsideClick
12+
ouiaId="ouia-id"
1213
headerContent={<div>Popover Header</div>}
1314
bodyContent={
1415
<div>
@@ -114,3 +115,45 @@ test('popover renders in strict mode', () => {
114115
expect(consoleError).not.toHaveBeenCalled();
115116
expect(asFragment()).toMatchSnapshot();
116117
});
118+
119+
test('Renders with custom ouiaId', () => {
120+
render(
121+
<Popover isVisible ouiaId="test-id" headerContent={<div>Popover Header</div>} bodyContent={<div>Popover body</div>}>
122+
<div>Toggle Popover</div>
123+
</Popover>
124+
);
125+
expect(screen.getByRole('dialog')).toHaveAttribute('data-ouia-component-id', 'test-id');
126+
});
127+
128+
test('Renders with expected ouia component type', () => {
129+
render(
130+
<Popover isVisible ouiaId="test-id" headerContent={<div>Popover Header</div>} bodyContent={<div>Popover body</div>}>
131+
<div>Toggle Popover</div>
132+
</Popover>
133+
);
134+
expect(screen.getByRole('dialog')).toHaveAttribute('data-ouia-component-type', 'PF6/Popover');
135+
});
136+
137+
test('Renders with ouiaSafe defaulting to true', () => {
138+
render(
139+
<Popover isVisible ouiaId="test-id" headerContent={<div>Popover Header</div>} bodyContent={<div>Popover body</div>}>
140+
<div>Toggle Popover</div>
141+
</Popover>
142+
);
143+
expect(screen.getByRole('dialog')).toHaveAttribute('data-ouia-safe', 'true');
144+
});
145+
146+
test('Renders with ouiaSafe=false when specified', () => {
147+
render(
148+
<Popover
149+
isVisible
150+
ouiaId="test-id"
151+
ouiaSafe={false}
152+
headerContent={<div>Popover Header</div>}
153+
bodyContent={<div>Popover body</div>}
154+
>
155+
<div>Toggle Popover</div>
156+
</Popover>
157+
);
158+
expect(screen.getByRole('dialog')).toHaveAttribute('data-ouia-safe', 'false');
159+
});

packages/react-core/src/helpers/OUIA/OUIA.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ component.
6666
* [NavExpandable](/components/navigation)
6767
* [NavItem](/components/navigation)
6868
* [Pagination](/components/pagination)
69+
* [Popover](/components/popover)
6970
* [Radio](/components/forms/radio)
7071
* [Select](/components/menus/select)
7172
* [Switch](/components/switch)

0 commit comments

Comments
 (0)