Skip to content

Commit 7cb7e5b

Browse files
committed
tests
1 parent b9e7d51 commit 7cb7e5b

7 files changed

Lines changed: 206 additions & 24 deletions

File tree

docs/pages/experiments/material-ui/floating-autocomplete.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ function KeepMountedDemo() {
182182
sx={{ width: 300 }}
183183
slots={{ popper: FloatingPopup }}
184184
slotProps={{
185-
popper: { keepMounted: true } as any,
185+
popper: { keepMounted: true },
186186
}}
187187
renderInput={(params) => <TextField {...params} label="Movie" />}
188188
/>

docs/pages/experiments/material-ui/floating-tooltip.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ function OffsetDemo() {
111111
slotProps={{
112112
popper: {
113113
middleware: [offset(offsetVal), flip(), shift()],
114-
} as any,
114+
},
115115
}}
116116
>
117117
<Button variant="outlined">Hover me</Button>
@@ -158,7 +158,7 @@ function AutoPlacementDemo() {
158158
popper: {
159159
middleware,
160160
disablePortal: true,
161-
} as any,
161+
},
162162
}}
163163
>
164164
<Button variant="outlined">Hover after scrolling</Button>
@@ -192,7 +192,7 @@ function StrategyDemo() {
192192
arrow
193193
slots={{ popper: FloatingPopup }}
194194
slotProps={{
195-
popper: { strategy } as any,
195+
popper: { strategy },
196196
}}
197197
>
198198
<Button variant="outlined">Hover me</Button>
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import * as React from 'react';
2+
import { offset, flip, shift, Middleware } from '@floating-ui/react-dom';
3+
import Autocomplete from '@mui/material/Autocomplete';
4+
import TextField from '@mui/material/TextField';
5+
import FloatingPopup from '@mui/material/FloatingPopup';
6+
7+
// FloatingPopup can be passed as the popper slot
8+
<Autocomplete
9+
options={['one', 'two', 'three']}
10+
slots={{ popper: FloatingPopup }}
11+
renderInput={(params) => <TextField {...params} />}
12+
/>;
13+
14+
// FloatingPopup-specific slotProps compile without `as any`
15+
<Autocomplete
16+
options={['one', 'two', 'three']}
17+
slots={{ popper: FloatingPopup }}
18+
slotProps={{
19+
popper: {
20+
strategy: 'fixed',
21+
middleware: [offset(8), flip(), shift()],
22+
transform: false,
23+
arrowPadding: 4,
24+
},
25+
}}
26+
renderInput={(params) => <TextField {...params} />}
27+
/>;
28+
29+
// Standard Popper props still accepted alongside FloatingPopup props
30+
<Autocomplete
31+
options={['one', 'two', 'three']}
32+
slots={{ popper: FloatingPopup }}
33+
slotProps={{
34+
popper: {
35+
disablePortal: true,
36+
keepMounted: true,
37+
placement: 'bottom-end',
38+
strategy: 'fixed',
39+
},
40+
}}
41+
renderInput={(params) => <TextField {...params} />}
42+
/>;
43+
44+
// Middleware as a variable
45+
const middleware: Middleware[] = [offset(8), flip(), shift()];
46+
<Autocomplete
47+
options={['one', 'two', 'three']}
48+
slots={{ popper: FloatingPopup }}
49+
slotProps={{
50+
popper: { middleware },
51+
}}
52+
renderInput={(params) => <TextField {...params} />}
53+
/>;
54+
55+
// Without FloatingPopup slot — standard Popper slotProps still work
56+
<Autocomplete
57+
options={['one', 'two', 'three']}
58+
slotProps={{
59+
popper: { placement: 'bottom-end' },
60+
}}
61+
renderInput={(params) => <TextField {...params} />}
62+
/>;
63+
64+
// slotProps.popper as a function (ownerState callback form)
65+
<Autocomplete
66+
options={['one', 'two', 'three']}
67+
slots={{ popper: FloatingPopup }}
68+
slotProps={{
69+
popper: () => ({
70+
strategy: 'fixed' as const,
71+
middleware: [offset(8)],
72+
}),
73+
}}
74+
renderInput={(params) => <TextField {...params} />}
75+
/>;

packages/mui-material/src/Autocomplete/Autocomplete.floating.test.tsx

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
import * as React from 'react';
22
import { expect } from 'chai';
33
import { spy } from 'sinon';
4-
import {
5-
createRenderer,
6-
fireEvent,
7-
flushMicrotasks,
8-
screen,
9-
} from '@mui/internal-test-utils';
4+
import { createRenderer, fireEvent, flushMicrotasks, screen } from '@mui/internal-test-utils';
105
import TextField from '@mui/material/TextField';
116
import Autocomplete, { autocompleteClasses as classes } from '@mui/material/Autocomplete';
127
import FloatingPopup from '@mui/material/FloatingPopup';
13-
import type { UserEvent } from '@testing-library/user-event';
148

159
const options = ['Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon'];
1610

@@ -28,7 +22,9 @@ function checkHighlightIs(listbox: HTMLElement, expected: string | null) {
2822
* FloatingPopup's async computePosition completes and visibility:hidden
2923
* is removed (making the popup accessible to getByRole).
3024
*/
31-
async function openAutocomplete(user: UserEvent) {
25+
async function openAutocomplete(
26+
user: ReturnType<ReturnType<typeof createRenderer>['render']>['user'],
27+
) {
3228
const input = screen.getByRole('combobox');
3329
await user.click(input);
3430
await flushMicrotasks();
@@ -176,7 +172,7 @@ describe('<Autocomplete slots={{ popper: FloatingPopup }} />', () => {
176172
const input = await openAutocomplete(user);
177173
await user.keyboard('{ArrowDown}');
178174
const firstOption = screen.getAllByRole('option')[0];
179-
expect(input).to.have.attribute('aria-activedescendant', firstOption.getAttribute('id'));
175+
expect(input).to.have.attribute('aria-activedescendant', firstOption.id);
180176
});
181177

182178
it('should clear input on blur when no option is selected', async () => {
@@ -365,7 +361,7 @@ describe('<Autocomplete slots={{ popper: FloatingPopup }} />', () => {
365361
const { user } = renderAutocomplete();
366362
const input = await openAutocomplete(user);
367363
const listbox = screen.getByRole('listbox');
368-
expect(input).to.have.attribute('aria-controls', listbox.getAttribute('id'));
364+
expect(input).to.have.attribute('aria-controls', listbox.id);
369365
});
370366

371367
it('should have role="presentation" on the popup container', async () => {
@@ -559,7 +555,7 @@ describe('<Autocomplete slots={{ popper: FloatingPopup }} />', () => {
559555
describe('slotProps.popper', () => {
560556
it('should forward keepMounted to FloatingPopup', () => {
561557
renderAutocomplete({
562-
slotProps: { popper: { keepMounted: true } as any },
558+
slotProps: { popper: { keepMounted: true } },
563559
});
564560
// Closed — floating element in DOM but with visibility:hidden (FOUC guard)
565561
const floating = document.querySelector('[data-popper-placement]');
@@ -568,7 +564,7 @@ describe('<Autocomplete slots={{ popper: FloatingPopup }} />', () => {
568564

569565
it('should forward data attributes to the floating element', async () => {
570566
const { user } = renderAutocomplete({
571-
slotProps: { popper: { 'data-testid': 'custom-popup' } as any },
567+
slotProps: { popper: { 'data-testid': 'custom-popup' } },
572568
});
573569
await openAutocomplete(user);
574570
expect(screen.getByTestId('custom-popup')).not.to.equal(null);
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import * as React from 'react';
2+
import { offset, flip, shift, Middleware } from '@floating-ui/react-dom';
3+
import Tooltip from '@mui/material/Tooltip';
4+
import FloatingPopup from '@mui/material/FloatingPopup';
5+
6+
// FloatingPopup can be passed as the popper slot
7+
<Tooltip title="Hello" slots={{ popper: FloatingPopup }}>
8+
<button type="button">Hover</button>
9+
</Tooltip>;
10+
11+
// FloatingPopup-specific slotProps compile without `as any`
12+
<Tooltip
13+
title="Hello"
14+
slots={{ popper: FloatingPopup }}
15+
slotProps={{
16+
popper: {
17+
strategy: 'fixed',
18+
middleware: [offset(8), flip(), shift()],
19+
transform: false,
20+
arrowPadding: 8,
21+
},
22+
}}
23+
>
24+
<button type="button">Hover</button>
25+
</Tooltip>;
26+
27+
// Arrow + FloatingPopup-specific props
28+
<Tooltip
29+
title="Hello"
30+
arrow
31+
slots={{ popper: FloatingPopup }}
32+
slotProps={{
33+
popper: {
34+
arrowPadding: 4,
35+
strategy: 'fixed',
36+
},
37+
}}
38+
>
39+
<button type="button">Hover</button>
40+
</Tooltip>;
41+
42+
// Standard Popper props still accepted alongside FloatingPopup props
43+
<Tooltip
44+
title="Hello"
45+
slots={{ popper: FloatingPopup }}
46+
slotProps={{
47+
popper: {
48+
disablePortal: true,
49+
keepMounted: true,
50+
placement: 'top-start',
51+
strategy: 'fixed',
52+
middleware: [offset(12)],
53+
},
54+
}}
55+
>
56+
<button type="button">Hover</button>
57+
</Tooltip>;
58+
59+
// Middleware as a variable
60+
const middleware: Middleware[] = [offset(8), flip(), shift()];
61+
<Tooltip
62+
title="Hello"
63+
slots={{ popper: FloatingPopup }}
64+
slotProps={{
65+
popper: { middleware },
66+
}}
67+
>
68+
<button type="button">Hover</button>
69+
</Tooltip>;
70+
71+
// Without FloatingPopup slot — standard Popper slotProps still work
72+
<Tooltip
73+
title="Hello"
74+
slotProps={{
75+
popper: { placement: 'bottom-end' },
76+
}}
77+
>
78+
<button type="button">Hover</button>
79+
</Tooltip>;
80+
81+
// slotProps.popper as a function (ownerState callback form)
82+
<Tooltip
83+
title="Hello"
84+
slots={{ popper: FloatingPopup }}
85+
slotProps={{
86+
popper: () => ({
87+
strategy: 'fixed' as const,
88+
middleware: [offset(8)],
89+
}),
90+
}}
91+
>
92+
<button type="button">Hover</button>
93+
</Tooltip>;
94+
95+
// All slot overrides together
96+
<Tooltip
97+
title="Hello"
98+
arrow
99+
slots={{ popper: FloatingPopup }}
100+
slotProps={{
101+
popper: {
102+
strategy: 'absolute',
103+
transform: true,
104+
arrowPadding: 2,
105+
middleware: [offset(4), flip(), shift()],
106+
},
107+
tooltip: { sx: { maxWidth: 'none' } },
108+
}}
109+
>
110+
<button type="button">Hover</button>
111+
</Tooltip>;

packages/mui-material/src/Tooltip/Tooltip.floating.test.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ describe('<Tooltip slots={{ popper: FloatingPopup }} />', () => {
415415
title="Persistent"
416416
open={false}
417417
slots={{ popper: FloatingPopup }}
418-
slotProps={{ popper: { keepMounted: true } as any }}
418+
slotProps={{ popper: { keepMounted: true } }}
419419
>
420420
<button>Trigger</button>
421421
</Tooltip>,
@@ -429,7 +429,7 @@ describe('<Tooltip slots={{ popper: FloatingPopup }} />', () => {
429429
title="Hidden persistent"
430430
open={false}
431431
slots={{ popper: FloatingPopup }}
432-
slotProps={{ popper: { keepMounted: true } as any }}
432+
slotProps={{ popper: { keepMounted: true } }}
433433
>
434434
<button>Trigger</button>
435435
</Tooltip>,
@@ -450,7 +450,7 @@ describe('<Tooltip slots={{ popper: FloatingPopup }} />', () => {
450450
title="Data attr"
451451
open
452452
slots={{ popper: FloatingPopup }}
453-
slotProps={{ popper: { 'data-testid': 'my-popper' } as any }}
453+
slotProps={{ popper: { 'data-testid': 'my-popper' } as Record<string, unknown> }}
454454
>
455455
<button>Trigger</button>
456456
</Tooltip>,
@@ -464,7 +464,7 @@ describe('<Tooltip slots={{ popper: FloatingPopup }} />', () => {
464464
title="Fixed strategy"
465465
open
466466
slots={{ popper: FloatingPopup }}
467-
slotProps={{ popper: { strategy: 'fixed' } as any }}
467+
slotProps={{ popper: { strategy: 'fixed' } }}
468468
>
469469
<button>Trigger</button>
470470
</Tooltip>,
@@ -583,7 +583,7 @@ describe('<Tooltip slots={{ popper: FloatingPopup }} />', () => {
583583
title="Inline"
584584
open
585585
slots={{ popper: FloatingPopup }}
586-
slotProps={{ popper: { disablePortal: true } as any }}
586+
slotProps={{ popper: { disablePortal: true } }}
587587
>
588588
<button>Trigger</button>
589589
</Tooltip>,
@@ -644,7 +644,7 @@ describe('<Tooltip slots={{ popper: FloatingPopup }} />', () => {
644644
title="With middleware"
645645
open
646646
slots={{ popper: FloatingPopup }}
647-
slotProps={{ popper: { middleware: [offset(20)] } as any }}
647+
slotProps={{ popper: { middleware: [offset(20)] } }}
648648
>
649649
<button>Trigger</button>
650650
</Tooltip>,
@@ -665,7 +665,7 @@ describe('<Tooltip slots={{ popper: FloatingPopup }} />', () => {
665665
open
666666
arrow
667667
slots={{ popper: FloatingPopup }}
668-
slotProps={{ popper: { middleware: [offset(12)] } as any }}
668+
slotProps={{ popper: { middleware: [offset(12)] } }}
669669
>
670670
<button>Trigger</button>
671671
</Tooltip>,

packages/mui-material/src/Tooltip/Tooltip.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ const Tooltip = React.forwardRef(function Tooltip(inProps, ref) {
758758
role="tooltip"
759759
popperOptions={popperOptions}
760760
arrowRef={arrowRef}
761-
arrowPadding={4}
761+
arrowPadding={popperSlotProps.arrowPadding ?? 4}
762762
>
763763
{({ TransitionProps: TransitionPropsInner }) => (
764764
<TransitionSlot

0 commit comments

Comments
 (0)