test: improve test for requestAnimationFrame (#22433)

* test: improve test for requestAnimationFrame

*  fix test coverage

* fix test case

* fix test case
This commit is contained in:
偏右 2020-03-20 15:07:47 +08:00 committed by GitHub
parent 1f79c76b80
commit 66f67051af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 94 additions and 109 deletions

View File

@ -1,16 +1,9 @@
import scrollTo from '../scrollTo';
import { sleep } from '../../../tests/utils';
describe('Test ScrollTo function', () => {
let dateNowMock;
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
beforeEach(() => {
dateNowMock = jest
.spyOn(Date, 'now')
@ -29,8 +22,8 @@ describe('Test ScrollTo function', () => {
});
scrollTo(1000);
await sleep(20);
jest.runAllTimers();
expect(window.pageYOffset).toBe(1000);
scrollToSpy.mockRestore();
@ -41,7 +34,7 @@ describe('Test ScrollTo function', () => {
scrollTo(1000, {
callback: cbMock,
});
jest.runAllTimers();
await sleep(20);
expect(cbMock).toHaveBeenCalledTimes(1);
});
@ -50,7 +43,7 @@ describe('Test ScrollTo function', () => {
scrollTo(1000, {
getContainer: () => div,
});
jest.runAllTimers();
await sleep(20);
expect(div.scrollTop).toBe(1000);
});
});

View File

@ -8,37 +8,30 @@ import getDataOrAriaProps from '../getDataOrAriaProps';
import Wave from '../wave';
import TransButton from '../transButton';
import openAnimation from '../openAnimation';
import { sleep } from '../../../tests/utils';
describe('Test utils function', () => {
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
it('throttle function should work', () => {
it('throttle function should work', async () => {
const callback = jest.fn();
const throttled = throttleByAnimationFrame(callback);
expect(callback).not.toHaveBeenCalled();
throttled();
throttled();
await sleep(20);
jest.runAllTimers();
expect(callback).toHaveBeenCalled();
expect(callback.mock.calls.length).toBe(1);
});
it('throttle function should be canceled', () => {
it('throttle function should be canceled', async () => {
const callback = jest.fn();
const throttled = throttleByAnimationFrame(callback);
throttled();
throttled.cancel();
await sleep(20);
jest.runAllTimers();
expect(callback).not.toHaveBeenCalled();
});

View File

@ -46,7 +46,7 @@ describe('Wave component', () => {
it('wave color is not grey', async () => {
const wrapper = mount(<Wave><button type="button" style={{ borderColor: 'red' }}>button</button></Wave>);
wrapper.find('button').getDOMNode().click();
await sleep(0);
await sleep(200);
const styles = document.getElementsByTagName('style');
expect(styles.length).toBe(1);
expect(styles[0].innerHTML).toContain('--antd-wave-shadow-color: red;');

View File

@ -5,6 +5,7 @@ import { getObserverEntities } from '../utils';
import Button from '../../button';
import { spyElementPrototype } from '../../__tests__/util/domHook';
import rtlTest from '../../../tests/shared/rtlTest';
import { sleep } from '../../../tests/utils';
const events = {};
@ -54,7 +55,6 @@ describe('Affix Render', () => {
};
beforeAll(() => {
jest.useFakeTimers();
domMock = spyElementPrototype(HTMLElement, 'getBoundingClientRect', function mockBounding() {
return (
classRect[this.className] || {
@ -66,10 +66,10 @@ describe('Affix Render', () => {
});
afterAll(() => {
jest.useRealTimers();
domMock.mockRestore();
});
const movePlaceholder = top => {
const movePlaceholder = async top => {
classRect.fixed = {
top,
bottom: top,
@ -77,58 +77,58 @@ describe('Affix Render', () => {
events.scroll({
type: 'scroll',
});
jest.runAllTimers();
await sleep(20);
};
it('Anchor render perfectly', () => {
it('Anchor render perfectly', async () => {
document.body.innerHTML = '<div id="mounter" />';
wrapper = mount(<AffixMounter />, { attachTo: document.getElementById('mounter') });
jest.runAllTimers();
await sleep(20);
movePlaceholder(0);
await movePlaceholder(0);
expect(wrapper.instance().affix.state.affixStyle).toBeFalsy();
movePlaceholder(-100);
await movePlaceholder(-100);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
movePlaceholder(0);
await movePlaceholder(0);
expect(wrapper.instance().affix.state.affixStyle).toBeFalsy();
});
it('support offsetBottom', () => {
it('support offsetBottom', async () => {
document.body.innerHTML = '<div id="mounter" />';
wrapper = mount(<AffixMounter offsetBottom={0} />, {
attachTo: document.getElementById('mounter'),
});
jest.runAllTimers();
await sleep(20);
movePlaceholder(300);
await movePlaceholder(300);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
movePlaceholder(0);
await movePlaceholder(0);
expect(wrapper.instance().affix.state.affixStyle).toBeFalsy();
movePlaceholder(300);
await movePlaceholder(300);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
});
it('updatePosition when offsetTop changed', () => {
it('updatePosition when offsetTop changed', async () => {
document.body.innerHTML = '<div id="mounter" />';
wrapper = mount(<AffixMounter offsetTop={0} />, {
attachTo: document.getElementById('mounter'),
});
jest.runAllTimers();
await sleep(20);
movePlaceholder(-100);
await movePlaceholder(-100);
expect(wrapper.instance().affix.state.affixStyle.top).toBe(0);
wrapper.setProps({
offsetTop: 10,
});
jest.runAllTimers();
await sleep(20);
expect(wrapper.instance().affix.state.affixStyle.top).toBe(10);
});
@ -144,7 +144,7 @@ describe('Affix Render', () => {
expect(wrapper.instance().state.placeholderStyle).toBe(undefined);
});
it('instance change', () => {
it('instance change', async () => {
const getObserverLength = () => Object.keys(getObserverEntities()).length;
const container = document.createElement('div');
@ -154,20 +154,20 @@ describe('Affix Render', () => {
const originLength = getObserverLength();
const getTarget = () => target;
wrapper = mount(<Affix target={getTarget} />);
jest.runAllTimers();
await sleep(20);
expect(getObserverLength()).toBe(originLength + 1);
target = null;
wrapper.setProps({});
wrapper.update();
jest.runAllTimers();
await sleep(20);
expect(getObserverLength()).toBe(originLength);
});
});
describe('updatePosition when size changed', () => {
function test(name, index) {
it(name, () => {
it(name, async () => {
document.body.innerHTML = '<div id="mounter" />';
const updateCalled = jest.fn();
@ -175,11 +175,11 @@ describe('Affix Render', () => {
attachTo: document.getElementById('mounter'),
});
jest.runAllTimers();
await sleep(20);
movePlaceholder(300);
await movePlaceholder(300);
expect(wrapper.instance().affix.state.affixStyle).toBeTruthy();
jest.runAllTimers();
await sleep(20);
wrapper.update();
// Mock trigger resize
@ -189,7 +189,7 @@ describe('Affix Render', () => {
.at(index)
.instance()
.onResize([{ target: { getBoundingClientRect: () => ({ width: 99, height: 99 }) } }]);
jest.runAllTimers();
await sleep(20);
expect(updateCalled).toHaveBeenCalled();
});

View File

@ -273,9 +273,7 @@ describe('Anchor Render', () => {
expect(wrapper.instance().state.activeLink).toBe('#API2');
});
it('Anchor targetOffset prop', () => {
jest.useFakeTimers();
it('Anchor targetOffset prop', async () => {
let dateNowMock;
function dataNowMockFn() {
@ -304,23 +302,22 @@ describe('Anchor Render', () => {
</Anchor>,
);
wrapper.instance().handleScrollTo('#API');
jest.runAllTimers();
await sleep(20);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 1000);
dateNowMock = dataNowMockFn();
wrapper.setProps({ offsetTop: 100 });
wrapper.instance().handleScrollTo('#API');
jest.runAllTimers();
await sleep(20);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 900);
dateNowMock = dataNowMockFn();
wrapper.setProps({ targetOffset: 200 });
wrapper.instance().handleScrollTo('#API');
jest.runAllTimers();
await sleep(20);
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
dateNowMock.mockRestore();
jest.useRealTimers();
});
it('Anchor onChange prop', async () => {

View File

@ -2,6 +2,7 @@ import React from 'react';
import { mount } from 'enzyme';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { sleep } from '../../../tests/utils';
describe('Collapse', () => {
// Fix css-animation deps on these
@ -55,8 +56,7 @@ describe('Collapse', () => {
expect(wrapper.render()).toMatchSnapshot();
});
it('could be expand and collapse', () => {
jest.useFakeTimers();
it('could be expand and collapse', async () => {
const wrapper = mount(
<Collapse>
<Collapse.Panel header="This is panel header 1" key="1">
@ -69,10 +69,8 @@ describe('Collapse', () => {
.find('.ant-collapse-header')
.at(0)
.simulate('click');
await sleep(400);
expect(wrapper.find('.ant-collapse-item').hasClass('ant-collapse-item-active')).toBe(true);
jest.runAllTimers();
expect(wrapper.find('.ant-collapse-item').hasClass('ant-collapse-item-active')).toBe(true);
jest.useRealTimers();
});
it('could override default openAnimation', () => {

View File

@ -4,6 +4,7 @@ import { mount } from 'enzyme';
import Input from '..';
import focusTest from '../../../tests/shared/focusTest';
import calculateNodeHeight, { calculateNodeStyling } from '../calculateNodeHeight';
import { sleep } from '../../../tests/utils';
const { TextArea } = Input;
@ -22,17 +23,15 @@ describe('TextArea', () => {
},
}),
});
jest.useFakeTimers();
});
afterAll(() => {
Object.defineProperty(window, 'getComputedStyle', {
value: originalGetComputedStyle,
});
jest.useRealTimers();
});
it('should auto calculate height according to content length', () => {
it('should auto calculate height according to content length', async () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const wrapper = mount(
@ -40,10 +39,10 @@ describe('TextArea', () => {
);
const mockFunc = jest.spyOn(wrapper.instance().resizableTextArea, 'resizeTextarea');
wrapper.setProps({ value: '1111\n2222\n3333' });
jest.runAllTimers();
await sleep(0);
expect(mockFunc).toHaveBeenCalledTimes(1);
wrapper.setProps({ value: '1111' });
jest.runAllTimers();
await sleep(0);
expect(mockFunc).toHaveBeenCalledTimes(2);
wrapper.update();
expect(wrapper.find('textarea').props().style.overflow).toBeFalsy();
@ -143,10 +142,10 @@ describe('TextArea', () => {
expect(onKeyDown).toHaveBeenCalled();
});
it('should trigger onResize', () => {
it('should trigger onResize', async () => {
const onResize = jest.fn();
const wrapper = mount(<TextArea onResize={onResize} autoSize />);
jest.runAllTimers();
await sleep(100);
wrapper
.find('ResizeObserver')
.instance()
@ -285,8 +284,7 @@ describe('TextArea allowClear', () => {
expect(onFocus).toHaveBeenCalled();
});
it('scroll to bottom when autoSize', () => {
jest.useFakeTimers();
it('scroll to bottom when autoSize', async () => {
const wrapper = mount(<Input.TextArea autoSize />, { attachTo: document.body });
wrapper.find('textarea').simulate('focus');
wrapper
@ -298,8 +296,7 @@ describe('TextArea allowClear', () => {
'setSelectionRange',
);
wrapper.find('textarea').simulate('input', { target: { value: '\n1' } });
jest.runAllTimers();
jest.useRealTimers();
await sleep(50);
expect(setSelectionRangeFn).toHaveBeenCalled();
wrapper.unmount();
});

View File

@ -84,7 +84,7 @@ describe('Slider', () => {
it('should keepAlign by calling forcePopupAlign', async () => {
const wrapper = mount(<Slider defaultValue={30} tooltipVisible />);
wrapper.find('Tooltip').instance().tooltip.forcePopupAlign = jest.fn();
await sleep(0);
await sleep(20);
expect(wrapper.find('Tooltip').instance().tooltip.forcePopupAlign).toHaveBeenCalled();
});
});

View File

@ -277,8 +277,29 @@ describe('Tooltip', () => {
<Tooltip
title="xxxxx"
placement="bottomLeft"
mouseEnterDelay={0}
mouseLeaveDelay={0}
visible
transitionName=""
>
<span>
Hello world!
</span>
</Tooltip>,
);
await sleep(300);
expect(wrapper.instance().getPopupDomNode().className).toContain('placement-bottomLeft');
wrapper.setProps({
placement: 'topRight',
});
await sleep(300);
expect(wrapper.instance().getPopupDomNode().className).toContain('placement-topRight');
});
it('other placement when mouse enter', async () => {
const wrapper = mount(
<Tooltip
title="xxxxx"
placement="topRight"
transitionName=""
>
<span>
Hello world!
@ -289,14 +310,7 @@ describe('Tooltip', () => {
expect(wrapper.find('span')).toHaveLength(1);
const button = wrapper.find('span').at(0);
button.simulate('mouseenter');
await sleep(50);
expect(wrapper.instance().getPopupDomNode().className).toContain('placement-bottomLeft');
button.simulate('mouseleave');
wrapper.setProps({
placement: 'topRight',
});
button.simulate('mouseenter');
await sleep(50);
await sleep(300);
expect(wrapper.instance().getPopupDomNode().className).toContain('placement-topRight');
});
});

View File

@ -8,6 +8,7 @@ import Base from '../Base'; // eslint-disable-line import/no-named-as-default
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import Typography from '../Typography';
import { sleep } from '../../../tests/utils';
jest.mock('copy-to-clipboard');
@ -43,16 +44,11 @@ describe('Typography', () => {
return style;
};
beforeAll(() => {
jest.useFakeTimers();
});
afterEach(() => {
errorSpy.mockReset();
});
afterAll(() => {
jest.useRealTimers();
errorSpy.mockRestore();
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
get: originOffsetHeight,
@ -75,33 +71,33 @@ describe('Typography', () => {
const fullStr =
'Bamboo is Little Light Bamboo is Little Light Bamboo is Little Light Bamboo is Little Light Bamboo is Little Light';
it('should trigger update', () => {
it('should trigger update', async () => {
const wrapper = mount(
<Base ellipsis component="p" editable>
{fullStr}
</Base>,
);
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('span:not(.anticon)').text()).toEqual('Bamboo is Little ...');
wrapper.setProps({ ellipsis: { rows: 2 } });
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('span:not(.anticon)').text()).toEqual(
'Bamboo is Little Light Bamboo is Litt...',
);
wrapper.setProps({ ellipsis: { rows: 99 } });
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual(fullStr);
wrapper.unmount();
});
it('should middle ellipsis', () => {
it('should middle ellipsis', async () => {
const suffix = '--suffix';
const wrapper = mount(
<Base ellipsis={{ rows: 1, suffix }} component="p">
@ -109,13 +105,13 @@ describe('Typography', () => {
</Base>,
);
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual('Bamboo is...--suffix');
wrapper.unmount();
});
it('should front or middle ellipsis', () => {
it('should front or middle ellipsis', async () => {
const suffix = '--The information is very important';
const wrapper = mount(
<Base ellipsis={{ rows: 1, suffix }} component="p">
@ -123,24 +119,24 @@ describe('Typography', () => {
</Base>,
);
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual('...--The information is very important');
wrapper.setProps({ ellipsis: { rows: 2, suffix } });
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual('Ba...--The information is very important');
wrapper.setProps({ ellipsis: { rows: 99, suffix } });
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual(fullStr + suffix);
wrapper.unmount();
});
it('connect children', () => {
it('connect children', async () => {
const bamboo = 'Bamboo';
const is = ' is ';
@ -153,13 +149,13 @@ describe('Typography', () => {
</Base>,
);
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('span:not(.anticon)').text()).toEqual('Bamboo is Little...');
});
it('should expandable work', () => {
it('should expandable work', async () => {
const onExpand = jest.fn();
const wrapper = mount(
<Base ellipsis={{ expandable: true, onExpand }} component="p" copyable editable>
@ -167,12 +163,12 @@ describe('Typography', () => {
</Base>,
);
jest.runAllTimers();
await sleep(20);
wrapper.update();
wrapper.find('.ant-typography-expand').simulate('click');
expect(onExpand).toHaveBeenCalled();
jest.runAllTimers();
await sleep(20);
wrapper.update();
expect(wrapper.find('p').text()).toEqual(fullStr);
@ -187,6 +183,7 @@ describe('Typography', () => {
describe('copyable', () => {
function copyTest(name, text, target) {
it(name, () => {
jest.useFakeTimers();
const onCopy = jest.fn();
const wrapper = mount(
<Base component="p" copyable={{ text, onCopy }}>
@ -210,6 +207,7 @@ describe('Typography', () => {
// Will set back when 3 seconds pass
expect(wrapper.find('.anticon-check').length).toBeFalsy();
jest.useRealTimers();
});
}

View File

@ -23,11 +23,6 @@ if (typeof window !== 'undefined') {
}
}
// The built-in requestAnimationFrame and cancelAnimationFrame not working with jest.runFakeTimes()
// https://github.com/facebook/jest/issues/5147
global.requestAnimationFrame = cb => setTimeout(cb, 0);
global.cancelAnimationFrame = cb => clearTimeout(cb, 0);
const Enzyme = require('enzyme');
const Adapter = require('enzyme-adapter-react-16');