313 lines
9.7 KiB
JavaScript
313 lines
9.7 KiB
JavaScript
import * as React from '../../../libs/horizon/src/external/Horizon';
|
||
import * as HorizonDOM from '../../../libs/horizon/src/dom/DOMExternal';
|
||
import { act } from '../jest/customMatcher';
|
||
|
||
|
||
describe('Hook Test', () => {
|
||
const {
|
||
useState,
|
||
useReducer,
|
||
useEffect,
|
||
useLayoutEffect,
|
||
useContext,
|
||
useMemo,
|
||
useCallback,
|
||
useRef,
|
||
useImperativeHandle,
|
||
forwardRef
|
||
} = React;
|
||
const { unmountComponentAtNode } = HorizonDOM;
|
||
let container = null;
|
||
beforeEach(() => {
|
||
// 创建一个 DOM 元素作为渲染目标
|
||
container = document.createElement('div');
|
||
document.body.appendChild(container);
|
||
});
|
||
|
||
afterEach(() => {
|
||
// 退出时进行清理
|
||
unmountComponentAtNode(container);
|
||
container.remove();
|
||
container = null;
|
||
});
|
||
|
||
|
||
it('简单使用useState', () => {
|
||
const App = () => {
|
||
const [num, setNum] = useState(0);
|
||
return (
|
||
<>
|
||
<p>{num}</p>
|
||
<button onClick={() => setNum(num + 1)} />
|
||
</>
|
||
)
|
||
}
|
||
HorizonDOM.render(<App />, container);
|
||
expect(container.querySelector('p').innerHTML).toBe('0');
|
||
// 点击按钮触发num加1
|
||
container.querySelector('button').click();
|
||
expect(container.querySelector('p').innerHTML).toBe('1');
|
||
});
|
||
|
||
it('简单使用useEffect', () => {
|
||
const App = () => {
|
||
const [num, setNum] = useState(0);
|
||
useEffect(() => {
|
||
document.getElementById('p').style.display = num === 0 ? 'none' : 'inline';
|
||
});
|
||
return (
|
||
<>
|
||
<p style={{ display: 'block' }} id="p">{num}</p>
|
||
<button onClick={() => setNum(num + 1)} />
|
||
</>
|
||
)
|
||
}
|
||
HorizonDOM.render(<App />, container);
|
||
expect(document.getElementById('p').style.display).toBe('block');
|
||
// 点击按钮触发num加1
|
||
container.querySelector('button').click();
|
||
expect(document.getElementById('p').style.display).toBe('none');
|
||
container.querySelector('button').click();
|
||
expect(container.querySelector('p').style.display).toBe('inline');
|
||
});
|
||
|
||
it('简单使用useLayoutEffect', () => {
|
||
const App = () => {
|
||
const [num, setNum] = useState(0);
|
||
useLayoutEffect(() => {
|
||
document.getElementById('p').style.display = num === 0 ? 'none' : 'inline';
|
||
});
|
||
return (
|
||
<>
|
||
<p style={{ display: 'block' }} id="p">{num}</p>
|
||
<button onClick={() => setNum(num + 1)} />
|
||
</>
|
||
)
|
||
}
|
||
HorizonDOM.render(<App />, container);
|
||
expect(document.getElementById('p').style.display).toBe('none');
|
||
container.querySelector('button').click();
|
||
expect(container.querySelector('p').style.display).toBe('inline');
|
||
});
|
||
|
||
it('简单使用useContext', () => {
|
||
const LanguageTypes = {
|
||
JAVA: 'Java',
|
||
JAVASCRIPT: 'JavaScript',
|
||
};
|
||
const defaultValue = { type: LanguageTypes.JAVASCRIPT };
|
||
const SystemLanguageContext = React.createContext(defaultValue);
|
||
|
||
const SystemLanguageProvider = ({ type, children }) => {
|
||
return (
|
||
<SystemLanguageContext.Provider value={{ type }}>
|
||
{children}
|
||
</SystemLanguageContext.Provider>
|
||
);
|
||
};
|
||
const TestFunction = () => {
|
||
const context = useContext(SystemLanguageContext);
|
||
return <p id="p">{context.type}</p>;
|
||
}
|
||
let setValue;
|
||
const App = () => {
|
||
const [value, _setValue] = useState(LanguageTypes.JAVA);
|
||
setValue = _setValue;
|
||
return (
|
||
<div className="App">
|
||
<SystemLanguageProvider type={value}>
|
||
<TestFunction />
|
||
</SystemLanguageProvider>
|
||
</div>
|
||
)
|
||
}
|
||
HorizonDOM.render(<TestFunction />, container);
|
||
// 测试当Provider未提供时,获取到的默认值'JavaScript'。
|
||
expect(container.querySelector('p').innerHTML).toBe('JavaScript');
|
||
unmountComponentAtNode(container);
|
||
HorizonDOM.render(<App />, container);
|
||
// 测试当Provider提供时,可以获取到Provider的值'Java'。
|
||
expect(container.querySelector('p').innerHTML).toBe('Java');
|
||
// 测试当Provider改变时,可以获取到最新Provider的值。
|
||
act(() => setValue(LanguageTypes.JAVASCRIPT));
|
||
expect(container.querySelector('p').innerHTML).toBe('JavaScript');
|
||
});
|
||
|
||
it('简单使用useReducer', () => {
|
||
const intlCar = { logo: '', price: 0 };
|
||
let dispatch;
|
||
const App = () => {
|
||
const carReducer = (state, action) => {
|
||
switch (action.logo) {
|
||
case 'ford':
|
||
return {
|
||
...intlCar,
|
||
logo: 'ford',
|
||
price: 76
|
||
};
|
||
case 'bmw':
|
||
return {
|
||
...intlCar,
|
||
logo: 'bmw',
|
||
price: 100
|
||
};
|
||
case 'benz':
|
||
return {
|
||
...intlCar,
|
||
logo: 'benz',
|
||
price: 80
|
||
};
|
||
default:
|
||
return {
|
||
...intlCar,
|
||
logo: 'audi',
|
||
price: 88
|
||
};
|
||
}
|
||
}
|
||
const [car, carDispatch] = useReducer(carReducer, intlCar);
|
||
dispatch = carDispatch;
|
||
return (
|
||
<div>
|
||
<p>{car.logo}</p>
|
||
<p id={'senP'}>{car.price}</p>
|
||
</div>
|
||
)
|
||
}
|
||
HorizonDOM.render(<App />, container);
|
||
expect(container.querySelector('p').innerHTML).toBe('');
|
||
expect(container.querySelector('#senP').innerHTML).toBe('0');
|
||
// 触发bmw
|
||
dispatch({ logo: 'bmw' });
|
||
expect(container.querySelector('p').innerHTML).toBe('bmw');
|
||
expect(container.querySelector('#senP').innerHTML).toBe('100');
|
||
// 触发carReducer里的switch的default项
|
||
dispatch({ logo: 'wrong logo' });
|
||
expect(container.querySelector('p').innerHTML).toBe('audi');
|
||
expect(container.querySelector('#senP').innerHTML).toBe('88');
|
||
});
|
||
|
||
it('测试useMemo', () => {
|
||
let setMemo;
|
||
const App = () => {
|
||
const [num, setNum] = useState(0);
|
||
const [memoDependent, _setMemo] = useState('App');
|
||
setMemo = _setMemo;
|
||
const text = useMemo(() => {
|
||
setNum(num + 1);
|
||
return memoDependent;
|
||
}, [memoDependent])
|
||
return (
|
||
<>
|
||
<p>{text}</p>
|
||
<p id="p">{num}</p>
|
||
</>
|
||
);
|
||
}
|
||
HorizonDOM.render(<App words="App" />, container);
|
||
expect(container.querySelector('p').innerHTML).toBe('App');
|
||
expect(container.querySelector('#p').innerHTML).toBe('1');
|
||
// 修改useMemo的依赖项,num会加一,text会改变。
|
||
setMemo('Apps')
|
||
expect(container.querySelector('p').innerHTML).toBe('Apps');
|
||
expect(container.querySelector('#p').innerHTML).toBe('2');
|
||
// useMemo的依赖项不变,num不会加一,text不会改变。
|
||
setMemo('Apps')
|
||
expect(container.querySelector('p').innerHTML).toBe('Apps');
|
||
expect(container.querySelector('#p').innerHTML).toBe('2');
|
||
// 修改useMemo的依赖项,num会加一,text会改变。
|
||
setMemo('App')
|
||
expect(container.querySelector('p').innerHTML).toBe('App');
|
||
expect(container.querySelector('#p').innerHTML).toBe('3');
|
||
});
|
||
|
||
it('测试useCallback', () => {
|
||
const App = (props) => {
|
||
const [num, setNum] = useState(0);
|
||
const NumUseCallback = useCallback(() => {
|
||
setNum(num + props.text)
|
||
}, [props]);
|
||
return (
|
||
<>
|
||
<p>{num}</p>
|
||
<button onClick={NumUseCallback} />
|
||
</>
|
||
)
|
||
}
|
||
HorizonDOM.render(<App text={1} />, container);
|
||
expect(container.querySelector('p').innerHTML).toBe('0');
|
||
// 点击按钮触发num加1
|
||
container.querySelector('button').click();
|
||
expect(container.querySelector('p').innerHTML).toBe('1');
|
||
// 再次点击,依赖项没变,num不增加
|
||
container.querySelector('button').click();
|
||
expect(container.querySelector('p').innerHTML).toBe('1');
|
||
|
||
HorizonDOM.render(<App text={2} />, container);
|
||
expect(container.querySelector('p').innerHTML).toBe('1');
|
||
// 依赖项有变化,点击按钮num增加
|
||
container.querySelector('button').click();
|
||
expect(container.querySelector('p').innerHTML).toBe('3');
|
||
});
|
||
|
||
it('测试useRef', () => {
|
||
const App = () => {
|
||
const [num, setNum] = useState(1);
|
||
const ref = useRef();
|
||
if (!ref.current) {
|
||
ref.current = num;
|
||
}
|
||
return (
|
||
<>
|
||
<p>{num}</p>
|
||
<p id="sp">{ref.current}</p>
|
||
<button onClick={() => setNum(num + 1)} />
|
||
</>
|
||
)
|
||
}
|
||
HorizonDOM.render(<App />, container);
|
||
expect(container.querySelector('p').innerHTML).toBe('1');
|
||
expect(container.querySelector('#sp').innerHTML).toBe('1');
|
||
// 点击按钮触发num加1,ref不变
|
||
container.querySelector('button').click();
|
||
expect(container.querySelector('p').innerHTML).toBe('2');
|
||
expect(container.querySelector('#sp').innerHTML).toBe('1');
|
||
});
|
||
|
||
it('测试useImperativeHandle', () => {
|
||
|
||
let App = (props, ref) => {
|
||
const [num, setNum] = useState(0);
|
||
useImperativeHandle(ref, () => ({num, setNum}), []);
|
||
return <p>{num}</p>;
|
||
}
|
||
let App1 = (props, ref) => {
|
||
const [num1, setNum1] = useState(0);
|
||
useImperativeHandle(ref, () => ({num1, setNum1}), [num1]);
|
||
return <p>{num1}</p>;
|
||
}
|
||
|
||
App = forwardRef(App);
|
||
App1 = forwardRef(App1);
|
||
const counter = React.createRef(null);
|
||
const counter1 = React.createRef(null);
|
||
HorizonDOM.render(<App ref={counter} />, container);
|
||
expect(counter.current.num).toBe(0);
|
||
act(() => {
|
||
counter.current.setNum(1);
|
||
});
|
||
// useImperativeHandle的dep为[],所以不会变
|
||
expect(counter.current.num).toBe(0);
|
||
// 清空container
|
||
unmountComponentAtNode(container);
|
||
|
||
HorizonDOM.render(<App1 ref={counter1} />, container);
|
||
expect(counter1.current.num1).toBe(0);
|
||
act(() => {
|
||
counter1.current.setNum1(1);
|
||
});
|
||
// useImperativeHandle的dep为[num1],所以会变
|
||
expect(counter1.current.num1).toBe(1);
|
||
});
|
||
});
|