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

452 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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';
describe('Context Test', () => {
const LogUtils = getLogUtils();
it('Provider及其内部consumer组件都不受制于shouldComponentUpdate函数或者Horizon.memo()', () => {
const LanguageTypes = {
JAVA: 'Java',
JAVASCRIPT: 'JavaScript',
};
const defaultValue = { type: LanguageTypes.JAVASCRIPT };
const SystemLanguageContext = Horizon.createContext(defaultValue);
const SystemLanguageConsumer = SystemLanguageContext.Consumer;
const SystemLanguageProvider = (props) => {
LogUtils.log('SystemLanguageProvider');
return (
<SystemLanguageContext.Provider value={props.type}>
{props.children}
</SystemLanguageContext.Provider>
);
};
const Consumer = () => {
LogUtils.log('Consumer');
return (
<SystemLanguageConsumer>
{type => {
LogUtils.log('Consumer DOM mutations');
return <p>{type}</p>;
}}
</SystemLanguageConsumer>
);
};
class Middle extends Horizon.Component {
shouldComponentUpdate() {
return false;
}
render() {
LogUtils.log('Middle');
return this.props.children;
}
}
const App = (props) => {
LogUtils.log('App');
return (
<SystemLanguageProvider type={props.value}>
<Middle>
<Middle>
<Consumer />
</Middle>
</Middle>
</SystemLanguageProvider>
);
};
Horizon.render(<App value={LanguageTypes.JAVA} />, container);
expect(container.querySelector('p').innerHTML).toBe('Java');
expect(LogUtils.getAndClear()).toEqual([
'App',
'SystemLanguageProvider',
'Middle',
'Middle',
'Consumer',
'Consumer DOM mutations'
]);
// 组件不变Middle没有更新消费者也不会执行
Horizon.render(<App value={LanguageTypes.JAVA} />, container);
expect(container.querySelector('p').innerHTML).toBe('Java');
expect(LogUtils.getAndClear()).toEqual([
'App',
'SystemLanguageProvider'
]);
Horizon.render(<App value={LanguageTypes.JAVASCRIPT} />, container);
expect(container.querySelector('p').innerHTML).toBe('JavaScript');
// 组件更新但是Middle没有更新会绕过Middle
expect(LogUtils.getAndClear()).toEqual([
'App',
'SystemLanguageProvider',
'Consumer DOM mutations'
]);
});
it('嵌套consumer provider', () => {
const Num = {
ONE: 1,
TWO: 2,
};
const NumberContext = Horizon.createContext(0);
const NumberConsumer = NumberContext.Consumer;
const NumberProvider = (props) => {
LogUtils.log(`SystemLanguageProvider: ${props.type}`);
return (
<NumberContext.Provider value={props.type}>
{props.children}
</NumberContext.Provider>
);
};
const Consumer = () => {
LogUtils.log('Consumer');
return (
<NumberConsumer>
{type => {
LogUtils.log('Consumer DOM mutations');
return <p>{type}</p>;
}}
</NumberConsumer>
);
};
class Middle extends Horizon.Component {
shouldComponentUpdate() {
return false;
}
render() {
LogUtils.log('Middle');
return this.props.children;
}
}
const App = (props) => {
LogUtils.log('App');
return (
<NumberProvider type={props.value}>
<NumberProvider type={props.value + 1}>
<Middle>
<Consumer />
</Middle>
</NumberProvider>
</NumberProvider>
);
};
// Consumer决定于距离它最近的provider
Horizon.render(<App value={Num.ONE} />, container);
expect(container.querySelector('p').innerHTML).toBe('2');
expect(LogUtils.getAndClear()).toEqual([
'App',
'SystemLanguageProvider: 1',
'SystemLanguageProvider: 2',
'Middle',
'Consumer',
'Consumer DOM mutations'
]);
// 更新
Horizon.render(<App value={Num.TWO} />, container);
expect(container.querySelector('p').innerHTML).toBe('3');
expect(LogUtils.getAndClear()).toEqual([
'App',
'SystemLanguageProvider: 2',
'SystemLanguageProvider: 3',
'Consumer DOM mutations'
]);
});
it('设置defaultValue', () => {
const Num = {
ONE: 1,
TWO: 2,
};
const NumberContext = Horizon.createContext(0);
const NewNumberContext = Horizon.createContext(1);
const NumberConsumer = NumberContext.Consumer;
const NumberProvider = props => {
return (
<NumberContext.Provider value={props.type}>
{props.children}
</NumberContext.Provider>
);
};
const NewNumberProvider = props => {
return (
<NewNumberContext.Provider value={props.type}>
{props.children}
</NewNumberContext.Provider>
);
};
class Middle extends Horizon.Component {
shouldComponentUpdate() {
return false;
}
render() {
return this.props.children;
}
}
const NewApp = (props) => {
return (
<NewNumberProvider value={props.value}>
<Middle>
<NumberConsumer>
{type => {
LogUtils.log('Consumer DOM mutations');
return <p>{type}</p>;
}}
</NumberConsumer>
</Middle>
</NewNumberProvider>
);
};
const App = (props) => {
return (
<NumberProvider value={props.value}>
<Middle>
<NumberConsumer>
{type => {
LogUtils.log('Consumer DOM mutations');
return <p>{type}</p>;
}}
</NumberConsumer>
</Middle>
</NumberProvider>
);
};
Horizon.render(<NewApp value={Num.ONE} />, container);
// 没有匹配到Provider,会使用defaultValue
expect(container.querySelector('p').innerHTML).toBe('0');
// 更新,设置value为undefined
Horizon.render(<App value={undefined} />, container);
// 设置value为undefined时defaultValue不生效
expect(container.querySelector('p').innerHTML).toBe('');
});
it('不同provider下的多个consumer', () => {
const NumContext = Horizon.createContext(1);
const Consumer = NumContext.Consumer;
function Provider(props) {
return (
<Consumer>
{value => (
<NumContext.Provider value={props.value || value * 2}>
{props.children}
</NumContext.Provider>
)}
</Consumer>
);
}
class Middle extends Horizon.Component {
shouldComponentUpdate() {
return false;
}
render() {
return this.props.children;
}
}
const App = props => {
return (
<Provider value={props.value}>
<Middle>
<Middle>
<Provider>
<Consumer>
{value => <p>{value}</p>}
</Consumer>
</Provider>
</Middle>
<Middle>
<Consumer>
{value => <p id='p'>{value}</p>}
</Consumer>
</Middle>
</Middle>
</Provider>
);
};
Horizon.render(<App value={2} />, container);
expect(container.querySelector('p').innerHTML).toBe('4');
expect(container.querySelector('#p').innerHTML).toBe('2');
Horizon.render(<App value={3} />, container);
expect(container.querySelector('p').innerHTML).toBe('6');
expect(container.querySelector('#p').innerHTML).toBe('3');
});
it('consumer里的child更新是不会重新渲染', () => {
const NumContext = Horizon.createContext(1);
const Consumer = NumContext.Consumer;
let setNum;
const ReturnDom = props => {
const [num, _setNum] = Horizon.useState(0);
setNum = _setNum;
LogUtils.log('ReturnDom');
return (
<p>{`Context: ${props.context}, Num: ${num}`}</p>
);
};
const App = props => {
return (
<NumContext.Provider value={props.value}>
<Consumer>
{value => {
LogUtils.log('Consumer');
return <ReturnDom context={value} />;
}}
</Consumer>
</NumContext.Provider>
);
};
Horizon.render(<App value={2} />, container);
expect(container.querySelector('p').innerHTML).toBe('Context: 2, Num: 0');
expect(LogUtils.getAndClear()).toEqual([
'Consumer',
'ReturnDom'
]);
setNum(3);
expect(container.querySelector('p').innerHTML).toBe('Context: 2, Num: 3');
expect(LogUtils.getAndClear()).toEqual(['ReturnDom']);
});
it('consumer可以拿到其他context的值', () => {
const NumContext = Horizon.createContext(1);
const TypeContext = Horizon.createContext('typeA');
const NumAndType = () => {
const type = Horizon.useContext(TypeContext);
return (
<NumContext.Consumer>
{value => {
LogUtils.log('Consumer');
return <p>{`Num: ${value}, Type: ${type}`}</p>;
}}
</NumContext.Consumer>
);
};
const App = props => {
return (
<NumContext.Provider value={props.num}>
<TypeContext.Provider value={props.type}>
<NumAndType />
</TypeContext.Provider>
</NumContext.Provider>
);
};
Horizon.render(<App num={2} type={'typeB'} />, container);
expect(container.querySelector('p').innerHTML).toBe('Num: 2, Type: typeB');
Horizon.render(<App num={2} type={'typeR'} />, container);
expect(container.querySelector('p').innerHTML).toBe('Num: 2, Type: typeR');
Horizon.render(<App num={8} type={'typeR'} />, container);
expect(container.querySelector('p').innerHTML).toBe('Num: 8, Type: typeR');
});
// antd menu 级连context场景menu路径使用级联context实现
it('nested context', () => {
const NestedContext = Horizon.createContext([]);
let updateContext;
function App() {
const [state, useState] = Horizon.useState([]);
updateContext = useState;
return (
<NestedContext.Provider value={state}>
<Sub1 />
<Sub2 />
</NestedContext.Provider>
);
}
const div1Ref = Horizon.createRef();
const div2Ref = Horizon.createRef();
let updateSub1;
function Sub1() {
const path = Horizon.useContext(NestedContext);
const [_, setState] = Horizon.useState({});
updateSub1 = () => setState({});
return (
<NestedContext.Provider value={[...path, 1]}>
<Son divRef={div1Ref} />
</NestedContext.Provider>
);
}
function Sub2() {
const path = Horizon.useContext(NestedContext);
return (
<NestedContext.Provider value={[...path, 2]}>
<Sub3 />
</NestedContext.Provider>
);
}
function Sub3() {
const path = Horizon.useContext(NestedContext);
return (
<NestedContext.Provider value={[...path, 3]}>
<Son divRef={div2Ref} />
</NestedContext.Provider>
);
}
function Son({ divRef }) {
const path = Horizon.useContext(NestedContext);
return (
<NestedContext.Provider value={path}>
<div ref={divRef}>{path.join(',')}</div>
</NestedContext.Provider>
);
}
Horizon.render(<App />, container);
updateSub1();
expect(div1Ref.current.innerHTML).toEqual('1');
expect(div2Ref.current.innerHTML).toEqual('2,3');
updateContext([0]);
expect(div1Ref.current.innerHTML).toEqual('0,1');
expect(div2Ref.current.innerHTML).toEqual('0,2,3');
// 局部更新Sub1
updateSub1();
expect(div1Ref.current.innerHTML).toEqual('0,1');
expect(div2Ref.current.innerHTML).toEqual('0,2,3');
});
});