Skip to content

Commit 85d2847

Browse files
committed
feat(AnimationsProvider): update tests, set config to required, rename prop to hasAnimationsProp to match existing conventions
1 parent 751cb84 commit 85d2847

14 files changed

Lines changed: 199 additions & 318 deletions

File tree

packages/react-core/src/components/Alert/AlertGroup.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export interface AlertGroupProps extends Omit<React.HTMLProps<HTMLUListElement>,
3030
export const AlertGroup: React.FunctionComponent<AlertGroupProps> = ({
3131
className,
3232
children,
33-
hasAnimations: localHasAnimations,
33+
hasAnimations: hasAnimationsProp,
3434
isToast,
3535
isLiveRegion,
3636
onOverflowClick,
@@ -42,7 +42,7 @@ export const AlertGroup: React.FunctionComponent<AlertGroupProps> = ({
4242
}: AlertGroupProps) => {
4343
const containerRef = useRef<HTMLElement | null>(null);
4444
const [isContainerReady, setIsContainerReady] = useState(false);
45-
const hasAnimations = useHasAnimations(localHasAnimations);
45+
const hasAnimations = useHasAnimations(hasAnimationsProp);
4646

4747
const getTargetElement = () => {
4848
if (typeof appendTo === 'function') {

packages/react-core/src/components/Alert/AlertGroupInline.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import { useHasAnimations } from '../../helpers';
99
export const AlertGroupInline: React.FunctionComponent<AlertGroupProps> = ({
1010
className,
1111
children,
12-
hasAnimations: localHasAnimations,
12+
hasAnimations: hasAnimationsProp,
1313
isToast,
1414
isLiveRegion,
1515
onOverflowClick,
1616
overflowMessage,
1717
...props
1818
}: AlertGroupProps) => {
19-
const hasAnimations = useHasAnimations(localHasAnimations);
19+
const hasAnimations = useHasAnimations(hasAnimationsProp);
2020
const [handleTransitionEnd, setHandleTransitionEnd] = useState<() => void>(() => () => {});
2121

2222
const updateTransitionEnd = (onTransitionEnd: () => void) => {

packages/react-core/src/components/Alert/__tests__/AlertGroup.test.tsx

Lines changed: 38 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ test('Calls the callback set by updateTransitionEnd when transition ends and ani
9696
const closeButton = await screen.findByLabelText('Close');
9797
await user.click(closeButton);
9898
expect(mockCallback).not.toHaveBeenCalled();
99+
// fireEvent is needed here because transitionEnd is a browser event that occurs automatically
100+
// when CSS transitions complete, not a user interaction that userEvent can simulate
99101
fireEvent.transitionEnd(screen.getByText('Test Alert').closest('.pf-v6-c-alert-group__item') as HTMLElement);
100102
expect(mockCallback).toHaveBeenCalled();
101103
});
@@ -128,99 +130,50 @@ test('Does not call the callback set by updateTransitionEnd when transition ends
128130
await user.click(closeButton);
129131
expect(mockCallback).toHaveBeenCalledTimes(1);
130132
// The transitionend event firing should not cause the callback to be called again
133+
// fireEvent is needed here because transitionEnd is a browser event that occurs automatically
134+
// when CSS transitions complete, not a user interaction that userEvent can simulate
131135
fireEvent.transitionEnd(screen.getByText('Test Alert').closest('.pf-v6-c-alert-group__item') as HTMLElement);
132136
expect(mockCallback).toHaveBeenCalledTimes(1);
133137
});
134138

135-
// Animation context tests
136-
test('respects AnimationsProvider context when no local hasAnimations prop', () => {
137-
const mockCallback = jest.fn();
138-
139-
render(
140-
<AnimationsProvider config={{ hasAnimations: true }}>
141-
<AlertGroup isToast appendTo={document.body}>
142-
<Alert
143-
isLiveRegion
144-
title={'Test Alert'}
145-
actionClose={<AlertActionCloseButton aria-label="Close" onClose={mockCallback} />}
146-
/>
147-
</AlertGroup>
148-
</AnimationsProvider>
149-
);
150-
151-
const closeButton = screen.getByLabelText('Close');
152-
fireEvent.click(closeButton);
153-
expect(mockCallback).not.toHaveBeenCalled();
154-
155-
// Should call callback on transition end when animations are enabled via context
156-
fireEvent.transitionEnd(screen.getByText('Test Alert').closest('.pf-v6-c-alert-group__item') as HTMLElement);
157-
expect(mockCallback).toHaveBeenCalled();
158-
});
159-
160-
test('local hasAnimations prop takes precedence over context', () => {
161-
window.matchMedia = (query) => ({
162-
matches: false,
163-
media: query,
164-
onchange: null,
165-
addListener: () => {}, // deprecated
166-
removeListener: () => {}, // deprecated
167-
addEventListener: () => {},
168-
removeEventListener: () => {},
169-
dispatchEvent: () => true
139+
describe('Animation context behavior', () => {
140+
test('respects AnimationsProvider context when no local hasAnimations prop', () => {
141+
render(
142+
<AnimationsProvider config={{ hasAnimations: true }}>
143+
<AlertGroup>
144+
<Alert title="Test Alert" />
145+
</AlertGroup>
146+
</AnimationsProvider>
147+
);
148+
149+
// Should apply animation class when animations are enabled via context
150+
const alertGroupItem = screen.getByText('Test Alert').closest('.pf-v6-c-alert-group__item');
151+
expect(alertGroupItem).toHaveClass('pf-m-offstage-top');
170152
});
171153

172-
const mockCallback = jest.fn();
154+
test('local hasAnimations prop takes precedence over context', () => {
155+
render(
156+
<AnimationsProvider config={{ hasAnimations: true }}>
157+
<AlertGroup hasAnimations={false}>
158+
<Alert title="Test Alert" />
159+
</AlertGroup>
160+
</AnimationsProvider>
161+
);
162+
163+
// Should not apply animation class when local hasAnimations=false overrides context
164+
const alertGroupItem = screen.getByText('Test Alert').closest('.pf-v6-c-alert-group__item');
165+
expect(alertGroupItem).not.toHaveClass('pf-m-offstage-top');
166+
});
173167

174-
render(
175-
<AnimationsProvider config={{ hasAnimations: true }}>
176-
<AlertGroup hasAnimations={false} isToast appendTo={document.body}>
177-
<Alert
178-
isLiveRegion
179-
title={'Test Alert'}
180-
actionClose={<AlertActionCloseButton aria-label="Close" onClose={mockCallback} />}
181-
/>
168+
test('works without AnimationsProvider (backward compatibility)', () => {
169+
render(
170+
<AlertGroup>
171+
<Alert title="Test Alert" />
182172
</AlertGroup>
183-
</AnimationsProvider>
184-
);
173+
);
185174

186-
const closeButton = screen.getByLabelText('Close');
187-
fireEvent.click(closeButton);
188-
expect(mockCallback).toHaveBeenCalledTimes(1);
189-
190-
// Should not call callback again on transition end when local hasAnimations=false overrides context
191-
fireEvent.transitionEnd(screen.getByText('Test Alert').closest('.pf-v6-c-alert-group__item') as HTMLElement);
192-
expect(mockCallback).toHaveBeenCalledTimes(1);
193-
});
194-
195-
test('works without AnimationsProvider (backward compatibility)', () => {
196-
window.matchMedia = (query) => ({
197-
matches: false,
198-
media: query,
199-
onchange: null,
200-
addListener: () => {}, // deprecated
201-
removeListener: () => {}, // deprecated
202-
addEventListener: () => {},
203-
removeEventListener: () => {},
204-
dispatchEvent: () => true
175+
// Should not apply animation class when no context and no local hasAnimations
176+
const alertGroupItem = screen.getByText('Test Alert').closest('.pf-v6-c-alert-group__item');
177+
expect(alertGroupItem).not.toHaveClass('pf-m-offstage-top');
205178
});
206-
207-
const mockCallback = jest.fn();
208-
209-
render(
210-
<AlertGroup isToast appendTo={document.body}>
211-
<Alert
212-
isLiveRegion
213-
title={'Test Alert'}
214-
actionClose={<AlertActionCloseButton aria-label="Close" onClose={mockCallback} />}
215-
/>
216-
</AlertGroup>
217-
);
218-
219-
const closeButton = screen.getByLabelText('Close');
220-
fireEvent.click(closeButton);
221-
expect(mockCallback).toHaveBeenCalledTimes(1);
222-
223-
// Should not call callback again on transition end when no context and no local hasAnimations
224-
fireEvent.transitionEnd(screen.getByText('Test Alert').closest('.pf-v6-c-alert-group__item') as HTMLElement);
225-
expect(mockCallback).toHaveBeenCalledTimes(1);
226179
});

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ export const DualListSelector: React.FunctionComponent<DualListSelectorProps> =
2929
children,
3030
id,
3131
isTree = false,
32-
hasAnimations: localHasAnimations,
32+
hasAnimations: hasAnimationsProp,
3333
...props
3434
}: DualListSelectorProps) => {
35-
const hasAnimations = useHasAnimations(localHasAnimations);
35+
const hasAnimations = useHasAnimations(hasAnimationsProp);
3636

3737
return (
3838
<DualListSelectorContext.Provider value={{ isTree, hasAnimations }}>

packages/react-core/src/components/DualListSelector/DualListSelectorTreeItem.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,15 @@ const DualListSelectorTreeItemBase: React.FunctionComponent<DualListSelectorTree
5959
badgeProps,
6060
itemData,
6161
isDisabled = false,
62-
hasAnimations: localHasAnimations,
62+
hasAnimations: hasAnimationsProp,
6363
// eslint-disable-next-line @typescript-eslint/no-unused-vars
6464
useMemo,
6565
...props
6666
}: DualListSelectorTreeItemProps) => {
6767
const ref = useRef(null);
6868
const [isExpanded, setIsExpanded] = useState(defaultExpanded || false);
6969
const { setFocusedOption } = useContext(DualListSelectorListContext);
70-
const hasAnimations = useHasAnimations(localHasAnimations);
70+
const hasAnimations = useHasAnimations(hasAnimationsProp);
7171

7272
useEffect(() => {
7373
setIsExpanded(defaultExpanded);

packages/react-core/src/components/Form/FormFieldGroupExpandable.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ export const FormFieldGroupExpandable: React.FunctionComponent<FormFieldGroupExp
2626
header,
2727
isExpanded = false,
2828
toggleAriaLabel,
29-
hasAnimations: localHasAnimations,
29+
hasAnimations: hasAnimationsProp,
3030
...props
3131
}: FormFieldGroupExpandableProps) => {
3232
const [localIsExpanded, setIsExpanded] = useState(isExpanded);
33-
const hasAnimations = useHasAnimations(localHasAnimations);
33+
const hasAnimations = useHasAnimations(hasAnimationsProp);
3434

3535
return (
3636
<InternalFormFieldGroup

packages/react-core/src/components/Form/InternalFormFieldGroup.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ export const InternalFormFieldGroup: React.FunctionComponent<InternalFormFieldGr
3434
isExpanded,
3535
onToggle,
3636
toggleAriaLabel,
37-
hasAnimations: localHasAnimations,
37+
hasAnimations: hasAnimationsProp,
3838
...props
3939
}: InternalFormFieldGroupProps) => {
40-
const hasAnimations = useHasAnimations(localHasAnimations);
40+
const hasAnimations = useHasAnimations(hasAnimationsProp);
4141
const headerTitleText = header ? header.props.titleText : null;
4242
if (isExpandable && !toggleAriaLabel && !headerTitleText) {
4343
// eslint-disable-next-line no-console

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,8 @@ const SearchInputBase: React.FunctionComponent<SearchInputProps> = ({
181181
const popperRef = useRef(null);
182182
const [focusAfterExpandChange, setFocusAfterExpandChange] = useState(false);
183183

184-
const { isExpanded, onToggleExpand, toggleAriaLabel, hasAnimations: localHasAnimations } = expandableInput || {};
185-
const hasAnimations = useHasAnimations(localHasAnimations);
184+
const { isExpanded, onToggleExpand, toggleAriaLabel, hasAnimations: hasAnimationsProp } = expandableInput || {};
185+
const hasAnimations = useHasAnimations(hasAnimationsProp);
186186

187187
useEffect(() => {
188188
// this effect and the focusAfterExpandChange variable are needed to focus the input/toggle as needed when the

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,10 @@ export const TreeView: React.FunctionComponent<TreeViewProps> = ({
136136
useMemo,
137137
'aria-label': ariaLabel,
138138
'aria-labelledby': ariaLabelledby,
139-
hasAnimations: localHasAnimations,
139+
hasAnimations: hasAnimationsProp,
140140
...props
141141
}: TreeViewProps) => {
142-
const hasAnimations = useHasAnimations(localHasAnimations);
142+
const hasAnimations = useHasAnimations(hasAnimationsProp);
143143
const treeViewList = (
144144
<TreeViewList
145145
isNested={isNested}

packages/react-core/src/components/TreeView/TreeViewListItem.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,11 @@ const TreeViewListItemBase: React.FunctionComponent<TreeViewListItemProps> = ({
103103
expandedIcon,
104104
action,
105105
compareItems,
106-
hasAnimations: localHasAnimations,
106+
hasAnimations: hasAnimationsProp,
107107
// eslint-disable-next-line @typescript-eslint/no-unused-vars
108108
useMemo
109109
}: TreeViewListItemProps) => {
110-
const hasAnimations = useHasAnimations(localHasAnimations);
110+
const hasAnimations = useHasAnimations(hasAnimationsProp);
111111
const [internalIsExpanded, setIsExpanded] = useState(defaultExpanded);
112112
useEffect(() => {
113113
if (isExpanded !== undefined && isExpanded !== null) {

0 commit comments

Comments
 (0)