Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[test] Refactor most Pickers test to async #14583

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
db3cf69
[test] Attempt to fix flaky unit tests
LukasTy Sep 11, 2024
175efbd
Revert quickFilter mocking
LukasTy Sep 11, 2024
1c3af22
Co-locate clock restoring
LukasTy Sep 11, 2024
342f461
Update file
LukasTy Sep 11, 2024
e9f81d2
Use CSB build with option to specify `toMock`
LukasTy Sep 13, 2024
e8252f6
Avoid clock faking as much as possible
LukasTy Sep 19, 2024
2930755
Revert "Co-locate clock restoring"
LukasTy Sep 19, 2024
4732879
Revert "Revert quickFilter mocking"
LukasTy Sep 19, 2024
36f38fb
Revert "[test] Attempt to fix flaky unit tests"
LukasTy Sep 19, 2024
0e949a3
Merge remote-tracking branch 'upstream/master' into attempt-fix-flaky…
LukasTy Sep 19, 2024
b0b26cc
Fix ESLint issues
LukasTy Sep 19, 2024
a74304f
Merge remote-tracking branch 'upstream/master' into attempt-fix-flaky…
LukasTy Sep 19, 2024
91b61d3
dedupe
LukasTy Sep 19, 2024
87ba6f0
Cleanup
LukasTy Sep 20, 2024
7d92fe1
Merge remote-tracking branch 'upstream/master' into attempt-fix-flaky…
LukasTy Oct 2, 2024
4d888a8
Fix failing tests
LukasTy Oct 9, 2024
38159ba
Merge branch 'master' into attempt-fix-flaky-unit-tests
LukasTy Oct 9, 2024
7729df6
Fix more tests
LukasTy Oct 9, 2024
34a1e67
Refactor RTL keyboard interaction tests
LukasTy Oct 9, 2024
51b6abf
Refactor new test
LukasTy Oct 9, 2024
a114011
Remove redundant clock faking
LukasTy Oct 9, 2024
2ab60ac
Try fixing tests in browser
LukasTy Oct 10, 2024
526ddc7
Attempt more fixes
LukasTy Oct 11, 2024
3f14057
Merge remote-tracking branch 'upstream/master' into attempt-fix-flaky…
LukasTy Oct 11, 2024
8e7281f
Avoid reliance on real clock when necessary
LukasTy Oct 11, 2024
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
1 change: 1 addition & 0 deletions packages/x-date-pickers-pro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"@emotion/styled": "^11.8.1",
"@mui/material": "^5.15.14 || ^6.0.0",
"@mui/system": "^5.15.14 || ^6.0.0",
"@testing-library/user-event": "^14.5.2",
"date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0",
"date-fns-jalali": "^2.13.0-0 || ^3.2.0-0",
"dayjs": "^1.10.7",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import { spy } from 'sinon';
import { expect } from 'chai';
import { screen, fireEvent, within, fireTouchChangedEvent } from '@mui/internal-test-utils';
import { screen, within, fireTouchChangedEvent } from '@mui/internal-test-utils';
import {
adapterToUse,
buildPickerDragInteractions,
Expand All @@ -17,6 +17,8 @@ import { DateRangePickerDay } from '@mui/x-date-pickers-pro/DateRangePickerDay';
import { describeConformance } from 'test/utils/describeConformance';
import { RangePosition } from '../models';

const isJSDOM = /jsdom/.test(window.navigator.userAgent);

const getPickerDay = (name: string, picker = 'January 2018') =>
within(screen.getByRole('grid', { name: picker })).getByRole('gridcell', { name });

Expand All @@ -28,9 +30,10 @@ const dynamicShouldDisableDate = (date, position: RangePosition) => {
};

describe('<DateRangeCalendar />', () => {
const { render, clock } = createPickerRenderer({
const { render } = createPickerRenderer({
clock: 'fake',
clockConfig: new Date(2018, 0, 10),
clockOptions: { toFake: ['Date'] },
});

describeConformance(<DateRangeCalendar />, () => ({
Expand All @@ -43,26 +46,26 @@ describe('<DateRangeCalendar />', () => {
}));

describe('Selection', () => {
it('should select the range from the next month', () => {
it('should select the range from the next month', async () => {
const onChange = spy();

render(
const { user } = render(
<DateRangeCalendar
onChange={onChange}
defaultValue={[adapterToUse.date('2019-01-01'), null]}
reduceAnimations
/>,
);

fireEvent.click(getPickerDay('1', 'January 2019'));
await user.click(getPickerDay('1', 'January 2019'));

// FIXME use `getByRole(role, {hidden: false})` and skip JSDOM once this suite can run in JSDOM
const [visibleButton] = screen.getAllByRole('button', {
hidden: true,
name: 'Next month',
});
fireEvent.click(visibleButton);
clock.runToLast();
fireEvent.click(getPickerDay('19', 'March 2019'));
await user.click(visibleButton);
await user.click(getPickerDay('19', 'March 2019'));

expect(onChange.callCount).to.equal(2);

Expand All @@ -75,19 +78,19 @@ describe('<DateRangeCalendar />', () => {
expect(rangeOn2ndCall[1]).to.toEqualDateTime(new Date(2019, 2, 19));
});

it('should continue start selection if selected "end" date is before start', () => {
it('should continue start selection if selected "end" date is before start', async () => {
const onChange = spy();

render(
const { user } = render(
<DateRangeCalendar onChange={onChange} referenceDate={adapterToUse.date('2019-01-01')} />,
);

fireEvent.click(getPickerDay('30', 'January 2019'));
fireEvent.click(getPickerDay('19', 'January 2019'));
await user.click(getPickerDay('30', 'January 2019'));
await user.click(getPickerDay('19', 'January 2019'));

expect(screen.queryByTestId('DateRangeHighlight')).to.equal(null);

fireEvent.click(getPickerDay('30', 'January 2019'));
await user.click(getPickerDay('30', 'January 2019'));

expect(onChange.callCount).to.equal(3);
const range = onChange.lastCall.firstArg;
Expand Down Expand Up @@ -449,42 +452,42 @@ describe('<DateRangeCalendar />', () => {
});

describe('prop: disableAutoMonthSwitching', () => {
it('should go to the month of the end date when changing the start date', () => {
render(
it('should go to the month of the end date when changing the start date', async () => {
const { user } = render(
<DateRangeCalendar
defaultValue={[adapterToUse.date('2018-01-01'), adapterToUse.date('2018-07-01')]}
reduceAnimations
/>,
);

fireEvent.click(getPickerDay('5', 'January 2018'));
clock.runToLast();
await user.click(getPickerDay('5', 'January 2018'));
expect(getPickerDay('1', 'July 2018')).not.to.equal(null);
});

it('should not go to the month of the end date when changing the start date and props.disableAutoMonthSwitching = true', () => {
render(
it('should not go to the month of the end date when changing the start date and props.disableAutoMonthSwitching = true', async () => {
const { user } = render(
<DateRangeCalendar
defaultValue={[adapterToUse.date('2018-01-01'), adapterToUse.date('2018-07-01')]}
disableAutoMonthSwitching
reduceAnimations
/>,
);

fireEvent.click(getPickerDay('5', 'January 2018'));
clock.runToLast();
await user.click(getPickerDay('5', 'January 2018'));
expect(getPickerDay('1', 'January 2018')).not.to.equal(null);
});

it('should go to the month of the start date when changing both date from the outside', () => {
const { setProps } = render(
<DateRangeCalendar
value={[adapterToUse.date('2018-01-01'), adapterToUse.date('2018-07-01')]}
reduceAnimations
/>,
);

setProps({
value: [adapterToUse.date('2018-04-01'), adapterToUse.date('2018-04-01')],
});
clock.runToLast();
expect(getPickerDay('1', 'April 2018')).not.to.equal(null);
});

Expand All @@ -494,22 +497,22 @@ describe('<DateRangeCalendar />', () => {
<DateRangeCalendar
value={[adapterToUse.date('2018-01-10'), adapterToUse.date('2018-01-15')]}
currentMonthCalendarPosition={2}
reduceAnimations
/>,
);

setProps({
value: [adapterToUse.date('2018-02-11'), adapterToUse.date('2018-02-22')],
});
clock.runToLast();
expect(getPickerDay('1', 'February 2018')).not.to.equal(null);
});
});
});

['readOnly', 'disabled'].forEach((prop) => {
it(`prop: ${prop}="true" should not allow date editing`, () => {
it(`prop: ${prop}="true" should not allow date editing`, async () => {
const handleChange = spy();
render(
const { user } = render(
<DateRangeCalendar
value={[adapterToUse.date('2018-01-01'), adapterToUse.date('2018-01-10')]}
onChange={handleChange}
Expand All @@ -527,7 +530,8 @@ describe('<DateRangeCalendar />', () => {
'disabled',
);
}
fireEvent.click(getPickerDay('2'));
// without `pointerEventsCheck` it would fail to click on browser
await user.setup({ pointerEventsCheck: 0 }).click(getPickerDay('2'));
expect(handleChange.callCount).to.equal(0);
});
});
Expand All @@ -539,10 +543,10 @@ describe('<DateRangeCalendar />', () => {
});

describe('Performance', () => {
it('should only render the new start day when selecting a start day without a previously selected start day', () => {
it('should only render the new start day when selecting a start day without a previously selected start day', async () => {
const RenderCount = spy((props) => <DateRangePickerDay {...props} />);

render(
const { user } = render(
<DateRangeCalendar
slots={{
day: React.memo(RenderCount),
Expand All @@ -551,26 +555,27 @@ describe('<DateRangeCalendar />', () => {
);

const renderCountBeforeChange = RenderCount.callCount;
fireEvent.click(getPickerDay('2'));
expect(RenderCount.callCount - renderCountBeforeChange).to.equal(2); // 2 render * 1 day
await user.click(getPickerDay('2'));
expect(RenderCount.callCount - renderCountBeforeChange).to.equal(6);
});

it('should only render the day inside range when selecting the end day', () => {
it('should only render the day inside range when selecting the end day', async () => {
const RenderCount = spy((props) => <DateRangePickerDay {...props} />);

render(
const { user } = render(
<DateRangeCalendar
slots={{
day: React.memo(RenderCount),
}}
/>,
);

fireEvent.click(getPickerDay('2'));
await user.click(getPickerDay('2'));

const renderCountBeforeChange = RenderCount.callCount;
fireEvent.click(getPickerDay('4'));
expect(RenderCount.callCount - renderCountBeforeChange).to.equal(6); // 2 render * 3 day
await user.click(getPickerDay('4'));
// 10 days in unit tests, 18 days in browser
expect(RenderCount.callCount - renderCountBeforeChange).to.equal(isJSDOM ? 10 : 18);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';
import { fireEvent, screen } from '@mui/internal-test-utils/createRenderer';
import { screen } from '@mui/internal-test-utils/createRenderer';
import { expect } from 'chai';
import {
buildFieldInteractions,
Expand All @@ -10,44 +10,38 @@ import {
} from 'test/utils/pickers';

describe('<DateRangePicker />', () => {
const { render, clock } = createPickerRenderer({
clock: 'fake',
clockConfig: new Date(2018, 0, 1, 0, 0, 0, 0),
});
const { render, clock } = createPickerRenderer();

const { renderWithProps } = buildFieldInteractions({
render,
clock,
Component: DateRangePicker,
});

it('should not open mobile picker dialog when clicked on input', () => {
it('should not open mobile picker dialog when clicked on input', async () => {
// Test with v7 input
const { unmount } = renderWithProps({ enableAccessibleFieldDOMStructure: true });
fireEvent.click(getFieldInputRoot());
clock.runToLast();
let view = renderWithProps({ enableAccessibleFieldDOMStructure: true });
await view.user.click(getFieldInputRoot());

expect(screen.queryByRole('tooltip')).not.to.equal(null);
expect(screen.queryByRole('dialog')).to.equal(null);

unmount();
view.unmount();

// Test with v6 input
renderWithProps({ enableAccessibleFieldDOMStructure: false });
fireEvent.click(screen.getAllByRole('textbox')[0]);
clock.runToLast();
view = renderWithProps({ enableAccessibleFieldDOMStructure: false });
await view.user.click(screen.getAllByRole('textbox')[0]);

expect(screen.queryByRole('tooltip')).not.to.equal(null);
expect(screen.queryByRole('dialog')).to.equal(null);
});

it('should open mobile picker dialog when clicked on input when `useMediaQuery` returns `false`', () => {
it('should open mobile picker dialog when clicked on input when `useMediaQuery` returns `false`', async () => {
const originalMatchMedia = window.matchMedia;
window.matchMedia = stubMatchMedia(false);

render(<DateRangePicker enableAccessibleFieldDOMStructure />);
fireEvent.click(getFieldInputRoot());
clock.runToLast();
const { user } = render(<DateRangePicker enableAccessibleFieldDOMStructure />);
await user.click(getFieldInputRoot());

expect(screen.getByRole('dialog')).not.to.equal(null);
expect(screen.queryByRole('tooltip')).to.equal(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { createPickerRenderer } from 'test/utils/pickers';
import { describeConformance } from 'test/utils/describeConformance';

describe('<DateRangePicker /> - Describes', () => {
const { render } = createPickerRenderer({ clock: 'fake' });
const { render } = createPickerRenderer();

describeConformance(<DateRangePicker />, () => ({
classes: {} as any,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { describeConformance } from 'test/utils/describeConformance';
import { DateTimeRangePicker } from '../DateTimeRangePicker';

describe('<DateTimeRangePicker /> - Describes', () => {
const { render } = createPickerRenderer({ clock: 'fake' });
const { render } = createPickerRenderer();

describeConformance(<DateTimeRangePicker />, () => ({
classes: {} as any,
Expand Down
Loading
Loading