From 24f9556134050a115836dcaddbd2377d3e9c8ebd Mon Sep 17 00:00:00 2001 From: afc163 Date: Thu, 18 Aug 2022 11:36:09 +0800 Subject: [PATCH 01/18] style: use @checkbox-border-radius (#37131) --- components/checkbox/style/mixin.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/checkbox/style/mixin.less b/components/checkbox/style/mixin.less index ae4a39d949..3d7c0336ed 100644 --- a/components/checkbox/style/mixin.less +++ b/components/checkbox/style/mixin.less @@ -26,7 +26,7 @@ width: 100%; height: 100%; border: 1px solid @checkbox-color; - border-radius: @border-radius-base; + border-radius: @checkbox-border-radius; visibility: hidden; animation: antCheckboxEffect 0.36s ease-in-out; animation-fill-mode: backwards; From 8010cd19b6b3955d29dfc101bfd506e24ed5a07f Mon Sep 17 00:00:00 2001 From: lijianan <574980606@qq.com> Date: Thu, 18 Aug 2022 17:40:47 +0800 Subject: [PATCH 02/18] test: migrate part of DatePicker tests (#37115) * test: migrate part of DatePicker tests * test: migrate part of DatePicker tests * fix: update snap * test: migrate part of DatePicker tests * test: migrate part of DatePicker tests * test: migrate part of DatePicker tests * test: migrate part of DatePicker tests * test: migrate part of DatePicker tests * test: migrate part of DatePicker tests * test: remove useless methods * test: add test ignore --- .../{locale.test.js => locale.test.tsx} | 113 ++++---- .../date-picker/__tests__/DatePicker.test.js | 234 --------------- .../date-picker/__tests__/DatePicker.test.tsx | 268 ++++++++++++++++++ ...rPicker.test.js => QuarterPicker.test.tsx} | 6 +- .../date-picker/__tests__/RangePicker.test.js | 104 ------- .../__tests__/RangePicker.test.tsx | 115 ++++++++ ...WeekPicker.test.js => WeekPicker.test.tsx} | 7 +- ....test.js.snap => DatePicker.test.tsx.snap} | 0 ...st.js.snap => QuarterPicker.test.tsx.snap} | 0 ...test.js.snap => RangePicker.test.tsx.snap} | 0 ....test.js.snap => WeekPicker.test.tsx.snap} | 0 .../{demo.test.js.snap => demo.test.ts.snap} | 0 ...{mount.test.js.snap => mount.test.ts.snap} | 0 ...other.test.js.snap => other.test.tsx.snap} | 8 +- .../__tests__/{demo.test.js => demo.test.ts} | 0 .../{mount.test.js => mount.test.ts} | 0 .../{other.test.js => other.test.tsx} | 32 +-- components/date-picker/__tests__/utils.js | 58 ---- components/date-picker/__tests__/utils.ts | 27 ++ components/date-picker/util.ts | 16 +- .../table/__tests__/Table.expand.test.js | 2 +- 21 files changed, 499 insertions(+), 491 deletions(-) rename components/config-provider/__tests__/{locale.test.js => locale.test.tsx} (50%) delete mode 100644 components/date-picker/__tests__/DatePicker.test.js create mode 100644 components/date-picker/__tests__/DatePicker.test.tsx rename components/date-picker/__tests__/{QuarterPicker.test.js => QuarterPicker.test.tsx} (74%) delete mode 100644 components/date-picker/__tests__/RangePicker.test.js create mode 100644 components/date-picker/__tests__/RangePicker.test.tsx rename components/date-picker/__tests__/{WeekPicker.test.js => WeekPicker.test.tsx} (63%) rename components/date-picker/__tests__/__snapshots__/{DatePicker.test.js.snap => DatePicker.test.tsx.snap} (100%) rename components/date-picker/__tests__/__snapshots__/{QuarterPicker.test.js.snap => QuarterPicker.test.tsx.snap} (100%) rename components/date-picker/__tests__/__snapshots__/{RangePicker.test.js.snap => RangePicker.test.tsx.snap} (100%) rename components/date-picker/__tests__/__snapshots__/{WeekPicker.test.js.snap => WeekPicker.test.tsx.snap} (100%) rename components/date-picker/__tests__/__snapshots__/{demo.test.js.snap => demo.test.ts.snap} (100%) rename components/date-picker/__tests__/__snapshots__/{mount.test.js.snap => mount.test.ts.snap} (100%) rename components/date-picker/__tests__/__snapshots__/{other.test.js.snap => other.test.tsx.snap} (99%) rename components/date-picker/__tests__/{demo.test.js => demo.test.ts} (100%) rename components/date-picker/__tests__/{mount.test.js => mount.test.ts} (100%) rename components/date-picker/__tests__/{other.test.js => other.test.tsx} (62%) delete mode 100644 components/date-picker/__tests__/utils.js create mode 100644 components/date-picker/__tests__/utils.ts diff --git a/components/config-provider/__tests__/locale.test.js b/components/config-provider/__tests__/locale.test.tsx similarity index 50% rename from components/config-provider/__tests__/locale.test.js rename to components/config-provider/__tests__/locale.test.tsx index 736efc2841..497fec14f0 100644 --- a/components/config-provider/__tests__/locale.test.js +++ b/components/config-provider/__tests__/locale.test.tsx @@ -1,24 +1,24 @@ -import { mount } from 'enzyme'; import React from 'react'; +import { closePicker, openPicker, selectCell } from '../../date-picker/__tests__/utils'; import ConfigProvider from '..'; import DatePicker from '../../date-picker'; -import { closePicker, openPicker, selectCell } from '../../date-picker/__tests__/utils'; +import type { Locale } from '../../locale-provider'; import LocaleProvider from '../../locale-provider'; import enUS from '../../locale/en_US'; import zhCN from '../../locale/zh_CN'; import Modal from '../../modal'; import Pagination from '../../pagination'; import TimePicker from '../../time-picker'; -import { act } from '../../../tests/utils'; +import { act, render, fireEvent } from '../../../tests/utils'; describe('ConfigProvider.Locale', () => { - function $$(className) { + function $$(className: string): NodeListOf { return document.body.querySelectorAll(className); } it('not throw', () => { - mount( - + render( + , @@ -28,23 +28,16 @@ describe('ConfigProvider.Locale', () => { // https://github.com/ant-design/ant-design/issues/18731 it('should not reset locale for Modal', () => { class App extends React.Component { - state = { - showButton: false, - }; + state = { showButton: false }; componentDidMount() { - this.setState({ - showButton: true, - }); + this.setState({ showButton: true }); } // eslint-disable-next-line class-methods-use-this openConfirm = () => { jest.useFakeTimers(); - Modal.confirm({ - title: 'title', - content: 'Some descriptions', - }); + Modal.confirm({ title: 'title', content: 'Some descriptions' }); act(() => { jest.runAllTimers(); }); @@ -66,24 +59,24 @@ describe('ConfigProvider.Locale', () => { } } - const wrapper = mount(); - wrapper.find('button').simulate('click'); + const wrapper = render(); + fireEvent.click(wrapper.container.querySelector('button')!); expect($$('.ant-btn-primary')[0].textContent).toBe('OK'); }); // https://github.com/ant-design/ant-design/issues/31592 it('should not reset the component state when switching locale', () => { - const wrapper = mount( + const wrapper = render( , ); - const datepickerInitProps = wrapper.find('.ant-picker-input input').props(); - expect(datepickerInitProps.value).toBe(''); - expect(datepickerInitProps.placeholder).toBe('请选择日期'); - expect(wrapper.find('.ant-pagination-item-1').props().className).toContain( + const datepicke = wrapper.container.querySelector('.ant-picker-input input'); + expect(datepicke?.value).toBe(''); + expect(datepicke?.placeholder).toBe('请选择日期'); + expect(wrapper.container.querySelector('.ant-pagination-item-1')?.className).toContain( 'ant-pagination-item-active', ); @@ -91,58 +84,68 @@ describe('ConfigProvider.Locale', () => { selectCell(wrapper, 10); closePicker(wrapper); - expect(wrapper.find('.ant-picker-input input').props().value).not.toBe(''); + expect( + wrapper.container.querySelector('.ant-picker-input input')?.value, + ).not.toBe(''); + wrapper.rerender( + + + + , + ); - wrapper.setProps({ locale: {} }); - wrapper.find('.ant-pagination-item-3').simulate('click'); + fireEvent.click(wrapper.container.querySelector('.ant-pagination-item-3')!); - const datepickerProps = wrapper.find('.ant-picker-input input').props(); - expect(datepickerProps.placeholder).not.toBe('请选择日期'); - expect(datepickerProps.value).not.toBe(''); - expect(datepickerProps.value).toContain('-10'); + const datepicker = wrapper.container.querySelector('.ant-picker-input input'); - expect(wrapper.find('.ant-pagination-item-3').props().className).toContain( + expect(datepicker?.placeholder).not.toBe('请选择日期'); + expect(datepicker?.value).not.toBe(''); + expect(datepicker?.value).toContain('-10'); + + expect(wrapper.container.querySelector('.ant-pagination-item-3')?.className).toContain( 'ant-pagination-item-active', ); }); describe('support legacy LocaleProvider', () => { - function testLocale(wrapper) { - expect(wrapper.find('input').props().placeholder).toBe(zhCN.TimePicker.placeholder); + function testLocale(wrapper: ReturnType): void { + expect(wrapper.container.querySelector('input')?.placeholder).toBe( + zhCN.TimePicker?.placeholder, + ); } it('LocaleProvider', () => { - const wrapper = mount( - - - , + testLocale( + render( + + + , + ), ); - - testLocale(wrapper); }); it('LocaleProvider > ConfigProvider', () => { - const wrapper = mount( - - - - - , + testLocale( + render( + + + + + , + ), ); - - testLocale(wrapper); }); it('ConfigProvider > ConfigProvider', () => { - const wrapper = mount( - - - - - , + testLocale( + render( + + + + + , + ), ); - - testLocale(wrapper); }); }); }); diff --git a/components/date-picker/__tests__/DatePicker.test.js b/components/date-picker/__tests__/DatePicker.test.js deleted file mode 100644 index d917117c4e..0000000000 --- a/components/date-picker/__tests__/DatePicker.test.js +++ /dev/null @@ -1,234 +0,0 @@ -import { mount } from 'enzyme'; -import MockDate from 'mockdate'; -import moment from 'moment'; -import React from 'react'; -import DatePicker from '..'; -import focusTest from '../../../tests/shared/focusTest'; - -describe('DatePicker', () => { - const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); - - focusTest(DatePicker, { refFocus: true }); - - beforeEach(() => { - MockDate.set(moment('2016-11-22').valueOf()); - }); - - afterEach(() => { - MockDate.reset(); - errorSpy.mockReset(); - }); - - afterAll(() => { - errorSpy.mockRestore(); - }); - - it('prop locale should works', () => { - const locale = { - lang: { - locale: 'mk', - placeholder: 'Избери дата', - rangePlaceholder: ['Начална дата', 'Крайна дата'], - today: 'Днес', - now: 'Сега', - backToToday: 'Към днес', - ok: 'Добре', - clear: 'Изчистване', - month: 'Месец', - year: 'Година', - timeSelect: 'Избор на час', - dateSelect: 'Избор на дата', - monthSelect: 'Избор на месец', - yearSelect: 'Избор на година', - decadeSelect: 'Десетилетие', - previousMonth: 'Предишен месец (PageUp)', - nextMonth: 'Следващ месец (PageDown)', - previousYear: 'Последна година (Control + left)', - nextYear: 'Следваща година (Control + right)', - previousDecade: 'Предишно десетилетие', - nextDecade: 'Следващо десетилетие', - previousCentury: 'Последен век', - nextCentury: 'Следващ век', - yearFormat: 'YYYY', - dateFormat: 'D M YYYY', - dayFormat: 'D', - dateTimeFormat: 'D M YYYY HH:mm:ss', - monthBeforeYear: true, - }, - timePickerLocale: { - placeholder: 'Избор на час', - }, - }; - const birthday = moment('2000-01-01', 'YYYY-MM-DD'); - const wrapper = mount(); - expect(wrapper.render()).toMatchSnapshot(); - }); - - it('disabled date', () => { - const disabledDate = current => current && current < moment().endOf('day'); - const wrapper = mount(); - expect(wrapper.render()).toMatchSnapshot(); - }); - - it('placeholder', () => { - const wrapper = mount(); - expect(wrapper.find('input').props().placeholder).toEqual('Select date'); - }); - - it('showTime={{ showHour: true, showMinute: true }}', () => { - const wrapper = mount( - , - ); - expect(wrapper.find('.ant-picker-time-panel-column').length).toBe(2); - expect( - wrapper.find('.ant-picker-time-panel-column').at(0).find('.ant-picker-time-panel-cell') - .length, - ).toBe(24); - expect( - wrapper.find('.ant-picker-time-panel-column').at(1).find('.ant-picker-time-panel-cell') - .length, - ).toBe(60); - }); - - it('showTime={{ showHour: true, showSecond: true }}', () => { - const wrapper = mount( - , - ); - expect(wrapper.find('.ant-picker-time-panel-column').length).toBe(2); - expect( - wrapper.find('.ant-picker-time-panel-column').at(0).find('.ant-picker-time-panel-cell') - .length, - ).toBe(24); - expect( - wrapper.find('.ant-picker-time-panel-column').at(1).find('.ant-picker-time-panel-cell') - .length, - ).toBe(60); - }); - - it('showTime={{ showMinute: true, showSecond: true }}', () => { - const wrapper = mount( - , - ); - expect(wrapper.find('.ant-picker-time-panel-column').length).toBe(2); - expect( - wrapper.find('.ant-picker-time-panel-column').at(0).find('.ant-picker-time-panel-cell') - .length, - ).toBe(60); - expect( - wrapper.find('.ant-picker-time-panel-column').at(1).find('.ant-picker-time-panel-cell') - .length, - ).toBe(60); - }); - it('showTime should work correctly when format is custom function', () => { - const wrapper = mount( - val.format('YYYY-MM-DD')} open />, - ); - const input = wrapper.find('input').simulate('mousedown'); - expect(input.simulate.bind(input, 'focus')).not.toThrowError(); - }); - - it('12 hours', () => { - const wrapper = mount( - , - ); - expect(wrapper.find('.ant-picker-time-panel-column').length).toBe(4); - expect( - wrapper.find('.ant-picker-time-panel-column').at(0).find('.ant-picker-time-panel-cell') - .length, - ).toBe(12); - expect( - wrapper.find('.ant-picker-time-panel-column').at(1).find('.ant-picker-time-panel-cell') - .length, - ).toBe(60); - expect( - wrapper.find('.ant-picker-time-panel-column').at(2).find('.ant-picker-time-panel-cell') - .length, - ).toBe(60); - expect( - wrapper.find('.ant-picker-time-panel-column').at(3).find('.ant-picker-time-panel-cell') - .length, - ).toBe(2); - }); - - it('24 hours', () => { - const wrapper = mount( - , - ); - expect(wrapper.find('.ant-picker-time-panel-column').length).toBe(3); - expect( - wrapper.find('.ant-picker-time-panel-column').at(0).find('.ant-picker-time-panel-cell') - .length, - ).toBe(24); - expect( - wrapper.find('.ant-picker-time-panel-column').at(1).find('.ant-picker-time-panel-cell') - .length, - ).toBe(60); - expect( - wrapper.find('.ant-picker-time-panel-column').at(2).find('.ant-picker-time-panel-cell') - .length, - ).toBe(60); - }); - - it('DatePicker.RangePicker with defaultPickerValue and showTime', () => { - const startDate = moment('1982-02-12'); - const endDate = moment('1982-02-22'); - - const wrapper = mount( - , - ); - - const month = wrapper.find('.ant-picker-header-view .ant-picker-month-btn').text(); - const year = wrapper.find('.ant-picker-header-view .ant-picker-year-btn').text(); - - expect(month).toBe(startDate.format('MMM')); - expect(year).toBe(startDate.format('YYYY')); - expect(wrapper.find('.ant-picker-time-panel').length).toBe(1); - }); - - it('placement api work correctly ', () => { - const popupAlignDefault = (points = ['tl', 'bl'], offset = [0, 4]) => ({ - points, - offset, - overflow: { - adjustX: 1, - adjustY: 1, - }, - }); - - const wrapper = mount( - , - ); - expect(wrapper.find('Trigger').prop('popupAlign')).toEqual(popupAlignDefault(['tl', 'bl'])); - wrapper.setProps({ - placement: 'bottomRight', - }); - expect(wrapper.find('Trigger').prop('popupAlign')).toEqual(popupAlignDefault(['tr', 'br'])); - wrapper.setProps({ - placement: 'topLeft', - }); - expect(wrapper.find('Trigger').prop('popupAlign')).toEqual( - popupAlignDefault(['bl', 'tl'], [0, -4]), - ); - wrapper.setProps({ - placement: 'topRight', - }); - expect(wrapper.find('Trigger').prop('popupAlign')).toEqual( - popupAlignDefault(['br', 'tr'], [0, -4]), - ); - }); -}); diff --git a/components/date-picker/__tests__/DatePicker.test.tsx b/components/date-picker/__tests__/DatePicker.test.tsx new file mode 100644 index 0000000000..7168ebf74b --- /dev/null +++ b/components/date-picker/__tests__/DatePicker.test.tsx @@ -0,0 +1,268 @@ +import MockDate from 'mockdate'; +import moment from 'moment'; +import React from 'react'; +import type { TriggerProps } from 'rc-trigger'; +import { fireEvent, render } from '../../../tests/utils'; +import DatePicker from '..'; +import focusTest from '../../../tests/shared/focusTest'; +import type { PickerLocale } from '../generatePicker'; + +let triggerProps: TriggerProps; + +jest.mock('rc-trigger', () => { + let Trigger = jest.requireActual('rc-trigger/lib/mock'); + Trigger = Trigger.default || Trigger; + const h: typeof React = jest.requireActual('react'); + + return { + default: h.forwardRef((props, ref) => { + triggerProps = props; + return h.createElement(Trigger, { ref, ...props }); + }), + __esModule: true, + }; +}); + +describe('DatePicker', () => { + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + + focusTest(DatePicker, { refFocus: true }); + + beforeEach(() => { + MockDate.set(moment('2016-11-22').valueOf()); + }); + + afterEach(() => { + MockDate.reset(); + errorSpy.mockReset(); + }); + + afterAll(() => { + errorSpy.mockRestore(); + }); + + it('prop locale should works', () => { + const locale = { + lang: { + locale: 'mk', + placeholder: 'Избери дата', + rangePlaceholder: ['Начална дата', 'Крайна дата'], + today: 'Днес', + now: 'Сега', + backToToday: 'Към днес', + ok: 'Добре', + clear: 'Изчистване', + month: 'Месец', + year: 'Година', + timeSelect: 'Избор на час', + dateSelect: 'Избор на дата', + monthSelect: 'Избор на месец', + yearSelect: 'Избор на година', + decadeSelect: 'Десетилетие', + previousMonth: 'Предишен месец (PageUp)', + nextMonth: 'Следващ месец (PageDown)', + previousYear: 'Последна година (Control + left)', + nextYear: 'Следваща година (Control + right)', + previousDecade: 'Предишно десетилетие', + nextDecade: 'Следващо десетилетие', + previousCentury: 'Последен век', + nextCentury: 'Следващ век', + yearFormat: 'YYYY', + dateFormat: 'D M YYYY', + dayFormat: 'D', + dateTimeFormat: 'D M YYYY HH:mm:ss', + monthBeforeYear: true, + }, + timePickerLocale: { + placeholder: 'Избор на час', + }, + }; + const birthday = moment('2000-01-01', 'YYYY-MM-DD'); + const wrapper = render(); + expect(Array.from(wrapper.container.children)).toMatchSnapshot(); + }); + + it('disabled date', () => { + const disabledDate = (current: any) => current && current < moment().endOf('day'); + const wrapper = render(); + expect(Array.from(wrapper.container.children)).toMatchSnapshot(); + }); + + it('placeholder', () => { + const wrapper = render(); + expect(wrapper.container.querySelector('input')?.placeholder).toEqual('Select date'); + }); + + it('showTime={{ showHour: true, showMinute: true }}', () => { + const { container } = render( + , + ); + expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(2); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[0] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(24); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[1] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(60); + }); + + it('showTime={{ showHour: true, showSecond: true }}', () => { + const { container } = render( + , + ); + expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(2); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[0] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(24); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[1] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(60); + }); + + it('showTime={{ showMinute: true, showSecond: true }}', () => { + const { container } = render( + , + ); + expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(2); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[0] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(60); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[1] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(60); + }); + it('showTime should work correctly when format is custom function', () => { + const { container } = render( + val.format('YYYY-MM-DD')} open />, + ); + const fuousEvent = () => { + fireEvent.focus(container.querySelector('input')!); + }; + const mouseDownEvent = () => { + fireEvent.mouseDown(container.querySelector('input')!); + }; + expect(fuousEvent).not.toThrowError(); + expect(mouseDownEvent).not.toThrowError(); + }); + + it('12 hours', () => { + const { container } = render( + , + ); + expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(4); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[0] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(12); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[1] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(60); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[2] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(60); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[3] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(2); + }); + + it('24 hours', () => { + const { container } = render( + , + ); + expect(container.querySelectorAll('.ant-picker-time-panel-column').length).toBe(3); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[0] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(24); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[1] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(60); + expect( + container + .querySelectorAll('.ant-picker-time-panel-column')?.[2] + .querySelectorAll('.ant-picker-time-panel-cell').length, + ).toBe(60); + }); + + it('DatePicker.RangePicker with defaultPickerValue and showTime', () => { + const startDate = moment('1982-02-12'); + const endDate = moment('1982-02-22'); + + const { container } = render( + , + ); + + const m = container.querySelector('.ant-picker-header-view .ant-picker-month-btn')?.innerHTML; + const y = container.querySelector('.ant-picker-header-view .ant-picker-year-btn')?.innerHTML; + expect(m).toBe(startDate.format('MMM')); + expect(y).toBe(startDate.format('YYYY')); + expect(container.querySelectorAll('.ant-picker-time-panel').length).toBe(1); + }); + + it('placement api work correctly', () => { + const { rerender } = render(); + expect(triggerProps?.builtinPlacements).toEqual( + expect.objectContaining({ + topLeft: expect.objectContaining({ offset: [0, -4], points: ['bl', 'tl'] }), + }), + ); + + rerender(); + expect(triggerProps?.builtinPlacements).toEqual( + expect.objectContaining({ + topRight: expect.objectContaining({ offset: [0, -4], points: ['br', 'tr'] }), + }), + ); + + rerender(); + expect(triggerProps?.builtinPlacements).toEqual( + expect.objectContaining({ + bottomLeft: expect.objectContaining({ offset: [0, 4], points: ['tl', 'bl'] }), + }), + ); + + rerender(); + expect(triggerProps?.builtinPlacements).toEqual( + expect.objectContaining({ + bottomRight: expect.objectContaining({ offset: [0, 4], points: ['tr', 'br'] }), + }), + ); + }); +}); diff --git a/components/date-picker/__tests__/QuarterPicker.test.js b/components/date-picker/__tests__/QuarterPicker.test.tsx similarity index 74% rename from components/date-picker/__tests__/QuarterPicker.test.js rename to components/date-picker/__tests__/QuarterPicker.test.tsx index f607c268dd..869f8d5687 100644 --- a/components/date-picker/__tests__/QuarterPicker.test.js +++ b/components/date-picker/__tests__/QuarterPicker.test.tsx @@ -1,6 +1,6 @@ -import { mount } from 'enzyme'; import React from 'react'; import DatePicker from '..'; +import { render } from '../../../tests/utils'; import { resetWarned } from '../../_util/warning'; const { QuarterPicker } = DatePicker; @@ -10,8 +10,8 @@ describe('QuarterPicker', () => { resetWarned(); const warnSpy = jest.spyOn(console, 'error'); - const wrapper = mount(); - expect(wrapper.render()).toMatchSnapshot(); + const { container } = render(); + expect(container.firstChild).toMatchSnapshot(); expect(warnSpy).toHaveBeenCalledWith( "Warning: [antd: QuarterPicker] DatePicker.QuarterPicker is legacy usage. Please use DatePicker[picker='quarter'] directly.", diff --git a/components/date-picker/__tests__/RangePicker.test.js b/components/date-picker/__tests__/RangePicker.test.js deleted file mode 100644 index 9ce55f31fd..0000000000 --- a/components/date-picker/__tests__/RangePicker.test.js +++ /dev/null @@ -1,104 +0,0 @@ -import { mount } from 'enzyme'; -import moment from 'moment'; -import React from 'react'; -import DatePicker from '..'; -import focusTest from '../../../tests/shared/focusTest'; -import { resetMockDate, setMockDate } from '../../../tests/utils'; -import enUS from '../locale/en_US'; -import { closePicker, openPicker, selectCell } from './utils'; - -const { RangePicker } = DatePicker; - -describe('RangePicker', () => { - focusTest(RangePicker, { refFocus: true }); - - beforeEach(() => { - setMockDate(); - }); - - afterEach(() => { - resetMockDate(); - }); - - // issue: https://github.com/ant-design/ant-design/issues/5872 - it('should not throw error when value is reset to `[]`', () => { - const birthday = moment('2000-01-01', 'YYYY-MM-DD'); - const wrapper = mount(); - wrapper.setProps({ value: [] }); - - expect(() => { - openPicker(wrapper); - selectCell(wrapper, 3); - closePicker(wrapper); - - openPicker(wrapper, 1); - selectCell(wrapper, 5, 1); - closePicker(wrapper, 1); - }).not.toThrow(); - }); - - it('customize separator', () => { - const wrapper = mount(); - expect(wrapper.render()).toMatchSnapshot(); - }); - - // https://github.com/ant-design/ant-design/issues/13302 - describe('in "month" mode, when the left and right panels select the same month', () => { - it('the cell status is correct', () => { - class Test extends React.Component { - state = { - value: null, - }; - - onPanelChange = value => { - this.setState({ value }); - }; - - render() { - return ( - - ); - } - } - const wrapper = mount(); - openPicker(wrapper); - selectCell(wrapper, 'Feb'); - openPicker(wrapper, 1); - selectCell(wrapper, 'Feb'); - closePicker(wrapper, 1); - const { value } = wrapper.find(Test).state(); - expect(value[0].isSame(value[1], 'date')).toBeTruthy(); - }); - }); - - describe('ranges', () => { - it('RangePicker support presetted ranges with Tags', () => { - const wrapper = mount( - , - ); - expect(wrapper.render()).toMatchSnapshot(); - }); - }); - - it('placeholder', () => { - const wrapper = mount(); - expect(wrapper.find('input').first().props().placeholder).toEqual('Start date'); - expect(wrapper.find('input').last().props().placeholder).toEqual('End date'); - }); - - it('RangePicker picker quarter placeholder', () => { - const wrapper = mount(); - expect(wrapper.find('input').at(0).props().placeholder).toEqual('Start quarter'); - expect(wrapper.find('input').at(1).props().placeholder).toEqual('End quarter'); - }); -}); diff --git a/components/date-picker/__tests__/RangePicker.test.tsx b/components/date-picker/__tests__/RangePicker.test.tsx new file mode 100644 index 0000000000..13f25f9da4 --- /dev/null +++ b/components/date-picker/__tests__/RangePicker.test.tsx @@ -0,0 +1,115 @@ +import moment from 'moment'; +import type { RangeValue } from 'rc-picker/lib/interface'; +import React from 'react'; +import DatePicker from '..'; +import focusTest from '../../../tests/shared/focusTest'; +import { render, resetMockDate, setMockDate } from '../../../tests/utils'; +import enUS from '../locale/en_US'; + +import { closePicker, openPicker, selectCell } from './utils'; + +const { RangePicker } = DatePicker; + +describe('RangePicker', () => { + focusTest(RangePicker, { refFocus: true }); + + beforeEach(() => { + setMockDate(); + }); + + afterEach(() => { + resetMockDate(); + }); + + // issue: https://github.com/ant-design/ant-design/issues/5872 + it('should not throw error when value is reset to `[]`', () => { + const birthday = moment('2000-01-01', 'YYYY-MM-DD'); + const wrapper1 = render(); + const wrapper2 = render(); + + expect(() => { + openPicker(wrapper1); + selectCell(wrapper1, 3); + closePicker(wrapper1); + + openPicker(wrapper1, 1); + selectCell(wrapper1, 5, 1); + closePicker(wrapper1, 1); + + openPicker(wrapper2); + selectCell(wrapper2, 3); + closePicker(wrapper2); + + openPicker(wrapper2, 1); + selectCell(wrapper2, 5, 1); + closePicker(wrapper2, 1); + }).not.toThrow(); + }); + + it('customize separator', () => { + const { container } = render(); + expect(container.firstChild).toMatchSnapshot(); + }); + + // https://github.com/ant-design/ant-design/issues/13302 + describe('in "month" mode, when the left and right panels select the same month', () => { + it('the cell status is correct', () => { + let rangePickerValue = [] as unknown as RangeValue; + class Test extends React.Component { + state = { value: null }; + + render() { + return ( + { + this.setState({ value }); + rangePickerValue = value; + }} + /> + ); + } + } + const wrapper = render(); + + openPicker(wrapper); + selectCell(wrapper, 'Feb'); + openPicker(wrapper, 1); + selectCell(wrapper, 'Feb'); + closePicker(wrapper, 1); + + const [start, end] = rangePickerValue as [moment.Moment, moment.Moment]; + + expect(start.isSame(end, 'date')).toBeTruthy(); + }); + }); + + describe('ranges', () => { + it('RangePicker support presetted ranges with Tags', () => { + const { container } = render( + , + ); + expect(Array.from(container.children)).toMatchSnapshot(); + }); + }); + + it('placeholder', () => { + const { container } = render(); + const inputLists = container.querySelectorAll('input'); + expect(inputLists[0]?.placeholder).toEqual('Start date'); + expect(inputLists[inputLists.length - 1].placeholder).toEqual('End date'); + }); + + it('RangePicker picker quarter placeholder', () => { + const { container } = render(); + expect(container.querySelectorAll('input')[0]?.placeholder).toEqual('Start quarter'); + expect(container.querySelectorAll('input')[1]?.placeholder).toEqual('End quarter'); + }); +}); diff --git a/components/date-picker/__tests__/WeekPicker.test.js b/components/date-picker/__tests__/WeekPicker.test.tsx similarity index 63% rename from components/date-picker/__tests__/WeekPicker.test.js rename to components/date-picker/__tests__/WeekPicker.test.tsx index 5cfa6f4908..a2f6480eee 100644 --- a/components/date-picker/__tests__/WeekPicker.test.js +++ b/components/date-picker/__tests__/WeekPicker.test.tsx @@ -1,8 +1,7 @@ -import { mount } from 'enzyme'; import React from 'react'; import DatePicker from '..'; import focusTest from '../../../tests/shared/focusTest'; -import { resetMockDate, setMockDate } from '../../../tests/utils'; +import { render, resetMockDate, setMockDate } from '../../../tests/utils'; const { WeekPicker } = DatePicker; @@ -18,7 +17,7 @@ describe('WeekPicker', () => { focusTest(WeekPicker, { refFocus: true }); it('should support style prop', () => { - const wrapper = mount(); - expect(wrapper.render()).toMatchSnapshot(); + const { container } = render(); + expect(container.firstChild).toMatchSnapshot(); }); }); diff --git a/components/date-picker/__tests__/__snapshots__/DatePicker.test.js.snap b/components/date-picker/__tests__/__snapshots__/DatePicker.test.tsx.snap similarity index 100% rename from components/date-picker/__tests__/__snapshots__/DatePicker.test.js.snap rename to components/date-picker/__tests__/__snapshots__/DatePicker.test.tsx.snap diff --git a/components/date-picker/__tests__/__snapshots__/QuarterPicker.test.js.snap b/components/date-picker/__tests__/__snapshots__/QuarterPicker.test.tsx.snap similarity index 100% rename from components/date-picker/__tests__/__snapshots__/QuarterPicker.test.js.snap rename to components/date-picker/__tests__/__snapshots__/QuarterPicker.test.tsx.snap diff --git a/components/date-picker/__tests__/__snapshots__/RangePicker.test.js.snap b/components/date-picker/__tests__/__snapshots__/RangePicker.test.tsx.snap similarity index 100% rename from components/date-picker/__tests__/__snapshots__/RangePicker.test.js.snap rename to components/date-picker/__tests__/__snapshots__/RangePicker.test.tsx.snap diff --git a/components/date-picker/__tests__/__snapshots__/WeekPicker.test.js.snap b/components/date-picker/__tests__/__snapshots__/WeekPicker.test.tsx.snap similarity index 100% rename from components/date-picker/__tests__/__snapshots__/WeekPicker.test.js.snap rename to components/date-picker/__tests__/__snapshots__/WeekPicker.test.tsx.snap diff --git a/components/date-picker/__tests__/__snapshots__/demo.test.js.snap b/components/date-picker/__tests__/__snapshots__/demo.test.ts.snap similarity index 100% rename from components/date-picker/__tests__/__snapshots__/demo.test.js.snap rename to components/date-picker/__tests__/__snapshots__/demo.test.ts.snap diff --git a/components/date-picker/__tests__/__snapshots__/mount.test.js.snap b/components/date-picker/__tests__/__snapshots__/mount.test.ts.snap similarity index 100% rename from components/date-picker/__tests__/__snapshots__/mount.test.js.snap rename to components/date-picker/__tests__/__snapshots__/mount.test.ts.snap diff --git a/components/date-picker/__tests__/__snapshots__/other.test.js.snap b/components/date-picker/__tests__/__snapshots__/other.test.tsx.snap similarity index 99% rename from components/date-picker/__tests__/__snapshots__/other.test.js.snap rename to components/date-picker/__tests__/__snapshots__/other.test.tsx.snap index e2850c61bc..c3e3139f10 100644 --- a/components/date-picker/__tests__/__snapshots__/other.test.js.snap +++ b/components/date-picker/__tests__/__snapshots__/other.test.tsx.snap @@ -3,8 +3,8 @@ exports[`MonthPicker and WeekPicker render MonthPicker 1`] = `
{ }; const date = moment('2000-01-01', 'YYYY-MM-DD'); - function matchPicker(name, Picker, props) { + function matchPicker(name: string, Picker: typeof MonthPicker | typeof WeekPicker, props?: any) { it(name, () => { - const wrapper = mount( - + const { container } = render( + , ); - - expect(wrapper.render()).toMatchSnapshot(); + expect(container.firstChild).toMatchSnapshot(); }); } @@ -44,35 +44,33 @@ describe('Picker format by locale', () => { describe('MonthPicker and WeekPicker', () => { it('render MonthPicker', () => { const birthday = moment('2000-01-01', 'YYYY-MM-DD').locale('zh-cn'); - const wrapper = mount(); - wrapper.setProps({ value: birthday }); - expect(render(wrapper.find('Trigger').instance().getComponent())).toMatchSnapshot(); + const { container } = render(); + expect(container.querySelector('div.ant-picker-dropdown')?.parentNode).toMatchSnapshot(); }); it('render WeekPicker', () => { const birthday = moment('2000-01-01', 'YYYY-MM-DD').locale('zh-cn'); - const wrapper = mount(); - wrapper.setProps({ value: birthday }); - expect(render(wrapper.find('Trigger').instance().getComponent())).toMatchSnapshot(); + const { container } = render(); + expect(container.querySelector('div.ant-picker-dropdown')?.parentNode).toMatchSnapshot(); }); }); describe('Override locale setting of the ConfigProvider', () => { it('DatePicker', () => { - const wrapper = mount( + const { container } = render( , ); - expect(wrapper.find('input').props().placeholder).toEqual('請選擇日期'); + expect(container.querySelector('input')?.placeholder).toEqual('請選擇日期'); }); it('RangePicker', () => { - const wrapper = mount( + const { container } = render( , ); - expect(wrapper.find('input').at(0).props().placeholder).toEqual('開始日期'); - expect(wrapper.find('input').at(1).props().placeholder).toEqual('結束日期'); + expect(container.querySelectorAll('input')[0]?.placeholder).toEqual('開始日期'); + expect(container.querySelectorAll('input')[1]?.placeholder).toEqual('結束日期'); }); }); diff --git a/components/date-picker/__tests__/utils.js b/components/date-picker/__tests__/utils.js deleted file mode 100644 index a8062e5aff..0000000000 --- a/components/date-picker/__tests__/utils.js +++ /dev/null @@ -1,58 +0,0 @@ -/* eslint-disable import/prefer-default-export */ -export function selectDate(wrapper, date, index) { - let calendar = wrapper; - if (index !== undefined) { - calendar = wrapper.find('.ant-calendar-range-part').at(index); - } - calendar.find({ title: date.format('LL'), role: 'gridcell' }).simulate('click'); -} - -export function hasSelected(wrapper, date) { - return wrapper - .find({ title: date.format('LL'), role: 'gridcell' }) - .hasClass('ant-calendar-selected-day'); -} - -export function openPanel(wrapper) { - wrapper.find('.ant-calendar-picker-input').simulate('click'); -} - -export function clearInput(wrapper) { - wrapper.find('.ant-calendar-picker-clear').hostNodes().simulate('click'); -} - -export function nextYear(wrapper) { - wrapper.find('.ant-calendar-next-year-btn').simulate('click'); -} - -export function nextMonth(wrapper) { - wrapper.find('.ant-calendar-next-month-btn').simulate('click'); -} - -export function openPicker(wrapper, index = 0) { - wrapper.find('input').at(index).simulate('mousedown').simulate('focus'); -} -export function closePicker(wrapper, index = 0) { - wrapper.find('input').at(index).simulate('blur'); -} - -export function selectCell(wrapper, text, index = 0) { - let matchCell; - - wrapper - .find('table') - .at(index) - .find('td') - .forEach(td => { - if (td.text() === String(text) && td.props().className.includes('-in-view')) { - matchCell = td; - td.simulate('click'); - } - }); - - if (!matchCell) { - throw new Error('Cell not match in picker panel.'); - } - - return matchCell; -} diff --git a/components/date-picker/__tests__/utils.ts b/components/date-picker/__tests__/utils.ts new file mode 100644 index 0000000000..98106855de --- /dev/null +++ b/components/date-picker/__tests__/utils.ts @@ -0,0 +1,27 @@ +import { fireEvent } from '../../../tests/utils'; +import type { render } from '../../../tests/utils'; + +export function openPicker(wrapper: ReturnType, index = 0) { + fireEvent.mouseDown(wrapper.container?.querySelectorAll('input')?.[index]!); + fireEvent.focus(wrapper.container?.querySelectorAll('input')?.[index]!); +} + +export function closePicker(wrapper: ReturnType, index = 0) { + fireEvent.blur(wrapper.container?.querySelectorAll('input')[index]!); +} + +export function selectCell(wrapper: ReturnType, text: string | number, index = 0) { + let matchCell: HTMLTableCellElement | null = null; + const tds = wrapper.container?.querySelectorAll('table')?.[index]?.querySelectorAll('td'); + tds.forEach(td => { + if (td.querySelector('div')?.innerHTML === String(text) && td.className.includes('-in-view')) { + matchCell = td; + fireEvent.click(td); + } + }); + /* istanbul ignore next */ + if (!matchCell) { + throw new Error('Cell not match in picker panel.'); + } + return matchCell; +} diff --git a/components/date-picker/util.ts b/components/date-picker/util.ts index 7b4626765f..c6cf9625ea 100644 --- a/components/date-picker/util.ts +++ b/components/date-picker/util.ts @@ -95,17 +95,11 @@ export function transPlacement2DropdownAlign( }; } default: { - return direction === 'rtl' - ? { - points: ['tr', 'br'], - offset: [0, 4], - overflow, - } - : { - points: ['tl', 'bl'], - offset: [0, 4], - overflow, - }; + return { + points: direction === 'rtl' ? ['tr', 'br'] : ['tl', 'bl'], + offset: [0, 4], + overflow, + }; } } } diff --git a/components/table/__tests__/Table.expand.test.js b/components/table/__tests__/Table.expand.test.js index 7df55d031b..3f1283c6aa 100644 --- a/components/table/__tests__/Table.expand.test.js +++ b/components/table/__tests__/Table.expand.test.js @@ -81,7 +81,7 @@ describe('Table.expand', () => { fireEvent.click(container.querySelector('.ant-table-row-expand-icon')); expect(container.querySelector('.indent-level-1').style.paddingLeft).toEqual('0px'); }); - + it('has right aria-expanded state', () => { const { container } = render(); expect(container.querySelector('[aria-expanded=false]')).toBeTruthy(); From 15e4b93e437ca9ebda90be7e2b8457eeb0a5bffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E7=88=B1=E5=90=83=E7=99=BD=E8=90=9D?= =?UTF-8?q?=E5=8D=9C?= Date: Fri, 19 Aug 2022 01:31:16 +0800 Subject: [PATCH 03/18] fix: Visible change not show Tooltip of Typography (#37147) * test: Update snapshot * test: Add test case * test: fix react 18 --- components/typography/Base/index.tsx | 27 ++++++- .../__snapshots__/demo-extend.test.ts.snap | 51 ++++++++++++ .../__tests__/__snapshots__/demo.test.js.snap | 27 +++++++ .../typography/__tests__/ellipsis.test.js | 80 +++++++++++++++---- components/typography/demo/ellipsis-debug.md | 13 +++ 5 files changed, 181 insertions(+), 17 deletions(-) diff --git a/components/typography/Base/index.tsx b/components/typography/Base/index.tsx index ccd08ca815..dd97673d4e 100644 --- a/components/typography/Base/index.tsx +++ b/components/typography/Base/index.tsx @@ -227,6 +227,7 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => { const [expanded, setExpanded] = React.useState(false); const [isJsEllipsis, setIsJsEllipsis] = React.useState(false); const [isNativeEllipsis, setIsNativeEllipsis] = React.useState(false); + const [isNativeVisible, setIsNativeVisible] = React.useState(true); const [enableEllipsis, ellipsisConfig] = useMergedConfig(ellipsis, { expandable: false, }); @@ -307,7 +308,31 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => { setIsNativeEllipsis(currentEllipsis); } } - }, [enableEllipsis, cssEllipsis, children, cssLineClamp]); + }, [enableEllipsis, cssEllipsis, children, cssLineClamp, isNativeVisible]); + + // https://github.com/ant-design/ant-design/issues/36786 + // Use IntersectionObserver to check if element is invisible + React.useEffect(() => { + const textEle = typographyRef.current; + if ( + typeof IntersectionObserver === 'undefined' || + !textEle || + !cssEllipsis || + !mergedEnableEllipsis + ) { + return; + } + + /* eslint-disable-next-line compat/compat */ + const observer = new IntersectionObserver(() => { + setIsNativeVisible(!!textEle.offsetParent); + }); + observer.observe(textEle!); + + return () => { + observer.disconnect(); + }; + }, [cssEllipsis, mergedEnableEllipsis]); // ========================== Tooltip =========================== let tooltipProps: TooltipProps = {}; diff --git a/components/typography/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/typography/__tests__/__snapshots__/demo-extend.test.ts.snap index 26411b767b..e4bf70af2e 100644 --- a/components/typography/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/typography/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -618,6 +618,57 @@ Array [ [After]

, +
+ + 默认display none 样式的超长文字, 悬停tooltip失效了 + + + +
+
+
+
+ +
+ +
+
+
+
, ] `; diff --git a/components/typography/__tests__/__snapshots__/demo.test.js.snap b/components/typography/__tests__/__snapshots__/demo.test.js.snap index 5a93633bb3..4f7cfe9f2a 100644 --- a/components/typography/__tests__/__snapshots__/demo.test.js.snap +++ b/components/typography/__tests__/__snapshots__/demo.test.js.snap @@ -522,6 +522,33 @@ Array [ [After]

, +
+ + 默认display none 样式的超长文字, 悬停tooltip失效了 + + + +
, ] `; diff --git a/components/typography/__tests__/ellipsis.test.js b/components/typography/__tests__/ellipsis.test.js index 69c94f1d95..23652f0cc7 100644 --- a/components/typography/__tests__/ellipsis.test.js +++ b/components/typography/__tests__/ellipsis.test.js @@ -1,5 +1,6 @@ import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; import React from 'react'; +import { act } from 'react-dom/test-utils'; import { fireEvent, render, sleep, triggerResize, waitFor } from '../../../tests/utils'; import Base from '../Base'; // eslint-disable-next-line no-unused-vars @@ -14,6 +15,7 @@ describe('Typography.Ellipsis', () => { const LINE_STR_COUNT = 20; const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); let mockRectSpy; + let getWidthTimes = 0; beforeAll(() => { mockRectSpy = spyElementPrototypes(HTMLElement, { @@ -26,7 +28,10 @@ describe('Typography.Ellipsis', () => { }, }, offsetWidth: { - get: () => 100, + get: () => { + getWidthTimes += 1; + return 100; + }, }, getBoundingClientRect() { let html = this.innerHTML; @@ -39,6 +44,7 @@ describe('Typography.Ellipsis', () => { afterEach(() => { errorSpy.mockReset(); + getWidthTimes = 0; }); afterAll(() => { @@ -223,28 +229,70 @@ describe('Typography.Ellipsis', () => { it('should have custom expand style', async () => { const symbol = 'more'; - const { container: wrapper } = render( + const { container } = render( {fullStr} , ); - expect(wrapper.querySelector('.ant-typography-expand').textContent).toEqual('more'); + expect(container.querySelector('.ant-typography-expand').textContent).toEqual('more'); }); - it('can use css ellipsis', () => { - const { container: wrapper } = render(); - expect(wrapper.querySelectorAll('.ant-typography-ellipsis-single-line').length).toBeGreaterThan( - 0, - ); - }); + describe('native css ellipsis', () => { + it('can use css ellipsis', () => { + const { container } = render(); + expect(container.querySelector('.ant-typography-ellipsis-single-line')).toBeTruthy(); + }); - it('should calculate padding', () => { - const { container: wrapper } = render( - , - ); - expect(wrapper.querySelectorAll('.ant-typography-ellipsis-single-line').length).toBeGreaterThan( - 0, - ); + // https://github.com/ant-design/ant-design/issues/36786 + it('Tooltip should recheck on parent visible change', () => { + const originIntersectionObserver = global.IntersectionObserver; + + let elementChangeCallback; + const observeFn = jest.fn(); + const disconnectFn = jest.fn(); + + global.IntersectionObserver = class MockIntersectionObserver { + constructor(callback) { + elementChangeCallback = callback; + } + + observe = observeFn; + + disconnect = disconnectFn; + }; + + const { container, unmount } = render(); + + expect(observeFn).toHaveBeenCalled(); + + // Hide first + act(() => { + elementChangeCallback(); + }); + + // Trigger visible should trigger recheck + getWidthTimes = 0; + Object.defineProperty(container.querySelector('.ant-typography'), 'offsetParent', { + get: () => document.body, + }); + act(() => { + elementChangeCallback(); + }); + + expect(getWidthTimes).toBeGreaterThan(0); + + unmount(); + expect(disconnectFn).toHaveBeenCalled(); + + global.IntersectionObserver = originIntersectionObserver; + }); + + it('should calculate padding', () => { + const { container } = render( + , + ); + expect(container.querySelector('.ant-typography-ellipsis-single-line')).toBeTruthy(); + }); }); describe('should tooltip support', () => { diff --git a/components/typography/demo/ellipsis-debug.md b/components/typography/demo/ellipsis-debug.md index 8dfd8679c1..b094f0fff3 100644 --- a/components/typography/demo/ellipsis-debug.md +++ b/components/typography/demo/ellipsis-debug.md @@ -26,6 +26,13 @@ const App: React.FC = () => { const [copyable, setCopyable] = useState(false); const [editable, setEditable] = useState(false); const [expandable, setExpandable] = useState(false); + const [display, setDisplay] = useState('none'); + + React.useEffect(() => { + setTimeout(() => { + setDisplay('block'); + }, 100); + }, []); return ( <> @@ -60,6 +67,12 @@ const App: React.FC = () => {

[Before]not ellipsis[After]

+ +
+ + 默认display none 样式的超长文字, 悬停tooltip失效了 + +
); }; From 0868bff4d116296f4b44790d6b62d99e5a738766 Mon Sep 17 00:00:00 2001 From: MadCcc <1075746765@qq.com> Date: Sun, 21 Aug 2022 15:12:14 +0800 Subject: [PATCH 04/18] docs: changelog 4.22.7 (#37169) --- CHANGELOG.en-US.md | 7 +++++++ CHANGELOG.zh-CN.md | 7 +++++++ package.json | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 7693f5db62..f16b4c7ea9 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -15,6 +15,13 @@ timeline: true --- +## 4.22.7 + +`2022-08-21` + +- 🐞 Fix Typography visible change some time Tooltip not work with ellipsis. [#37147](https://github.com/ant-design/ant-design/pull/37147) +- 🐞 Fix InputNumber that style cannot be customized with controls less variables. [#37070](https://github.com/ant-design/ant-design/pull/37070) [@coldice945](https://github.com/coldice945) + ## 4.22.6 `2022-08-17` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 92e8603d73..dd6cb4a2e6 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -15,6 +15,13 @@ timeline: true --- +## 4.22.7 + +`2022-08-21` + +- 🐞 修复 Typography 可见度切换时有时候省略不会显示 Tooltip 的问题。[#37147](https://github.com/ant-design/ant-design/pull/37147) +- 🐞 修复 InputNumber 样式不跟随控件 less 变量改变的问题。[#37070](https://github.com/ant-design/ant-design/pull/37070) [@coldice945](https://github.com/coldice945) + ## 4.22.6 `2022-08-17` diff --git a/package.json b/package.json index 5f64158267..b3b1757e93 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "antd", - "version": "4.22.6", + "version": "4.22.7", "description": "An enterprise-class UI design language and React components implementation", "title": "Ant Design", "keywords": [ From a34c9cef7f855373644c5b2fa3316a77ea70b68d Mon Sep 17 00:00:00 2001 From: Dmitry Artamonov <41914249+dartamonov-vertex@users.noreply.github.com> Date: Sun, 21 Aug 2022 04:39:54 -0400 Subject: [PATCH 05/18] Fix: sortable columns are not indicated as such for screen readers (#37167) --- .../__snapshots__/components.test.js.snap | 35 +++++---- .../table/__tests__/Table.sorter.test.js | 27 +++++++ .../__snapshots__/Table.sorter.test.js.snap | 9 ++- .../__snapshots__/demo-extend.test.ts.snap | 77 +++++++++++-------- .../__tests__/__snapshots__/demo.test.js.snap | 77 +++++++++++-------- components/table/hooks/useSorter.tsx | 4 + 6 files changed, 149 insertions(+), 80 deletions(-) diff --git a/components/config-provider/__tests__/__snapshots__/components.test.js.snap b/components/config-provider/__tests__/__snapshots__/components.test.js.snap index 4b55b7e76d..6fb92f4fb0 100644 --- a/components/config-provider/__tests__/__snapshots__/components.test.js.snap +++ b/components/config-provider/__tests__/__snapshots__/components.test.js.snap @@ -26723,6 +26723,7 @@ exports[`ConfigProvider components Table configProvider 1`] = ` >
@@ -26749,7 +26750,7 @@ exports[`ConfigProvider components Table configProvider 1`] = ` @@ -1542,7 +1544,7 @@ exports[`renders ./components/table/demo/custom-filter-panel.md extend context c @@ -3596,7 +3600,7 @@ Array [ @@ -7551,7 +7556,7 @@ exports[`renders ./components/table/demo/filter-in-tree.md extend context correc @@ -8371,7 +8377,7 @@ exports[`renders ./components/table/demo/filter-search.md extend context correct @@ -14780,7 +14790,7 @@ exports[`renders ./components/table/demo/multiple-sorter.md extend context corre @@ -14864,7 +14875,7 @@ exports[`renders ./components/table/demo/multiple-sorter.md extend context corre @@ -20685,7 +20698,7 @@ Array [ @@ -20775,7 +20789,7 @@ Array [ @@ -21310,7 +21325,7 @@ exports[`renders ./components/table/demo/resizable-column.md extend context corr @@ -1160,7 +1162,7 @@ exports[`renders ./components/table/demo/custom-filter-panel.md correctly 1`] = @@ -2893,7 +2897,7 @@ Array [ @@ -5870,7 +5875,7 @@ exports[`renders ./components/table/demo/filter-in-tree.md correctly 1`] = ` @@ -6216,7 +6222,7 @@ exports[`renders ./components/table/demo/filter-search.md correctly 1`] = ` @@ -11166,7 +11176,7 @@ exports[`renders ./components/table/demo/multiple-sorter.md correctly 1`] = ` @@ -11226,7 +11237,7 @@ exports[`renders ./components/table/demo/multiple-sorter.md correctly 1`] = ` @@ -15534,7 +15547,7 @@ Array [ @@ -15600,7 +15614,7 @@ Array [ @@ -15923,7 +15938,7 @@ exports[`renders ./components/table/demo/resizable-column.md correctly 1`] = ` { - setVal('bamboo'); - }} - > - {getVal()} - - ); - }; - - const wrapper = mount(); - expect(wrapper.text()).toEqual('light'); - wrapper.find('span').simulate('click'); - expect(wrapper.text()).toEqual('bamboo'); - }); -}); diff --git a/components/_util/__tests__/useSyncState.test.tsx b/components/_util/__tests__/useSyncState.test.tsx new file mode 100644 index 0000000000..c00c833f8d --- /dev/null +++ b/components/_util/__tests__/useSyncState.test.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import useSyncState from '../hooks/useSyncState'; +import { render, fireEvent } from '../../../tests/utils'; + +describe('Table', () => { + it('useSyncState', () => { + const Test: React.FC = () => { + const [getVal, setVal] = useSyncState('light'); + return setVal('bamboo')}>{getVal()}; + }; + + const { container } = render(); + expect(container.querySelector('span')?.innerHTML).toBe('light'); + fireEvent.click(container.querySelector('span')!); + expect(container.querySelector('span')?.innerHTML).toBe('bamboo'); + }); +}); diff --git a/components/_util/__tests__/util.test.js b/components/_util/__tests__/util.test.tsx similarity index 84% rename from components/_util/__tests__/util.test.js rename to components/_util/__tests__/util.test.tsx index cb2eeb3835..d7ff31261a 100644 --- a/components/_util/__tests__/util.test.js +++ b/components/_util/__tests__/util.test.tsx @@ -1,9 +1,8 @@ /* eslint-disable class-methods-use-this */ -import { mount } from 'enzyme'; import KeyCode from 'rc-util/lib/KeyCode'; import raf from 'rc-util/lib/raf'; import React from 'react'; -import { sleep } from '../../../tests/utils'; +import { sleep, render, fireEvent } from '../../../tests/utils'; import getDataOrAriaProps from '../getDataOrAriaProps'; import delayRaf from '../raf'; import { isStyleSupport } from '../styleChecker'; @@ -141,20 +140,24 @@ describe('Test utils function', () => { describe('TransButton', () => { it('can be focus/blur', () => { - const ref = React.createRef(); - mount(TransButton); - expect(typeof ref.current.focus).toBe('function'); - expect(typeof ref.current.blur).toBe('function'); + const ref = React.createRef(); + render(TransButton); + expect(typeof ref.current?.focus).toBe('function'); + expect(typeof ref.current?.blur).toBe('function'); }); it('should trigger onClick when press enter', () => { const onClick = jest.fn(); - const preventDefault = jest.fn(); - const wrapper = mount(TransButton); - wrapper.simulate('keyUp', { keyCode: KeyCode.ENTER }); - expect(onClick).toHaveBeenCalled(); - wrapper.simulate('keyDown', { keyCode: KeyCode.ENTER, preventDefault }); - expect(preventDefault).toHaveBeenCalled(); + + const { container } = render(TransButton); + + // callback should trigger + fireEvent.keyUp(container.querySelector('div')!, { keyCode: KeyCode.ENTER }); + expect(onClick).toHaveBeenCalledTimes(1); + + // callback should not trigger + fireEvent.keyDown(container.querySelector('div')!, { keyCode: KeyCode.ENTER }); + expect(onClick).toHaveBeenCalledTimes(1); }); }); @@ -167,7 +170,7 @@ describe('Test utils function', () => { it('isStyleSupport return false in service side', () => { const spy = jest .spyOn(window.document, 'documentElement', 'get') - .mockImplementation(() => undefined); + .mockImplementation(() => undefined as unknown as HTMLElement); expect(isStyleSupport('color')).toBe(false); expect(isStyleSupport('not-existed')).toBe(false); spy.mockRestore(); diff --git a/components/_util/__tests__/warning.test.js b/components/_util/__tests__/warning.test.ts similarity index 96% rename from components/_util/__tests__/warning.test.js rename to components/_util/__tests__/warning.test.ts index 2eeeb0f1bf..e02e8effd2 100644 --- a/components/_util/__tests__/warning.test.js +++ b/components/_util/__tests__/warning.test.ts @@ -23,9 +23,7 @@ describe('Test warning', () => { expect(value).toBe(undefined); expect(spy).not.toHaveBeenCalled(); - expect(() => { - noop(); - }).not.toThrow(); + expect(noop).not.toThrow(); }); describe('process.env.NODE_ENV !== "production"', () => { diff --git a/components/_util/__tests__/wave.test.js b/components/_util/__tests__/wave.test.tsx similarity index 60% rename from components/_util/__tests__/wave.test.js rename to components/_util/__tests__/wave.test.tsx index 7e733b9e3b..b0b4ab1dd8 100644 --- a/components/_util/__tests__/wave.test.js +++ b/components/_util/__tests__/wave.test.tsx @@ -1,7 +1,6 @@ -import { mount } from 'enzyme'; import React from 'react'; import mountTest from '../../../tests/shared/mountTest'; -import { render, sleep } from '../../../tests/utils'; +import { render, sleep, fireEvent } from '../../../tests/utils'; import ConfigProvider from '../../config-provider'; import Wave from '../wave'; @@ -18,139 +17,155 @@ describe('Wave component', () => { it('isHidden works', () => { const TEST_NODE_ENV = process.env.NODE_ENV; process.env.NODE_ENV = 'development'; - const wrapper = mount( + const { container, unmount } = render( , ); - expect(wrapper.find('button').getDOMNode().className).toBe(''); - wrapper.find('button').getDOMNode().click(); + expect(container.querySelector('button')?.className).toBe(''); + + container.querySelector('button')?.click(); + expect( - wrapper.find('button').getDOMNode().hasAttribute('ant-click-animating-without-extra-node'), - ).toBe(false); - wrapper.unmount(); + container.querySelector('button')?.hasAttribute('ant-click-animating-without-extra-node'), + ).toBeFalsy(); + unmount(); process.env.NODE_ENV = TEST_NODE_ENV; }); it('isHidden is mocked', () => { - const wrapper = mount( + const { container, unmount } = render( , ); - expect(wrapper.find('button').getDOMNode().className).toBe(''); - wrapper.find('button').getDOMNode().click(); + expect(container.querySelector('button')?.className).toBe(''); + container.querySelector('button')?.click(); expect( - wrapper.find('button').getDOMNode().getAttribute('ant-click-animating-without-extra-node'), + container.querySelector('button')?.getAttribute('ant-click-animating-without-extra-node'), ).toBe('false'); - wrapper.unmount(); + unmount(); }); it('wave color is grey', async () => { - const wrapper = mount( + const { container, unmount } = render( , ); - wrapper.find('button').getDOMNode().click(); + container.querySelector('button')?.click(); await sleep(0); - const styles = wrapper.find('button').getDOMNode().getRootNode().getElementsByTagName('style'); + const styles = ( + container.querySelector('button')?.getRootNode() as HTMLButtonElement + ).getElementsByTagName('style'); expect(styles.length).toBe(0); - wrapper.unmount(); + unmount(); }); it('wave color is not grey', async () => { - const wrapper = mount( + const { container, unmount } = render( , ); - wrapper.find('button').getDOMNode().click(); + container.querySelector('button')?.click(); await sleep(200); - const styles = wrapper.find('button').getDOMNode().getRootNode().getElementsByTagName('style'); + const styles = ( + container.querySelector('button')?.getRootNode() as HTMLButtonElement + ).getElementsByTagName('style'); expect(styles.length).toBe(1); expect(styles[0].innerHTML).toContain('--antd-wave-shadow-color: red;'); - wrapper.unmount(); + unmount(); }); it('read wave color from border-top-color', async () => { - const wrapper = mount( + const { container, unmount } = render(
button
, ); - wrapper.find('div').getDOMNode().click(); + container.querySelector('div')?.click(); await sleep(0); - const styles = wrapper.find('div').getDOMNode().getRootNode().getElementsByTagName('style'); + const styles = ( + container.querySelector('div')?.getRootNode() as HTMLDivElement + ).getElementsByTagName('style'); expect(styles.length).toBe(1); expect(styles[0].innerHTML).toContain('--antd-wave-shadow-color: blue;'); - wrapper.unmount(); + unmount(); }); it('read wave color from background color', async () => { - const wrapper = mount( + const { container, unmount } = render(
button
, ); - wrapper.find('div').getDOMNode().click(); + container.querySelector('div')?.click(); await sleep(0); - const styles = wrapper.find('div').getDOMNode().getRootNode().getElementsByTagName('style'); + const styles = ( + container.querySelector('div')?.getRootNode() as HTMLDivElement + ).getElementsByTagName('style'); expect(styles.length).toBe(1); expect(styles[0].innerHTML).toContain('--antd-wave-shadow-color: green;'); - wrapper.unmount(); + unmount(); }); it('read wave color from border firstly', async () => { - const wrapper = mount( + const { container, unmount } = render(
button
, ); - wrapper.find('div').getDOMNode().click(); + container.querySelector('div')?.click(); await sleep(0); - const styles = wrapper.find('div').getDOMNode().getRootNode().getElementsByTagName('style'); + const styles = ( + container.querySelector('div')?.getRootNode() as HTMLDivElement + ).getElementsByTagName('style'); expect(styles.length).toBe(1); expect(styles[0].innerHTML).toContain('--antd-wave-shadow-color: yellow;'); - wrapper.unmount(); + unmount(); }); it('hidden element with -leave className', async () => { - const wrapper = mount( + const { container, unmount } = render( , ); - wrapper.find('button').getDOMNode().click(); + container.querySelector('button')?.click(); await sleep(0); - const styles = wrapper.find('button').getDOMNode().getRootNode().getElementsByTagName('style'); + const styles = ( + container.querySelector('button')?.getRootNode() as HTMLButtonElement + ).getElementsByTagName('style'); expect(styles.length).toBe(0); - wrapper.unmount(); + unmount(); }); it('ConfigProvider csp', async () => { - const wrapper = mount( + const { container, unmount } = render( , ); - wrapper.find('button').getDOMNode().click(); + container.querySelector('button')?.click(); await sleep(0); - const styles = wrapper.find('button').getDOMNode().getRootNode().getElementsByTagName('style'); + const styles = ( + container.querySelector('button')?.getRootNode() as HTMLButtonElement + ).getElementsByTagName('style'); expect(styles[0].getAttribute('nonce')).toBe('YourNonceCode'); - wrapper.unmount(); + unmount(); }); it('bindAnimationEvent should return when node is null', () => { - const ref = React.createRef(); + const ref = React.createRef(); render(