inula/scripts/__tests__/ComponentTest/PortalComponent.test.js

290 lines
8.1 KiB
JavaScript
Executable File

/*
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
import * as Horizon from '@cloudsop/horizon/index.ts';
import { getLogUtils } from '../jest/testUtils';
import dispatchChangeEvent from '../utils/dispatchChangeEvent';
describe('PortalComponent Test', () => {
const LogUtils = getLogUtils();
it('将子节点渲染到存在于父组件以外的 DOM 节点', () => {
const portalRoot = document.createElement('div');
class PortalApp extends Horizon.Component {
constructor(props) {
super(props);
this.element = portalRoot;
}
render() {
return Horizon.createPortal(this.props.child, this.element);
}
}
Horizon.render(<PortalApp child={<div>PortalApp</div>} />, container);
expect(container.textContent).toBe('');
// <div>PortalApp</div>被渲染到了portalRoot而非container
expect(portalRoot.textContent).toBe('PortalApp');
Horizon.unmountComponentAtNode(container);
expect(container.textContent).toBe('');
expect(portalRoot.textContent).toBe('');
});
it('渲染多个Portal', () => {
const portalRoot1st = document.createElement('div');
const portalRoot2nd = document.createElement('div');
class PortalApp extends Horizon.Component {
constructor(props) {
super(props);
this.element = portalRoot1st;
this.newElement = portalRoot2nd;
}
render() {
return [
Horizon.createPortal(this.props.child, this.element),
Horizon.createPortal(this.props.child, this.newElement),
];
}
}
Horizon.render(<PortalApp child={<div>PortalApp</div>} />, container);
expect(container.textContent).toBe('');
// <div>PortalApp</div>被渲染到了portalRoot而非container
expect(portalRoot1st.textContent).toBe('PortalApp');
expect(portalRoot2nd.textContent).toBe('PortalApp');
Horizon.unmountComponentAtNode(container);
expect(container.textContent).toBe('');
expect(portalRoot1st.textContent).toBe('');
expect(portalRoot2nd.textContent).toBe('');
});
it('渲染最近的Portal', () => {
const portalRoot1st = document.createElement('div');
const portalRoot2nd = document.createElement('div');
const portalRoot3rd = document.createElement('div');
class PortalApp extends Horizon.Component {
constructor(props) {
super(props);
this.element = portalRoot1st;
this.newElement = portalRoot2nd;
this.element3rd = portalRoot3rd;
}
render() {
return [
<div>PortalApp1st</div>,
Horizon.createPortal(
[<div>PortalApp4</div>, Horizon.createPortal(this.props.child, this.element3rd)],
this.element
),
<div>PortalApp2nd</div>,
Horizon.createPortal(this.props.child, this.newElement),
];
}
}
Horizon.render(<PortalApp child={<div>PortalApp</div>} />, container);
expect(container.textContent).toBe('PortalApp1stPortalApp2nd');
// <div>PortalApp4</div>会挂载在this.element上
expect(portalRoot1st.textContent).toBe('PortalApp4');
expect(portalRoot2nd.textContent).toBe('PortalApp');
expect(portalRoot3rd.textContent).toBe('PortalApp');
Horizon.unmountComponentAtNode(container);
expect(container.textContent).toBe('');
expect(portalRoot1st.textContent).toBe('');
expect(portalRoot2nd.textContent).toBe('');
});
it('改变Portal的参数', () => {
const portalRoot = document.createElement('div');
class PortalApp extends Horizon.Component {
constructor(props) {
super(props);
this.element = portalRoot;
}
render() {
return Horizon.createPortal(this.props.child, this.element);
}
}
Horizon.render(<PortalApp key="portal" child={<div>PortalApp</div>} />, container);
expect(container.textContent).toBe('');
expect(portalRoot.textContent).toBe('PortalApp');
Horizon.render(<PortalApp key="portal" child={<div>AppPortal</div>} />, container);
expect(container.textContent).toBe('');
expect(portalRoot.textContent).toBe('AppPortal');
Horizon.render(<PortalApp key="portal" child={['por', 'tal']} />, container);
expect(container.textContent).toBe('');
expect(portalRoot.textContent).toBe('portal');
Horizon.render(<PortalApp key="portal" child={null} />, container);
expect(container.textContent).toBe('');
expect(portalRoot.textContent).toBe('');
Horizon.unmountComponentAtNode(container);
expect(container.textContent).toBe('');
expect(portalRoot.textContent).toBe('');
});
it('通过Portal进行事件冒泡', () => {
const portalRoot = document.createElement('div');
const buttonRef = Horizon.createRef();
class PortalApp extends Horizon.Component {
constructor(props) {
super(props);
this.element = portalRoot;
}
render() {
return Horizon.createPortal(this.props.child, this.element);
}
}
const Child = () => {
return (
<div>
<button ref={buttonRef}>Click</button>
</div>
);
};
const App = () => {
const handleClick = () => {
LogUtils.log('bubble click event');
};
const handleCaptureClick = () => {
LogUtils.log('capture click event');
};
return (
<div onClickCapture={handleCaptureClick()} onClick={handleClick()}>
<PortalApp child={<Child />}></PortalApp>
</div>
);
};
Horizon.render(<App />, container);
const event = document.createEvent('Event');
event.initEvent('click', true, true);
buttonRef.current.dispatchEvent(event);
expect(LogUtils.getAndClear()).toEqual([
// 从外到内先捕获再冒泡
'capture click event',
'bubble click event',
]);
});
it('Create portal at app root should not add event listener multiple times', () => {
const btnRef = Horizon.createRef();
class PortalApp extends Horizon.Component {
constructor(props) {
super(props);
}
render() {
return Horizon.createPortal(this.props.child, container);
}
}
const onClick = jest.fn();
class App extends Horizon.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<button onClick={onClick} ref={btnRef}></button>
<PortalApp />
</div>
);
}
}
Horizon.render(<App />, container);
btnRef.current.click();
expect(onClick).toHaveBeenCalledTimes(1);
});
it('#76 Portal onChange should activate', () => {
class Dialog extends Horizon.Component {
node;
constructor(props) {
super(props);
this.node = window.document.createElement('div');
window.document.body.appendChild(this.node);
}
render() {
return Horizon.createPortal(this.props.children, this.node);
}
}
let showPortalInput;
const fn = jest.fn();
const inputRef = Horizon.createRef();
function App() {
const Input = () => {
const [show, setShow] = Horizon.useState(false);
showPortalInput = setShow;
Horizon.useEffect(() => {
setTimeout(() => {
setShow(true);
}, 0);
}, []);
if (!show) {
return null;
}
return <input onChange={fn} ref={inputRef} />;
};
return (
<div>
<Dialog>
<Input />
</Dialog>
</div>
);
}
Horizon.render(<App />, container);
showPortalInput(true);
jest.advanceTimersToNextTimer();
dispatchChangeEvent(inputRef.current, 'test');
expect(fn).toHaveBeenCalledTimes(1);
});
});