mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 11:10:01 +08:00
chore: merge master
This commit is contained in:
commit
7460c95b65
@ -1,8 +1,7 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Anchor from '..';
|
||||
import type { InternalAnchorClass } from '../Anchor';
|
||||
import { sleep, render } from '../../../tests/utils';
|
||||
import { sleep, render, fireEvent } from '../../../tests/utils';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
@ -48,42 +47,54 @@ describe('Anchor Render', () => {
|
||||
|
||||
it('Anchor render perfectly', () => {
|
||||
const hash = getHashUrl();
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { container } = render(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.find(`a[href="#${hash}"]`).simulate('click');
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
anchorInstance.handleScroll();
|
||||
expect(anchorInstance.state).not.toBe(null);
|
||||
fireEvent.click(container.querySelector(`a[href="#${hash}"]`)!);
|
||||
anchorInstance!.handleScroll();
|
||||
expect(anchorInstance!.state).not.toBe(null);
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - click', () => {
|
||||
const hash = getHashUrl();
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { container } = render(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`http://www.example.com/#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.find(`a[href="http://www.example.com/#${hash}"]`).simulate('click');
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
expect(anchorInstance.state.activeLink).toBe(`http://www.example.com/#${hash}`);
|
||||
fireEvent.click(container.querySelector(`a[href="http://www.example.com/#${hash}"]`)!);
|
||||
expect(anchorInstance!.state!.activeLink).toBe(`http://www.example.com/#${hash}`);
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - hash router', async () => {
|
||||
const root = createDiv();
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
mount(<div id="/faq?locale=en#Q1">Q1</div>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
render(<div id="/faq?locale=en#Q1">Q1</div>, { container: root });
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
render(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href="/#/faq?locale=en#Q1" title="Q1" />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
anchorInstance.handleScrollTo('/#/faq?locale=en#Q1');
|
||||
expect(anchorInstance.state.activeLink).toBe('/#/faq?locale=en#Q1');
|
||||
anchorInstance!.handleScrollTo('/#/faq?locale=en#Q1');
|
||||
expect(anchorInstance!.state.activeLink).toBe('/#/faq?locale=en#Q1');
|
||||
expect(scrollToSpy).not.toHaveBeenCalled();
|
||||
await sleep(1000);
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
@ -92,32 +103,39 @@ describe('Anchor Render', () => {
|
||||
it('Anchor render perfectly for complete href - scroll', () => {
|
||||
const hash = getHashUrl();
|
||||
const root = createDiv();
|
||||
mount(<div id={hash}>Hello</div>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
render(<div id={hash}>Hello</div>, { container: root });
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
render(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`http://www.example.com/#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
anchorInstance.handleScroll();
|
||||
expect(anchorInstance.state.activeLink).toBe(`http://www.example.com/#${hash}`);
|
||||
anchorInstance!.handleScroll();
|
||||
expect(anchorInstance!.state!.activeLink).toBe(`http://www.example.com/#${hash}`);
|
||||
});
|
||||
|
||||
it('Anchor render perfectly for complete href - scrollTo', async () => {
|
||||
const hash = getHashUrl();
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
const root = createDiv();
|
||||
mount(<div id={`#${hash}`}>Hello</div>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
render(<div id={`#${hash}`}>Hello</div>, { container: root });
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
render(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`##${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
anchorInstance.handleScrollTo(`##${hash}`);
|
||||
expect(anchorInstance.state.activeLink).toBe(`##${hash}`);
|
||||
anchorInstance!.handleScrollTo(`##${hash}`);
|
||||
expect(anchorInstance!.state.activeLink).toBe(`##${hash}`);
|
||||
const calls = scrollToSpy.mock.calls.length;
|
||||
await sleep(1000);
|
||||
expect(scrollToSpy.mock.calls.length).toBeGreaterThan(calls);
|
||||
@ -125,15 +143,19 @@ describe('Anchor Render', () => {
|
||||
|
||||
it('should remove listener when unmount', async () => {
|
||||
const hash = getHashUrl();
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { unmount } = render(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
const removeListenerSpy = jest.spyOn((anchorInstance as any).scrollEvent, 'remove');
|
||||
wrapper.unmount();
|
||||
const removeListenerSpy = jest.spyOn((anchorInstance! as any).scrollEvent, 'remove');
|
||||
unmount();
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -154,23 +176,27 @@ describe('Anchor Render', () => {
|
||||
|
||||
it('should update links when link href update', async () => {
|
||||
const hash = getHashUrl();
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
function AnchorUpdate({ href }: { href: string }) {
|
||||
return (
|
||||
<Anchor>
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={href} title={hash} />
|
||||
</Anchor>
|
||||
);
|
||||
}
|
||||
const wrapper = mount(<AnchorUpdate href={`#${hash}`} />);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
const { rerender } = render(<AnchorUpdate href={`#${hash}`} />);
|
||||
|
||||
if (anchorInstance == null) {
|
||||
if (anchorInstance! == null) {
|
||||
throw new Error('anchorInstance should not be null');
|
||||
}
|
||||
|
||||
expect((anchorInstance as any).links).toEqual([`#${hash}`]);
|
||||
wrapper.setProps({ href: `#${hash}_1` });
|
||||
expect((anchorInstance as any).links).toEqual([`#${hash}_1`]);
|
||||
expect((anchorInstance as any)!.links).toEqual([`#${hash}`]);
|
||||
rerender(<AnchorUpdate href={`#${hash}_1`} />);
|
||||
expect((anchorInstance as any)!.links).toEqual([`#${hash}_1`]);
|
||||
});
|
||||
|
||||
it('Anchor onClick event', () => {
|
||||
@ -187,18 +213,20 @@ describe('Anchor Render', () => {
|
||||
|
||||
const href = `#${hash}`;
|
||||
const title = hash;
|
||||
|
||||
const wrapper = mount(
|
||||
<Anchor onClick={handleClick}>
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { container } = render(
|
||||
<Anchor
|
||||
onClick={handleClick}
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={href} title={title} />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.find(`a[href="${href}"]`).simulate('click');
|
||||
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
anchorInstance.handleScroll();
|
||||
fireEvent.click(container.querySelector(`a[href="${href}"]`)!);
|
||||
anchorInstance!.handleScroll();
|
||||
expect(event).not.toBe(undefined);
|
||||
expect(link).toEqual({ href, title });
|
||||
});
|
||||
@ -206,20 +234,28 @@ describe('Anchor Render', () => {
|
||||
it('Different function returns the same DOM', async () => {
|
||||
const hash = getHashUrl();
|
||||
const root = createDiv();
|
||||
mount(<div id={hash}>Hello</div>, { attachTo: root });
|
||||
render(<div id={hash}>Hello</div>, { container: root });
|
||||
const getContainerA = createGetContainer(hash);
|
||||
const getContainerB = createGetContainer(hash);
|
||||
|
||||
const wrapper = mount(
|
||||
<Anchor getContainer={getContainerA}>
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { rerender } = render(
|
||||
<Anchor
|
||||
getContainer={getContainerA}
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
const removeListenerSpy = jest.spyOn((anchorInstance as any).scrollEvent, 'remove');
|
||||
const removeListenerSpy = jest.spyOn((anchorInstance! as any).scrollEvent, 'remove');
|
||||
await sleep(1000);
|
||||
wrapper.setProps({ getContainer: getContainerB });
|
||||
rerender(
|
||||
<Anchor getContainer={getContainerB}>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -227,57 +263,73 @@ describe('Anchor Render', () => {
|
||||
const hash1 = getHashUrl();
|
||||
const hash2 = getHashUrl();
|
||||
const root = createDiv();
|
||||
mount(
|
||||
render(
|
||||
<div>
|
||||
<div id={hash1}>Hello</div>
|
||||
<div id={hash2}>World</div>
|
||||
</div>,
|
||||
{ attachTo: root },
|
||||
{ container: root },
|
||||
);
|
||||
const getContainerA = createGetContainer(hash1);
|
||||
const getContainerB = createGetContainer(hash2);
|
||||
const wrapper = mount(
|
||||
<Anchor getContainer={getContainerA}>
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { rerender } = render(
|
||||
<Anchor
|
||||
getContainer={getContainerA}
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
const removeListenerSpy = jest.spyOn((anchorInstance as any).scrollEvent, 'remove');
|
||||
const removeListenerSpy = jest.spyOn((anchorInstance! as any).scrollEvent, 'remove');
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
await sleep(1000);
|
||||
wrapper.setProps({ getContainer: getContainerB });
|
||||
rerender(
|
||||
<Anchor getContainer={getContainerB}>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
);
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Same function returns the same DOM', () => {
|
||||
const hash = getHashUrl();
|
||||
const root = createDiv();
|
||||
mount(<div id={hash}>Hello</div>, { attachTo: root });
|
||||
render(<div id={hash}>Hello</div>, { container: root });
|
||||
const getContainer = createGetContainer(hash);
|
||||
const wrapper = mount(
|
||||
<Anchor getContainer={getContainer}>
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { container } = render(
|
||||
<Anchor
|
||||
getContainer={getContainer}
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.find(`a[href="#${hash}"]`).simulate('click');
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
(anchorInstance as any).handleScroll();
|
||||
expect(anchorInstance.state).not.toBe(null);
|
||||
fireEvent.click(container.querySelector(`a[href="#${hash}"]`)!);
|
||||
|
||||
anchorInstance!.handleScroll();
|
||||
expect(anchorInstance!.state).not.toBe(null);
|
||||
});
|
||||
|
||||
it('Same function returns different DOM', async () => {
|
||||
const hash1 = getHashUrl();
|
||||
const hash2 = getHashUrl();
|
||||
const root = createDiv();
|
||||
mount(
|
||||
render(
|
||||
<div>
|
||||
<div id={hash1}>Hello</div>
|
||||
<div id={hash2}>World</div>
|
||||
</div>,
|
||||
{ attachTo: root },
|
||||
{ container: root },
|
||||
);
|
||||
const holdContainer = {
|
||||
container: document.getElementById(hash1),
|
||||
@ -288,19 +340,28 @@ describe('Anchor Render', () => {
|
||||
}
|
||||
return holdContainer.container;
|
||||
};
|
||||
const wrapper = mount(
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { rerender } = render(
|
||||
<Anchor
|
||||
getContainer={getContainer}
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn((anchorInstance! as any).scrollEvent, 'remove');
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
await sleep(1000);
|
||||
holdContainer.container = document.getElementById(hash2);
|
||||
rerender(
|
||||
<Anchor getContainer={getContainer}>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
const removeListenerSpy = jest.spyOn((anchorInstance as any).scrollEvent, 'remove');
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
await sleep(1000);
|
||||
holdContainer.container = document.getElementById(hash2);
|
||||
wrapper.setProps({ 'data-only-trigger-re-render': true });
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -323,27 +384,45 @@ describe('Anchor Render', () => {
|
||||
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
const root = createDiv();
|
||||
mount(<h1 id={hash}>Hello</h1>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
render(<h1 id={hash}>Hello</h1>, { container: root });
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { rerender } = render(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
const setProps = (props: Record<string, any>) =>
|
||||
rerender(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 1000);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ offsetTop: 100 });
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
setProps({ offsetTop: 100 });
|
||||
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 900);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ targetOffset: 200 });
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
setProps({ targetOffset: 200 });
|
||||
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
|
||||
|
||||
@ -370,27 +449,43 @@ describe('Anchor Render', () => {
|
||||
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
const root = createDiv();
|
||||
mount(<h1 id={hash}>Hello</h1>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
render(<h1 id={hash}>Hello</h1>, { container: root });
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { rerender } = render(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
const setProps = (props: Record<string, any>) =>
|
||||
rerender(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 1000);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ offsetTop: 100 });
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
setProps({ offsetTop: 100 });
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 900);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ targetOffset: 200 });
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
setProps({ targetOffset: 200 });
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
|
||||
|
||||
@ -401,33 +496,44 @@ describe('Anchor Render', () => {
|
||||
const hash1 = getHashUrl();
|
||||
const hash2 = getHashUrl();
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
<Anchor onChange={onChange}>
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
render(
|
||||
<Anchor
|
||||
onChange={onChange}
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
// https://github.com/testing-library/react-testing-library/releases/tag/v13.0.0
|
||||
// @ts-ignore
|
||||
{ legacyRoot: true },
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
expect(onChange).toHaveBeenCalledTimes(1);
|
||||
anchorInstance.handleScrollTo(hash2);
|
||||
anchorInstance!.handleScrollTo(hash2);
|
||||
expect(onChange).toHaveBeenCalledTimes(2);
|
||||
expect(onChange).toHaveBeenCalledWith(hash2);
|
||||
});
|
||||
|
||||
it('invalid hash', async () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { container } = render(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href="notexsited" title="title" />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.find(`a[href="notexsited"]`).simulate('click');
|
||||
fireEvent.click(container.querySelector(`a[href="notexsited"]`)!);
|
||||
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
anchorInstance.handleScrollTo('notexsited');
|
||||
expect(anchorInstance.state).not.toBe(null);
|
||||
anchorInstance!.handleScrollTo('notexsited');
|
||||
expect(anchorInstance!.state).not.toBe(null);
|
||||
});
|
||||
|
||||
it('test edge case when getBoundingClientRect return zero size', async () => {
|
||||
@ -454,27 +560,42 @@ describe('Anchor Render', () => {
|
||||
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
const root = createDiv();
|
||||
mount(<h1 id={hash}>Hello</h1>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
render(<h1 id={hash}>Hello</h1>, { container: root });
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { rerender } = render(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
const setProps = (props: Record<string, any>) =>
|
||||
rerender(
|
||||
<Anchor
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 1000);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ offsetTop: 100 });
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
setProps({ offsetTop: 100 });
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 900);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ targetOffset: 200 });
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
setProps({ targetOffset: 200 });
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
|
||||
|
||||
@ -505,27 +626,44 @@ describe('Anchor Render', () => {
|
||||
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
const root = createDiv();
|
||||
mount(<h1 id={hash}>Hello</h1>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor getContainer={() => document.body}>
|
||||
render(<h1 id={hash}>Hello</h1>, { container: root });
|
||||
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
const { rerender } = render(
|
||||
<Anchor
|
||||
getContainer={() => document.body}
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
const setProps = (props: Record<string, any>) =>
|
||||
rerender(
|
||||
<Anchor
|
||||
getContainer={() => document.body}
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<Link href={`#${hash}`} title={hash} />
|
||||
</Anchor>,
|
||||
);
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ offsetTop: 100 });
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
setProps({ offsetTop: 100 });
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ targetOffset: 200 });
|
||||
anchorInstance.handleScrollTo(`#${hash}`);
|
||||
setProps({ targetOffset: 200 });
|
||||
anchorInstance!.handleScrollTo(`#${hash}`);
|
||||
await sleep(30);
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
|
||||
|
||||
@ -537,15 +675,20 @@ describe('Anchor Render', () => {
|
||||
const hash1 = getHashUrl();
|
||||
const hash2 = getHashUrl();
|
||||
const getCurrentAnchor = () => `#${hash2}`;
|
||||
const wrapper = mount(
|
||||
<Anchor getCurrentAnchor={getCurrentAnchor}>
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
render(
|
||||
<Anchor
|
||||
getCurrentAnchor={getCurrentAnchor}
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
expect(anchorInstance.state.activeLink).toBe(`#${hash2}`);
|
||||
expect(anchorInstance!.state.activeLink).toBe(`#${hash2}`);
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/30584
|
||||
@ -553,16 +696,25 @@ describe('Anchor Render', () => {
|
||||
const hash1 = getHashUrl();
|
||||
const hash2 = getHashUrl();
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
<Anchor onChange={onChange} getCurrentAnchor={() => hash1}>
|
||||
let anchorInstance: InternalAnchorClass;
|
||||
render(
|
||||
<Anchor
|
||||
onChange={onChange}
|
||||
getCurrentAnchor={() => hash1}
|
||||
ref={node => {
|
||||
anchorInstance = node as InternalAnchorClass;
|
||||
}}
|
||||
>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
// https://github.com/testing-library/react-testing-library/releases/tag/v13.0.0
|
||||
// @ts-ignore
|
||||
{ legacyRoot: true },
|
||||
);
|
||||
const anchorInstance = wrapper.find('Anchor').last().instance() as any as InternalAnchorClass;
|
||||
|
||||
expect(onChange).toHaveBeenCalledTimes(1);
|
||||
anchorInstance.handleScrollTo(hash2);
|
||||
anchorInstance!.handleScrollTo(hash2);
|
||||
expect(onChange).toHaveBeenCalledTimes(2);
|
||||
expect(onChange).toHaveBeenCalledWith(hash2);
|
||||
});
|
||||
@ -572,16 +724,16 @@ describe('Anchor Render', () => {
|
||||
const hash1 = getHashUrl();
|
||||
const hash2 = getHashUrl();
|
||||
const getCurrentAnchor = jest.fn();
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Anchor getCurrentAnchor={getCurrentAnchor}>
|
||||
<Link href={`#${hash1}`} title={hash1} />
|
||||
<Link href={`#${hash2}`} title={hash2} />
|
||||
</Anchor>,
|
||||
);
|
||||
|
||||
wrapper.find(`a[href="#${hash1}"]`).simulate('click');
|
||||
fireEvent.click(container.querySelector(`a[href="#${hash1}"]`)!);
|
||||
expect(getCurrentAnchor).toHaveBeenCalledWith(`#${hash1}`);
|
||||
wrapper.find(`a[href="#${hash2}"]`).simulate('click');
|
||||
fireEvent.click(container.querySelector(`a[href="#${hash2}"]`)!);
|
||||
expect(getCurrentAnchor).toHaveBeenCalledWith(`#${hash2}`);
|
||||
});
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { memo, useState, useRef, useContext } from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Anchor from '../Anchor';
|
||||
import AnchorContext from '../context';
|
||||
import { getNodeText, render, fireEvent } from '../../../tests/utils';
|
||||
|
||||
// we use'memo' here in order to only render inner component while context changed.
|
||||
const CacheInner = memo(() => {
|
||||
@ -38,14 +38,16 @@ const CacheOuter = () => {
|
||||
};
|
||||
|
||||
it("Rendering on Anchor without changed AnchorContext won't trigger rendering on child component.", () => {
|
||||
const wrapper = mount(<CacheOuter />);
|
||||
const childCount = wrapper.find('#child_count').text();
|
||||
wrapper.find('#parent_btn').at(0).simulate('click');
|
||||
expect(wrapper.find('#parent_count').text()).toBe('2');
|
||||
const { container } = render(<CacheOuter />);
|
||||
const childCount = getNodeText(container.querySelector('#child_count')!);
|
||||
|
||||
fireEvent.click(container.querySelector('#parent_btn')!);
|
||||
|
||||
expect(getNodeText(container.querySelector('#parent_count')!)).toBe('2');
|
||||
// child component won't rerender
|
||||
expect(wrapper.find('#child_count').text()).toBe(childCount);
|
||||
wrapper.find('#parent_btn').at(0).simulate('click');
|
||||
expect(wrapper.find('#parent_count').text()).toBe('3');
|
||||
expect(getNodeText(container.querySelector('#child_count')!)).toBe(childCount);
|
||||
fireEvent.click(container.querySelector('#parent_btn')!);
|
||||
expect(getNodeText(container.querySelector('#parent_count')!)).toBe('3');
|
||||
// child component won't rerender
|
||||
expect(wrapper.find('#child_count').text()).toBe(childCount);
|
||||
expect(getNodeText(container.querySelector('#child_count')!)).toBe(childCount);
|
||||
});
|
||||
|
@ -31,7 +31,17 @@ export interface CarouselRef {
|
||||
}
|
||||
|
||||
const Carousel = React.forwardRef<CarouselRef, CarouselProps>(
|
||||
({ dots = true, arrows = false, draggable = false, dotPosition = 'bottom', ...props }, ref) => {
|
||||
(
|
||||
{
|
||||
dots = true,
|
||||
arrows = false,
|
||||
draggable = false,
|
||||
dotPosition = 'bottom',
|
||||
vertical = dotPosition === 'left' || dotPosition === 'right',
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const slickRef = React.useRef<any>();
|
||||
|
||||
@ -61,6 +71,7 @@ const Carousel = React.forwardRef<CarouselRef, CarouselProps>(
|
||||
}, [props.children]);
|
||||
|
||||
const newProps = {
|
||||
vertical,
|
||||
...props,
|
||||
};
|
||||
|
||||
@ -70,7 +81,6 @@ const Carousel = React.forwardRef<CarouselRef, CarouselProps>(
|
||||
|
||||
const prefixCls = getPrefixCls('carousel', newProps.prefixCls);
|
||||
const dotsClass = 'slick-dots';
|
||||
newProps.vertical = dotPosition === 'left' || dotPosition === 'right';
|
||||
|
||||
const enableDots = !!dots;
|
||||
const dsClass = classNames(
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render, fireEvent } from '../../../tests/utils';
|
||||
import Checkbox from '..';
|
||||
import focusTest from '../../../tests/shared/focusTest';
|
||||
import { resetWarned } from '../../_util/devWarning';
|
||||
@ -15,12 +15,14 @@ describe('Checkbox', () => {
|
||||
const onMouseEnter = jest.fn();
|
||||
const onMouseLeave = jest.fn();
|
||||
|
||||
const wrapper = mount(<Checkbox onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} />);
|
||||
const { container } = render(
|
||||
<Checkbox onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} />,
|
||||
);
|
||||
|
||||
wrapper.find('label').simulate('mouseenter');
|
||||
fireEvent.mouseEnter(container.querySelector('label'));
|
||||
expect(onMouseEnter).toHaveBeenCalled();
|
||||
|
||||
wrapper.find('label').simulate('mouseleave');
|
||||
fireEvent.mouseLeave(container.querySelector('label'));
|
||||
expect(onMouseLeave).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -28,7 +30,7 @@ describe('Checkbox', () => {
|
||||
resetWarned();
|
||||
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mount(<Checkbox value />);
|
||||
render(<Checkbox value />);
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Checkbox] `value` is not a valid prop, do you mean `checked`?',
|
||||
);
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Collapse from '../../collapse';
|
||||
import Table from '../../table';
|
||||
import Checkbox from '../index';
|
||||
@ -14,16 +13,16 @@ describe('CheckboxGroup', () => {
|
||||
|
||||
it('should work basically', () => {
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Checkbox.Group options={['Apple', 'Pear', 'Orange']} onChange={onChange} />,
|
||||
);
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[0]);
|
||||
expect(onChange).toHaveBeenCalledWith(['Apple']);
|
||||
wrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[1]);
|
||||
expect(onChange).toHaveBeenCalledWith(['Apple', 'Pear']);
|
||||
wrapper.find('.ant-checkbox-input').at(2).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[2]);
|
||||
expect(onChange).toHaveBeenCalledWith(['Apple', 'Pear', 'Orange']);
|
||||
wrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[1]);
|
||||
expect(onChange).toHaveBeenCalledWith(['Apple', 'Orange']);
|
||||
});
|
||||
|
||||
@ -35,12 +34,12 @@ describe('CheckboxGroup', () => {
|
||||
{ label: 'Pear', value: 'Pear' },
|
||||
];
|
||||
|
||||
const groupWrapper = mount(
|
||||
const { container } = render(
|
||||
<Checkbox.Group options={options} onChange={onChangeGroup} disabled />,
|
||||
);
|
||||
groupWrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[0]);
|
||||
expect(onChangeGroup).not.toHaveBeenCalled();
|
||||
groupWrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[1]);
|
||||
expect(onChangeGroup).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -52,17 +51,17 @@ describe('CheckboxGroup', () => {
|
||||
{ label: 'Orange', value: 'Orange', disabled: true },
|
||||
];
|
||||
|
||||
const groupWrapper = mount(<Checkbox.Group options={options} onChange={onChangeGroup} />);
|
||||
groupWrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
const { container } = render(<Checkbox.Group options={options} onChange={onChangeGroup} />);
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[0]);
|
||||
expect(onChangeGroup).toHaveBeenCalledWith(['Apple']);
|
||||
groupWrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[1]);
|
||||
expect(onChangeGroup).toHaveBeenCalledWith(['Apple']);
|
||||
});
|
||||
|
||||
it('all children should have a name property', () => {
|
||||
const wrapper = mount(<Checkbox.Group name="checkboxgroup" options={['Yes', 'No']} />);
|
||||
wrapper.find('input[type="checkbox"]').forEach(el => {
|
||||
expect(el.props().name).toEqual('checkboxgroup');
|
||||
const { container } = render(<Checkbox.Group name="checkboxgroup" options={['Yes', 'No']} />);
|
||||
[...container.querySelectorAll('input[type="checkbox"]')].forEach(el => {
|
||||
expect(el.getAttribute('name')).toEqual('checkboxgroup');
|
||||
});
|
||||
});
|
||||
|
||||
@ -72,9 +71,9 @@ describe('CheckboxGroup', () => {
|
||||
{ label: 'Orange', value: 'Orange', style: { fontSize: 12 } },
|
||||
];
|
||||
|
||||
const wrapper = mount(<Checkbox.Group prefixCls="my-checkbox" options={options} />);
|
||||
const { container } = render(<Checkbox.Group prefixCls="my-checkbox" options={options} />);
|
||||
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should be controlled by value', () => {
|
||||
@ -82,23 +81,22 @@ describe('CheckboxGroup', () => {
|
||||
{ label: 'Apple', value: 'Apple' },
|
||||
{ label: 'Orange', value: 'Orange' },
|
||||
];
|
||||
|
||||
const wrapper = mount(<Checkbox.Group options={options} />);
|
||||
expect(wrapper.find('.ant-checkbox-checked').length).toBe(0);
|
||||
wrapper.setProps({ value: ['Apple'] });
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-checkbox-checked').length).toBe(1);
|
||||
const renderCheckbox = props => <Checkbox.Group {...props} />;
|
||||
const { container, rerender } = render(renderCheckbox({ options }));
|
||||
expect(container.querySelectorAll('.ant-checkbox-checked').length).toBe(0);
|
||||
rerender(renderCheckbox({ options, value: 'Apple' }));
|
||||
expect(container.querySelectorAll('.ant-checkbox-checked').length).toBe(1);
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/12642
|
||||
it('should trigger onChange in sub Checkbox', () => {
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Checkbox.Group>
|
||||
<Checkbox value="my" onChange={onChange} />
|
||||
</Checkbox.Group>,
|
||||
);
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[0]);
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
expect(onChange.mock.calls[0][0].target.value).toEqual('my');
|
||||
});
|
||||
@ -143,7 +141,7 @@ describe('CheckboxGroup', () => {
|
||||
// https://github.com/ant-design/ant-design/issues/17297
|
||||
it('onChange should keep the order of the original values', () => {
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Checkbox.Group onChange={onChange}>
|
||||
<Checkbox key={1} value={1} />
|
||||
<Checkbox key={2} value={2} />
|
||||
@ -151,20 +149,19 @@ describe('CheckboxGroup', () => {
|
||||
<Checkbox key={4} value={4} />
|
||||
</Checkbox.Group>,
|
||||
);
|
||||
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[0]);
|
||||
expect(onChange).toHaveBeenCalledWith([1]);
|
||||
wrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[1]);
|
||||
expect(onChange).toHaveBeenCalledWith([1, 2]);
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[0]);
|
||||
expect(onChange).toHaveBeenCalledWith([2]);
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[0]);
|
||||
expect(onChange).toHaveBeenCalledWith([1, 2]);
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/21134
|
||||
it('should work when checkbox is wrapped by other components', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Checkbox.Group>
|
||||
<Collapse bordered={false}>
|
||||
<Collapse.Panel header="test panel">
|
||||
@ -175,28 +172,31 @@ describe('CheckboxGroup', () => {
|
||||
</Collapse>
|
||||
</Checkbox.Group>,
|
||||
);
|
||||
wrapper.find('.ant-collapse-item').at(0).find('.ant-collapse-header').simulate('click');
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
expect(wrapper.find('.ant-checkbox-checked').length).toBe(1);
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
expect(wrapper.find('.ant-checkbox-checked').length).toBe(0);
|
||||
|
||||
fireEvent.click(
|
||||
container.querySelector('.ant-collapse-item').querySelector('.ant-collapse-header'),
|
||||
);
|
||||
fireEvent.click(container.querySelector('.ant-checkbox-input'));
|
||||
expect(container.querySelectorAll('.ant-checkbox-checked').length).toBe(1);
|
||||
fireEvent.click(container.querySelector('.ant-checkbox-input'));
|
||||
expect(container.querySelectorAll('.ant-checkbox-checked').length).toBe(0);
|
||||
});
|
||||
|
||||
it('skipGroup', () => {
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Checkbox.Group onChange={onChange}>
|
||||
<Checkbox value={1} />
|
||||
<Checkbox value={2} skipGroup />
|
||||
</Checkbox.Group>,
|
||||
);
|
||||
wrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[1]);
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Table rowSelection', () => {
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Checkbox.Group onChange={onChange}>
|
||||
<Table
|
||||
dataSource={[{ key: 1, value: '1' }]}
|
||||
@ -205,27 +205,32 @@ describe('CheckboxGroup', () => {
|
||||
/>
|
||||
</Checkbox.Group>,
|
||||
);
|
||||
wrapper.find('.ant-checkbox-input').at(1).simulate('change');
|
||||
fireEvent.click(container.querySelectorAll('.ant-checkbox-input')[1]);
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should get div ref', () => {
|
||||
mount(
|
||||
const refCalls = [];
|
||||
render(
|
||||
<Checkbox.Group
|
||||
options={['Apple', 'Pear', 'Orange']}
|
||||
ref={node => {
|
||||
expect(node.nodeName).toBe('DIV');
|
||||
refCalls.push(node);
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
const [mountCall] = refCalls;
|
||||
expect(mountCall.nodeName).toBe('DIV');
|
||||
});
|
||||
|
||||
it('should support number option', () => {
|
||||
const onChange = jest.fn();
|
||||
|
||||
const wrapper = mount(<Checkbox.Group options={[1, 'Pear', 'Orange']} onChange={onChange} />);
|
||||
const { container } = render(
|
||||
<Checkbox.Group options={[1, 'Pear', 'Orange']} onChange={onChange} />,
|
||||
);
|
||||
|
||||
wrapper.find('.ant-checkbox-input').at(0).simulate('change');
|
||||
fireEvent.click(container.querySelector('.ant-checkbox-input'));
|
||||
expect(onChange).toHaveBeenCalledWith([1]);
|
||||
});
|
||||
|
||||
@ -251,17 +256,13 @@ describe('CheckboxGroup', () => {
|
||||
);
|
||||
};
|
||||
|
||||
const wrapper = mount(<Demo />);
|
||||
|
||||
wrapper.find('.ant-checkbox-input').first().simulate('change');
|
||||
const { container } = render(<Demo />);
|
||||
fireEvent.click(container.querySelector('.ant-checkbox-input'));
|
||||
expect(onChange).toHaveBeenCalledWith([]);
|
||||
wrapper.find('.ant-checkbox-input').first().simulate('change');
|
||||
fireEvent.click(container.querySelector('.ant-checkbox-input'));
|
||||
expect(onChange).toHaveBeenCalledWith(['length1']);
|
||||
wrapper
|
||||
.find('.ant-input')
|
||||
.first()
|
||||
.simulate('change', { target: { value: '' } });
|
||||
wrapper.find('.ant-checkbox-input').first().simulate('change');
|
||||
fireEvent.change(container.querySelector('.ant-input'), { target: { value: '' } });
|
||||
fireEvent.click(container.querySelector('.ant-checkbox-input'));
|
||||
expect(onChange).toHaveBeenCalledWith(['A']);
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { render, fireEvent } from '../../../tests/utils';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import Form from '../../form';
|
||||
@ -75,6 +76,40 @@ describe('Input', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('click focus', () => {
|
||||
it('click outside should also get focus', () => {
|
||||
const { container } = render(<Input suffix={<span className="test-suffix" />} />);
|
||||
const onFocus = jest.spyOn(container.querySelector('input')!, 'focus');
|
||||
fireEvent.mouseDown(container.querySelector('.test-suffix')!);
|
||||
fireEvent.mouseUp(container.querySelector('.test-suffix')!);
|
||||
expect(onFocus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('not get focus if out of component', () => {
|
||||
const holder = document.createElement('span');
|
||||
document.body.appendChild(holder);
|
||||
|
||||
const Popup = () => createPortal(<span className="popup" />, holder);
|
||||
|
||||
const { container } = render(
|
||||
<Input
|
||||
suffix={
|
||||
<span className="test-suffix">
|
||||
<Popup />
|
||||
</span>
|
||||
}
|
||||
/>,
|
||||
);
|
||||
|
||||
const onFocus = jest.spyOn(container.querySelector('input')!, 'focus');
|
||||
fireEvent.mouseDown(document.querySelector('.popup')!);
|
||||
fireEvent.mouseUp(document.querySelector('.popup')!);
|
||||
|
||||
expect(onFocus).not.toHaveBeenCalled();
|
||||
document.body.removeChild(holder);
|
||||
});
|
||||
});
|
||||
|
||||
it('set mouse cursor position', () => {
|
||||
const defaultValue = '11111';
|
||||
const valLength = defaultValue.length;
|
||||
|
@ -404,27 +404,6 @@ describe('TextArea allowClear', () => {
|
||||
expect(wrapper.find('input').props().value).toEqual('Light');
|
||||
});
|
||||
|
||||
describe('click focus', () => {
|
||||
it('click outside should also get focus', () => {
|
||||
const wrapper = mount(<Input suffix={<span className="test-suffix" />} />);
|
||||
const onFocus = jest.spyOn(wrapper.find('input').instance(), 'focus');
|
||||
wrapper.find('.test-suffix').simulate('mouseUp');
|
||||
expect(onFocus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('not get focus if out of component', () => {
|
||||
const wrapper = mount(<Input suffix={<span className="test-suffix" />} />);
|
||||
const onFocus = jest.spyOn(wrapper.find('input').instance(), 'focus');
|
||||
const ele = document.createElement('span');
|
||||
document.body.appendChild(ele);
|
||||
wrapper.find('.test-suffix').simulate('mouseUp', {
|
||||
target: ele,
|
||||
});
|
||||
expect(onFocus).not.toHaveBeenCalled();
|
||||
document.body.removeChild(ele);
|
||||
});
|
||||
});
|
||||
|
||||
it('scroll to bottom when autoSize', async () => {
|
||||
const wrapper = mount(<Input.TextArea autoSize />, { attachTo: document.body });
|
||||
wrapper.find('textarea').simulate('focus');
|
||||
|
@ -206,6 +206,7 @@ export interface ArgsProps {
|
||||
duration?: number | null;
|
||||
icon?: React.ReactNode;
|
||||
placement?: NotificationPlacement;
|
||||
maxCount?: number;
|
||||
style?: React.CSSProperties;
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
|
@ -12,7 +12,7 @@
|
||||
padding: @segmented-container-padding;
|
||||
color: @segmented-label-color;
|
||||
background-color: @segmented-bg;
|
||||
border-radius: 2px;
|
||||
border-radius: @border-radius-base;
|
||||
transition: all 0.3s @ease-in-out;
|
||||
|
||||
&-group {
|
||||
@ -67,7 +67,7 @@
|
||||
|
||||
// syntactic sugar to add `icon` for Segmented Item
|
||||
&-icon + * {
|
||||
margin-left: 6px;
|
||||
margin-left: @margin-sm / 2;
|
||||
}
|
||||
|
||||
&-input {
|
||||
|
@ -29,7 +29,7 @@ exports[`Space should render correct with children 1`] = `
|
||||
`;
|
||||
|
||||
exports[`Space should render width ConfigProvider 1`] = `
|
||||
Array [
|
||||
HTMLCollection [
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
@ -91,7 +91,7 @@ Array [
|
||||
`;
|
||||
|
||||
exports[`Space should render width rtl 1`] = `
|
||||
Array [
|
||||
HTMLCollection [
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-rtl ant-space-align-center"
|
||||
>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '../../../tests/utils';
|
||||
import Space from '..';
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import * as styleChecker from '../../_util/styleChecker';
|
||||
@ -12,13 +12,14 @@ jest.mock('../../_util/styleChecker', () => ({
|
||||
|
||||
describe('flex gap', () => {
|
||||
it('should render width empty children', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Space>
|
||||
<span />
|
||||
<span />
|
||||
</Space>,
|
||||
);
|
||||
expect(wrapper.getDOMNode()[1].style['column-gap']).toBe('8px');
|
||||
expect(wrapper.getDOMNode()[1].style['row-gap']).toBe('8px');
|
||||
|
||||
expect(container.querySelector('div.ant-space').style['column-gap']).toBe('8px');
|
||||
expect(container.querySelector('div.ant-space').style['row-gap']).toBe('8px');
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { render, fireEvent } from '../../../tests/utils';
|
||||
import Space from '..';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
@ -11,13 +10,13 @@ describe('Space', () => {
|
||||
rtlTest(Space);
|
||||
|
||||
it('should render width empty children', () => {
|
||||
const wrapper = mount(<Space />);
|
||||
const { container } = render(<Space />);
|
||||
|
||||
expect(wrapper.instance()).toBe(null);
|
||||
expect(container.children.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should render width ConfigProvider', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<ConfigProvider space={{ size: 'large' }}>
|
||||
<Space>
|
||||
<span>1</span>
|
||||
@ -34,11 +33,11 @@ describe('Space', () => {
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
expect(container.children).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render width rtl', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<ConfigProvider direction="rtl">
|
||||
<Space>
|
||||
<span>1</span>
|
||||
@ -55,46 +54,46 @@ describe('Space', () => {
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
expect(container.children).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render width customize size', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Space size={10}>
|
||||
<span>1</span>
|
||||
<span>2</span>
|
||||
</Space>,
|
||||
);
|
||||
|
||||
expect(wrapper.find('div.ant-space-item').at(0).prop('style').marginRight).toBe(10);
|
||||
expect(wrapper.find('div.ant-space-item').at(1).prop('style').marginRight).toBeUndefined();
|
||||
expect(container.querySelector('div.ant-space-item').style.marginRight).toBe('10px');
|
||||
expect(container.querySelectorAll('div.ant-space-item')[1].style.marginRight).toBe('');
|
||||
});
|
||||
|
||||
it('should render width size 0', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Space size={NaN}>
|
||||
<span>1</span>
|
||||
<span>2</span>
|
||||
</Space>,
|
||||
);
|
||||
|
||||
expect(wrapper.find('div.ant-space-item').at(0).prop('style').marginRight).toBe(0);
|
||||
expect(container.querySelector('div.ant-space-item').style.marginRight).toBe('0px');
|
||||
});
|
||||
|
||||
it('should render vertical space width customize size', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Space size={10} direction="vertical">
|
||||
<span>1</span>
|
||||
<span>2</span>
|
||||
</Space>,
|
||||
);
|
||||
|
||||
expect(wrapper.find('div.ant-space-item').at(0).prop('style').marginBottom).toBe(10);
|
||||
expect(wrapper.find('div.ant-space-item').at(1).prop('style').marginBottom).toBeUndefined();
|
||||
expect(container.querySelector('div.ant-space-item').style.marginBottom).toBe('10px');
|
||||
expect(container.querySelectorAll('div.ant-space-item')[1].style.marginBottom).toBe('');
|
||||
});
|
||||
|
||||
it('should render correct with children', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Space>
|
||||
text1<span>text1</span>
|
||||
{/* eslint-disable-next-line react/jsx-no-useless-fragment */}
|
||||
@ -102,18 +101,18 @@ describe('Space', () => {
|
||||
</Space>,
|
||||
);
|
||||
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
expect(container.children[0]).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render with invalidElement', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Space>
|
||||
text1<span>text1</span>
|
||||
text1
|
||||
</Space>,
|
||||
);
|
||||
|
||||
expect(wrapper.find('div.ant-space-item').length).toBe(3);
|
||||
expect(container.querySelectorAll('div.ant-space-item').length).toBe(3);
|
||||
});
|
||||
|
||||
it('should be keep store', () => {
|
||||
@ -144,25 +143,21 @@ describe('Space', () => {
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
const wrapper = mount(<SpaceDemo />);
|
||||
const { container } = render(<SpaceDemo />);
|
||||
|
||||
expect(wrapper.find('#demo').text()).toBe('1');
|
||||
expect(container.querySelector('#demo')).toHaveTextContent('1');
|
||||
|
||||
act(() => {
|
||||
wrapper.find('#demo').simulate('click');
|
||||
});
|
||||
fireEvent.click(container.querySelector('#demo'));
|
||||
|
||||
expect(wrapper.find('#demo').text()).toBe('2');
|
||||
expect(container.querySelector('#demo')).toHaveTextContent('2');
|
||||
|
||||
act(() => {
|
||||
wrapper.find('p').simulate('click');
|
||||
});
|
||||
fireEvent.click(container.querySelector('p'));
|
||||
|
||||
expect(wrapper.find('#demo').text()).toBe('2');
|
||||
expect(container.querySelector('#demo')).toHaveTextContent('2');
|
||||
});
|
||||
|
||||
it('split', () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Space split="-">
|
||||
text1<span>text1</span>
|
||||
{/* eslint-disable-next-line react/jsx-no-useless-fragment */}
|
||||
@ -170,13 +165,13 @@ describe('Space', () => {
|
||||
</Space>,
|
||||
);
|
||||
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
expect(container.children[0]).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/35305
|
||||
it('should not throw duplicated key warning', () => {
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
mount(
|
||||
render(
|
||||
<Space>
|
||||
<div key="1" />
|
||||
<div />
|
||||
|
@ -92,15 +92,12 @@ const Space: React.FC<SpaceProps> = props => {
|
||||
latestIndex = i;
|
||||
}
|
||||
|
||||
const keyOfChild = child && child.key;
|
||||
// Add `-space-item` as suffix in case simple key string trigger duplicated key warning
|
||||
// https://github.com/ant-design/ant-design/issues/35305
|
||||
const defaultKey = `${i}-space-item`;
|
||||
const key = (child && child.key) || `${itemClassName}-${i}`;
|
||||
|
||||
return (
|
||||
<Item
|
||||
className={itemClassName}
|
||||
key={`${itemClassName}-${keyOfChild || defaultKey}`}
|
||||
key={key}
|
||||
direction={direction}
|
||||
index={i}
|
||||
marginDirection={marginDirection}
|
||||
|
@ -2305,4 +2305,53 @@ describe('Table.filter', () => {
|
||||
);
|
||||
expect(errorSpy).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('can reset if filterResetToDefaultFilteredValue and filter is changing', () => {
|
||||
const wrapper = mount(
|
||||
createTable({
|
||||
columns: [
|
||||
{
|
||||
...column,
|
||||
filters: [
|
||||
{ text: 'Jack', value: 'Jack' },
|
||||
{ text: 'Lucy', value: 'Lucy' },
|
||||
],
|
||||
defaultFilteredValue: ['Jack'],
|
||||
filterResetToDefaultFilteredValue: true,
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
expect(wrapper.find('tbody tr').length).toBe(1);
|
||||
expect(wrapper.find('tbody tr').text()).toBe('Jack');
|
||||
|
||||
// open filter
|
||||
wrapper.find('span.ant-dropdown-trigger').first().simulate('click');
|
||||
expect(
|
||||
wrapper.find('.ant-table-filter-dropdown-btns .ant-btn-link').props().disabled,
|
||||
).toBeTruthy();
|
||||
expect(wrapper.find('li.ant-dropdown-menu-item').at(0).text()).toBe('Jack');
|
||||
expect(wrapper.find('li.ant-dropdown-menu-item').at(1).text()).toBe('Lucy');
|
||||
|
||||
// deselect default
|
||||
wrapper.find('li.ant-dropdown-menu-item').at(0).simulate('click');
|
||||
expect(
|
||||
wrapper.find('.ant-table-filter-dropdown-btns .ant-btn-link').props().disabled,
|
||||
).toBeFalsy();
|
||||
// select other one
|
||||
wrapper.find('li.ant-dropdown-menu-item').at(1).simulate('click');
|
||||
expect(
|
||||
wrapper.find('.ant-table-filter-dropdown-btns .ant-btn-link').props().disabled,
|
||||
).toBeFalsy();
|
||||
// deselect other one
|
||||
wrapper.find('li.ant-dropdown-menu-item').at(1).simulate('click');
|
||||
expect(
|
||||
wrapper.find('.ant-table-filter-dropdown-btns .ant-btn-link').props().disabled,
|
||||
).toBeFalsy();
|
||||
// select default
|
||||
wrapper.find('li.ant-dropdown-menu-item').at(0).simulate('click');
|
||||
expect(
|
||||
wrapper.find('.ant-table-filter-dropdown-btns .ant-btn-link').props().disabled,
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -407,16 +407,22 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
|
||||
);
|
||||
};
|
||||
|
||||
const getResetDisabled = () => {
|
||||
if (filterResetToDefaultFilteredValue) {
|
||||
return isEqual(
|
||||
(defaultFilteredValue || []).map(key => String(key)),
|
||||
selectedKeys,
|
||||
);
|
||||
}
|
||||
|
||||
return selectedKeys.length === 0;
|
||||
};
|
||||
|
||||
dropdownContent = (
|
||||
<>
|
||||
{getFilterComponent()}
|
||||
<div className={`${prefixCls}-dropdown-btns`}>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
disabled={selectedKeys.length === 0}
|
||||
onClick={() => onReset()}
|
||||
>
|
||||
<Button type="link" size="small" disabled={getResetDisabled()} onClick={() => onReset()}>
|
||||
{locale.filterReset}
|
||||
</Button>
|
||||
<Button type="primary" size="small" onClick={onConfirm}>
|
||||
|
@ -25,7 +25,7 @@ class ComponentDoc extends React.Component {
|
||||
expandAll: false,
|
||||
visibleAll: process.env.NODE_ENV !== 'production',
|
||||
showRiddleButton: false,
|
||||
react18Demo: true,
|
||||
react17Demo: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
@ -49,12 +49,12 @@ class ComponentDoc extends React.Component {
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const { location, theme } = this.props;
|
||||
const { location: nextLocation, theme: nextTheme } = nextProps;
|
||||
const { expandAll, visibleAll, showRiddleButton, react18Demo } = this.state;
|
||||
const { expandAll, visibleAll, showRiddleButton, react17Demo } = this.state;
|
||||
const {
|
||||
expandAll: nextExpandAll,
|
||||
visibleAll: nextVisibleAll,
|
||||
showRiddleButton: nextShowRiddleButton,
|
||||
react18Demo: nextReact18Demo,
|
||||
react17Demo: nextReact17Demo,
|
||||
} = nextState;
|
||||
|
||||
if (
|
||||
@ -64,7 +64,7 @@ class ComponentDoc extends React.Component {
|
||||
theme === nextTheme &&
|
||||
visibleAll === nextVisibleAll &&
|
||||
showRiddleButton === nextShowRiddleButton &&
|
||||
react18Demo === nextReact18Demo
|
||||
react17Demo === nextReact17Demo
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@ -90,9 +90,9 @@ class ComponentDoc extends React.Component {
|
||||
};
|
||||
|
||||
handleDemoVersionToggle = () => {
|
||||
const { react18Demo } = this.state;
|
||||
const { react17Demo } = this.state;
|
||||
this.setState({
|
||||
react18Demo: !react18Demo,
|
||||
react17Demo: !react17Demo,
|
||||
});
|
||||
};
|
||||
|
||||
@ -108,7 +108,7 @@ class ComponentDoc extends React.Component {
|
||||
} = this.props;
|
||||
const { content, meta } = doc;
|
||||
const demoValues = Object.keys(demos).map(key => demos[key]);
|
||||
const { expandAll, visibleAll, showRiddleButton, react18Demo } = this.state;
|
||||
const { expandAll, visibleAll, showRiddleButton, react17Demo } = this.state;
|
||||
const isSingleCol = meta.cols === 1;
|
||||
const leftChildren = [];
|
||||
const rightChildren = [];
|
||||
@ -131,7 +131,7 @@ class ComponentDoc extends React.Component {
|
||||
location={location}
|
||||
theme={theme}
|
||||
setIframeTheme={setIframeTheme}
|
||||
react18={react18Demo}
|
||||
react18={react17Demo}
|
||||
/>
|
||||
);
|
||||
if (index % 2 === 0 || isSingleCol) {
|
||||
@ -224,12 +224,12 @@ class ComponentDoc extends React.Component {
|
||||
title={
|
||||
<FormattedMessage
|
||||
id={`app.component.examples.${
|
||||
react18Demo ? 'openDemoNotReact18' : 'openDemoWithReact18'
|
||||
react17Demo ? 'openDemoWithReact18' : 'openDemoNotReact18'
|
||||
}`}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{react18Demo ? (
|
||||
{react17Demo ? (
|
||||
<ExperimentFilled
|
||||
className={expandTriggerClass}
|
||||
onClick={this.handleDemoVersionToggle}
|
||||
|
Loading…
Reference in New Issue
Block a user