Match-id-1988199472c662613fee402f6bd87513d3016c2b
This commit is contained in:
parent
d090158b1b
commit
5a06b9b663
|
@ -0,0 +1,249 @@
|
|||
import * as React from '../../../libs/horizon/src/external/Horizon';
|
||||
import * as HorizonDOM from '../../../libs/horizon/src/dom/DOMExternal';
|
||||
import * as LogUtils from '../jest/logUtils';
|
||||
import { act } from '../jest/customMatcher';
|
||||
|
||||
describe('Hook Test', () => {
|
||||
const { useMemo, useRef, useState, useImperativeHandle, forwardRef, useLayoutEffect, useEffect } = React;
|
||||
const { unmountComponentAtNode } = HorizonDOM;
|
||||
let container = null;
|
||||
beforeEach(() => {
|
||||
LogUtils.clear();
|
||||
// 创建一个 DOM 元素作为渲染目标
|
||||
container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// 退出时进行清理
|
||||
unmountComponentAtNode(container);
|
||||
container.remove();
|
||||
container = null;
|
||||
LogUtils.clear();
|
||||
});
|
||||
|
||||
const Text = (props) => {
|
||||
LogUtils.log(props.text);
|
||||
return <p>{props.text}</p>;
|
||||
}
|
||||
|
||||
describe('useLayoutEffect Test', () => {
|
||||
it('useLayoutEffect的触发时序', () => {
|
||||
const App = (props) => {
|
||||
useLayoutEffect(() => {
|
||||
LogUtils.log('LayoutEffect');
|
||||
});
|
||||
return <Text text={props.num} />;
|
||||
}
|
||||
HorizonDOM.render(<App num={1} />, container, () => LogUtils.log('Sync effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
1,
|
||||
// 同步在渲染之后
|
||||
'LayoutEffect',
|
||||
'Sync effect'
|
||||
]);
|
||||
expect(container.querySelector('p').innerHTML).toBe('1');
|
||||
// 更新
|
||||
HorizonDOM.render(<App num={2} />, container, () => LogUtils.log('Sync effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
2,
|
||||
'LayoutEffect',
|
||||
'Sync effect'
|
||||
]);
|
||||
expect(container.querySelector('p').innerHTML).toBe('2');
|
||||
});
|
||||
|
||||
it('创建,销毁useLayoutEffect', () => {
|
||||
const App = (props) => {
|
||||
useEffect(() => {
|
||||
LogUtils.log(`num effect [${props.num}]`);
|
||||
return () => {
|
||||
LogUtils.log('num effect destroy');
|
||||
};
|
||||
}, [props.num]);
|
||||
useLayoutEffect(() => {
|
||||
LogUtils.log(`num Layouteffect [${props.num}]`);
|
||||
return () => {
|
||||
LogUtils.log(`num [${props.num}] Layouteffect destroy`);
|
||||
};
|
||||
}, [props.num]);
|
||||
return <Text text={'num: ' + props.num} />;
|
||||
}
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(<App num={0} />, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num: 0',
|
||||
'num Layouteffect [0]',
|
||||
'callback effect'
|
||||
]);
|
||||
expect(container.textContent).toBe('num: 0');
|
||||
})
|
||||
|
||||
// 更新
|
||||
act(() => {
|
||||
HorizonDOM.render(<App num={1} />, container, () => LogUtils.log('callback effect'));
|
||||
})
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
// 异步effect
|
||||
'num effect [0]',
|
||||
'num: 1',
|
||||
// 旧Layouteffect销毁
|
||||
'num [0] Layouteffect destroy',
|
||||
// 新Layouteffect建立
|
||||
'num Layouteffect [1]',
|
||||
'callback effect',
|
||||
// 异步旧的effect销毁
|
||||
'num effect destroy',
|
||||
// 异步新的effect建立
|
||||
'num effect [1]'
|
||||
]);
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
|
||||
})
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
// 同步Layouteffect销毁
|
||||
'num [1] Layouteffect destroy',
|
||||
'callback effect',
|
||||
// 最后执行异步effect销毁
|
||||
'num effect destroy',
|
||||
]);
|
||||
});
|
||||
})
|
||||
|
||||
describe('useMemo Test', () => {
|
||||
it('触发useMemo', () => {
|
||||
const App = (props) => {
|
||||
const num = useMemo(() => {
|
||||
LogUtils.log(props._num);
|
||||
return props._num + 1;
|
||||
}, [props._num]);
|
||||
return <Text text={num} />;
|
||||
}
|
||||
HorizonDOM.render(<App _num={0} />, container);
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
0,
|
||||
1
|
||||
]);
|
||||
expect(container.textContent).toBe('1');
|
||||
|
||||
HorizonDOM.render(<App _num={1} />, container);
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
1,
|
||||
2
|
||||
]);
|
||||
expect(container.textContent).toBe('2');
|
||||
|
||||
HorizonDOM.render(<App _num={1} />, container);
|
||||
// 不会触发useMemo
|
||||
expect(LogUtils.getAndClear()).toEqual([2]);
|
||||
expect(container.textContent).toBe('2');
|
||||
|
||||
HorizonDOM.render(<App _num={2} />, container);
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
2,
|
||||
3
|
||||
]);
|
||||
expect(container.textContent).toBe('3');
|
||||
});
|
||||
|
||||
it('输入不变,重新渲染也会触发useMemo', () => {
|
||||
const App = (props) => {
|
||||
const num = useMemo(props._num);
|
||||
return <Text text={num} />;
|
||||
}
|
||||
|
||||
const num1 = () => {
|
||||
LogUtils.log('num 1');
|
||||
return 1;
|
||||
}
|
||||
|
||||
const num2 = () => {
|
||||
LogUtils.log('num 2');
|
||||
return 2;
|
||||
}
|
||||
|
||||
HorizonDOM.render(<App _num={num1} />, container);
|
||||
expect(LogUtils.getAndClear()).toEqual(['num 1', 1]);
|
||||
|
||||
HorizonDOM.render(<App _num={num1} />, container);
|
||||
expect(LogUtils.getAndClear()).toEqual(['num 1', 1]);
|
||||
|
||||
HorizonDOM.render(<App _num={num1} />, container);
|
||||
expect(LogUtils.getAndClear()).toEqual(['num 1', 1]);
|
||||
|
||||
HorizonDOM.render(<App _num={num2} />, container);
|
||||
expect(LogUtils.getAndClear()).toEqual(['num 2', 2]);
|
||||
});
|
||||
})
|
||||
|
||||
describe('useRef Test', () => {
|
||||
it('更新current值时不会re-render', () => {
|
||||
const App = () => {
|
||||
const ref = useRef(1);
|
||||
return (
|
||||
<>
|
||||
<button onClick={() => {
|
||||
ref.current += 1;
|
||||
}}>
|
||||
button
|
||||
</button>
|
||||
<Text text={ref.current} />;
|
||||
</>
|
||||
)
|
||||
|
||||
}
|
||||
HorizonDOM.render(<App />, container);
|
||||
expect(LogUtils.getAndClear()).toEqual([1]);
|
||||
expect(container.querySelector('p').innerHTML).toBe('1');
|
||||
// 点击按钮触发ref.current加1
|
||||
container.querySelector('button').click();
|
||||
// ref.current改变不会触发重新渲染
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
expect(container.querySelector('p').innerHTML).toBe('1');
|
||||
});
|
||||
})
|
||||
|
||||
describe('useImperativeHandle Test', () => {
|
||||
it('useImperativeHandle没有配置dep时自动更新', () => {
|
||||
|
||||
let App = (props, ref) => {
|
||||
const [num, setNum] = useState(0);
|
||||
useImperativeHandle(ref, () => ({ num, setNum }));
|
||||
return <Text text={num} />;
|
||||
}
|
||||
let App1 = (props, ref) => {
|
||||
const [num1, setNum1] = useState(0);
|
||||
useImperativeHandle(ref, () => ({ num1, setNum1 }), []);
|
||||
return <Text text={num1} />;
|
||||
}
|
||||
|
||||
App = forwardRef(App);
|
||||
App1 = forwardRef(App1);
|
||||
const counter = React.createRef(null);
|
||||
const counter1 = React.createRef(null);
|
||||
HorizonDOM.render(<App ref={counter} />, container);
|
||||
expect(LogUtils.getAndClear()).toEqual([0]);
|
||||
expect(counter.current.num).toBe(0);
|
||||
act(() => {
|
||||
counter.current.setNum(1);
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual([1]);
|
||||
// useImperativeHandle没有配置的dep,所以会自动更新
|
||||
expect(counter.current.num).toBe(1);
|
||||
// 清空container
|
||||
unmountComponentAtNode(container);
|
||||
|
||||
HorizonDOM.render(<App1 ref={counter1} />, container);
|
||||
expect(LogUtils.getAndClear()).toEqual([0]);
|
||||
expect(counter1.current.num1).toBe(0);
|
||||
act(() => {
|
||||
counter1.current.setNum1(1);
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual([1]);
|
||||
// useImperativeHandle的dep为[],所以不会变
|
||||
expect(counter1.current.num1).toBe(0);
|
||||
});
|
||||
})
|
||||
})
|
|
@ -4,7 +4,7 @@ import * as LogUtils from '../jest/logUtils';
|
|||
import { act } from '../jest/customMatcher';
|
||||
|
||||
describe('useEffect Hook Test', () => {
|
||||
const { useEffect, useLayoutEffect, useState, memo } = React;
|
||||
const { useEffect, useLayoutEffect, useState, memo, forwardRef, useImperativeHandle } = React;
|
||||
const { unmountComponentAtNode } = HorizonDOM;
|
||||
let container = null;
|
||||
beforeEach(() => {
|
||||
|
@ -27,6 +27,30 @@ describe('useEffect Hook Test', () => {
|
|||
return <p>{props.text}</p>;
|
||||
}
|
||||
|
||||
it('act方法', () => {
|
||||
const App = () => {
|
||||
return <Text text={'op'} />;
|
||||
}
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(<App />, container, () => {
|
||||
LogUtils.log('num effect');
|
||||
});
|
||||
// 第一次渲染为同步,所以同步执行的可以写在act里做判断
|
||||
expect(LogUtils.getAndClear()).toEqual(['op', 'num effect']);
|
||||
expect(container.textContent).toBe('op');
|
||||
});
|
||||
act(() => {
|
||||
HorizonDOM.render(null, container, () => {
|
||||
LogUtils.log('num effect89');
|
||||
});
|
||||
// 第二次渲染为异步,所以同步执行的不可以写在act里做判断,act里拿到的为空数组
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['num effect89']);
|
||||
expect(container.textContent).toBe('');
|
||||
});
|
||||
|
||||
it('兄弟节点被删除,useEffect依然正常', () => {
|
||||
const App = () => {
|
||||
return <Text text="App" />;
|
||||
|
@ -123,13 +147,19 @@ describe('useEffect Hook Test', () => {
|
|||
HorizonDOM.render(<App num={0} />, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual(['num: 0', 'callback effect']);
|
||||
expect(container.textContent).toEqual('num: 0');
|
||||
HorizonDOM.render(<App num={1} />, container, () => LogUtils.log('callback effect'));
|
||||
// 执行新的render前,会执行旧render的useEffect,所以会添加'First effect [0]'
|
||||
expect(LogUtils.getAndClear()).toEqual(['First effect [0]', 'num: 1', 'callback effect']);
|
||||
expect(container.textContent).toEqual('num: 1');
|
||||
})
|
||||
// 最后在act执行完后会执行新render的useEffect
|
||||
expect(LogUtils.getAndClear()).toEqual(['First effect [1]']);
|
||||
expect(LogUtils.getAndClear()).toEqual(['First effect [0]']);
|
||||
act(() => {
|
||||
HorizonDOM.render(<App num={1} />, container, () => LogUtils.log('callback effect'));
|
||||
|
||||
})
|
||||
// 此时异步执行,act执行完后会执行新render的useEffect
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num: 1',
|
||||
'callback effect',
|
||||
'First effect [1]'
|
||||
]);
|
||||
expect(container.textContent).toEqual('num: 1');
|
||||
});
|
||||
|
||||
it('混合使用useEffect', () => {
|
||||
|
@ -150,10 +180,16 @@ describe('useEffect Hook Test', () => {
|
|||
expect(LogUtils.getAndClear()).toEqual(['First effect [0]', 'Second effect [0]']);
|
||||
act(() => {
|
||||
HorizonDOM.render(<App num={1} />, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual(['num: 1', 'callback effect']);
|
||||
expect(container.textContent).toEqual('num: 1');
|
||||
})
|
||||
expect(LogUtils.getAndClear()).toEqual(['First effect [1]', 'Second effect [1]']);
|
||||
// 第二次render时异步执行,act保证所有效果都已更新,所以先常规记录日志
|
||||
// 然后记录useEffect的日志
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num: 1',
|
||||
'callback effect',
|
||||
'First effect [1]',
|
||||
'Second effect [1]'
|
||||
]);
|
||||
expect(container.textContent).toEqual('num: 1');
|
||||
});
|
||||
|
||||
it('创建,销毁useEffect', () => {
|
||||
|
@ -202,14 +238,13 @@ describe('useEffect Hook Test', () => {
|
|||
act(() => {
|
||||
// 此时word改变,num不变
|
||||
HorizonDOM.render(<App num={0} word={'React'} />, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num: 0,word: React',
|
||||
'word Layouteffect destroy',
|
||||
'word Layouteffect [React]',
|
||||
'callback effect'
|
||||
]);
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num: 0,word: React',
|
||||
'word Layouteffect destroy',
|
||||
'word Layouteffect [React]',
|
||||
'callback effect',
|
||||
// 最后执行异步的
|
||||
'word effect destroy',
|
||||
'word effect [React]',
|
||||
]);
|
||||
|
@ -217,13 +252,12 @@ describe('useEffect Hook Test', () => {
|
|||
act(() => {
|
||||
// 此时num和word的所有effect都销毁
|
||||
HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num Layouteffect destroy',
|
||||
'word Layouteffect destroy',
|
||||
'callback effect'
|
||||
]);
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num Layouteffect destroy',
|
||||
'word Layouteffect destroy',
|
||||
'callback effect',
|
||||
// 最后执行异步useEffect
|
||||
'num effect destroy',
|
||||
'word effect destroy',
|
||||
]);
|
||||
|
@ -254,27 +288,26 @@ describe('useEffect Hook Test', () => {
|
|||
|
||||
act(() => {
|
||||
HorizonDOM.render(<App num={1} />, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num: 1',
|
||||
'callback effect'
|
||||
]);
|
||||
expect(container.textContent).toEqual('num: 1');
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num: 1',
|
||||
'callback effect',
|
||||
// 最后执行异步
|
||||
'num effect destroy',
|
||||
'num effect [1]',
|
||||
]);
|
||||
expect(container.textContent).toEqual('num: 1');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'callback effect'
|
||||
]);
|
||||
expect(container.textContent).toEqual('');
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'callback effect',
|
||||
'num effect destroy'
|
||||
]);
|
||||
expect(container.textContent).toEqual('');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
});
|
||||
|
||||
it('销毁依赖空数组的useEffect', () => {
|
||||
|
@ -302,25 +335,24 @@ describe('useEffect Hook Test', () => {
|
|||
|
||||
act(() => {
|
||||
HorizonDOM.render(<App num={1} />, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num: 1',
|
||||
'callback effect'
|
||||
]);
|
||||
expect(container.textContent).toEqual('num: 1');
|
||||
});
|
||||
// 没有执行useEffect
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num: 1',
|
||||
'callback effect'
|
||||
// 依赖空数组,没有执行useEffect
|
||||
]);
|
||||
expect(container.textContent).toEqual('num: 1');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'callback effect'
|
||||
]);
|
||||
expect(container.textContent).toEqual('');
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'callback effect',
|
||||
'num effect destroy'
|
||||
]);
|
||||
expect(container.textContent).toEqual('');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
});
|
||||
|
||||
it('useEffect里使用useState(1', () => {
|
||||
|
@ -354,11 +386,12 @@ describe('useEffect Hook Test', () => {
|
|||
|
||||
act(() => {
|
||||
setNum();
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num: 1'
|
||||
]);
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['num effect [1]']);
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'num: 1',
|
||||
'num effect [1]'
|
||||
]);
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
});
|
||||
|
||||
it('useEffect里使用useState(2', () => {
|
||||
|
@ -389,7 +422,7 @@ describe('useEffect Hook Test', () => {
|
|||
expect(container.textContent).toEqual('Num: 1');
|
||||
});
|
||||
|
||||
it('useEffect与memo一起使用', () => {
|
||||
it('useEffect与memo一起使用(1', () => {
|
||||
let setNum;
|
||||
const App = memo(() => {
|
||||
const [num, _setNum] = useState(0);
|
||||
|
@ -415,28 +448,284 @@ describe('useEffect Hook Test', () => {
|
|||
// 不会重新渲染
|
||||
act(() => {
|
||||
HorizonDOM.render(<App />, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual(['callback effect']);
|
||||
expect(container.textContent).toEqual('0');
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['callback effect']);
|
||||
expect(container.textContent).toEqual('0');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
|
||||
// 会重新渲染
|
||||
act(() => {
|
||||
setNum(1);
|
||||
expect(LogUtils.getAndClear()).toEqual([1]);
|
||||
expect(container.textContent).toEqual('1');
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
1,
|
||||
'num effect destroy 0',
|
||||
'num effect [1]'
|
||||
]);
|
||||
expect(container.textContent).toEqual('1');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual(['callback effect']);
|
||||
expect(container.textContent).toEqual('');
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['num effect destroy 1']);
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'callback effect',
|
||||
'num effect destroy 1'
|
||||
]);
|
||||
expect(container.textContent).toEqual('');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
});
|
||||
|
||||
it('useEffect与memo一起使用(2', () => {
|
||||
const compare = (prevProps, nextProps) => prevProps.num === nextProps.num;
|
||||
const App = memo((props) => {
|
||||
useEffect(() => {
|
||||
LogUtils.log(`num effect [${props.num}]`);
|
||||
return () => {
|
||||
LogUtils.log(`num effect destroy ${props.num}`);
|
||||
};
|
||||
});
|
||||
return <Text text={props.num} />;
|
||||
}, compare)
|
||||
act(() => {
|
||||
HorizonDOM.render(<App num={0} />, container, () => LogUtils.log('callback effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
0,
|
||||
'callback effect'
|
||||
]);
|
||||
expect(container.textContent).toEqual('0');
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['num effect [0]']);
|
||||
|
||||
// 不会重新渲染
|
||||
act(() => {
|
||||
HorizonDOM.render(<App num={0} />, container, () => LogUtils.log('callback effect'));
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['callback effect']);
|
||||
expect(container.textContent).toEqual('0');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
|
||||
// 会重新渲染
|
||||
act(() => {
|
||||
HorizonDOM.render(<App num={1} />, container, () => LogUtils.log('callback effect'));
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
1,
|
||||
'callback effect',
|
||||
// 执行异步,先清除旧的,再执行新的
|
||||
'num effect destroy 0',
|
||||
'num effect [1]'
|
||||
]);
|
||||
expect(container.textContent).toEqual('1');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(null, container, () => LogUtils.log('callback effect'));
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['callback effect', 'num effect destroy 1']);
|
||||
expect(container.textContent).toEqual('');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
});
|
||||
|
||||
it('useEffect处理错误', () => {
|
||||
const App = (props) => {
|
||||
useEffect(() => {
|
||||
LogUtils.log('throw Error');
|
||||
throw new Error('mistake');
|
||||
// eslint-disable-next-line no-unreachable
|
||||
LogUtils.log(`Mount with [${props.num}]`);
|
||||
return () => {
|
||||
LogUtils.log(`Unmount with [${props.num}]`);
|
||||
};
|
||||
});
|
||||
return <Text text={'Number: ' + props.num} />;
|
||||
}
|
||||
act(() => {
|
||||
HorizonDOM.render(<App num={0} />, container, () =>
|
||||
LogUtils.log('Sync effect'),
|
||||
);
|
||||
expect(LogUtils.getAndClear()).toEqual(['Number: 0', 'Sync effect']);
|
||||
expect(container.textContent).toEqual('Number: 0');
|
||||
});
|
||||
// 处理错误,不会向下执行LogUtils.log(`Mount with [${props.num}]`);
|
||||
expect(LogUtils.getAndClear()).toEqual(['throw Error']);
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(null, container, () =>
|
||||
LogUtils.log('Sync effect'),
|
||||
);
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'Sync effect',
|
||||
// 不会处理卸载部分 LogUtils.log(`Unmount with [${props.num}]`);
|
||||
]);
|
||||
expect(container.textContent).toEqual('');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
});
|
||||
|
||||
it('卸载useEffect', () => {
|
||||
const App = (props) => {
|
||||
useEffect(() => {
|
||||
LogUtils.log(`num effect [${props.num}]`);
|
||||
return () => {
|
||||
LogUtils.log(`num effect destroy ${props.num}`);
|
||||
};
|
||||
}, []);
|
||||
if (props.num < 0) {
|
||||
useEffect(() => {
|
||||
LogUtils.log(`New num effect [${props.num}]`);
|
||||
return () => {
|
||||
LogUtils.log(`New num effect destroy ${props.num}`);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
return <Text text={`Number: ${props.num}`} />;
|
||||
}
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(<App num={0} />, container, () => LogUtils.log('num effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual(['Number: 0', 'num effect']);
|
||||
expect(container.textContent).toBe('Number: 0');
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['num effect [0]']);
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(null, container, () => LogUtils.log('num effect'));
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['num effect', 'num effect destroy 0']);
|
||||
expect(container.textContent).toBe('');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
});
|
||||
|
||||
it('同步刷新不会导致effect执行', () => {
|
||||
let setNum;
|
||||
const App = () => {
|
||||
const [num, _setNum] = useState(0);
|
||||
setNum = _setNum;
|
||||
useEffect(() => {
|
||||
LogUtils.log(`num effect [${num}]`);
|
||||
_setNum(1);
|
||||
}, []);
|
||||
return <Text text={`Number: ${num}`} />;
|
||||
}
|
||||
|
||||
HorizonDOM.render(<App />, container, () => LogUtils.log('num effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual(['Number: 0', 'num effect']);
|
||||
expect(container.textContent).toBe('Number: 0');
|
||||
|
||||
act(() => {
|
||||
// 模拟同步刷新
|
||||
(function () {
|
||||
setNum(2);
|
||||
})();
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['num effect [0]', 'Number: 1']);
|
||||
expect(container.textContent).toBe('Number: 1');
|
||||
expect(LogUtils.getAndClear()).toEqual([]);
|
||||
});
|
||||
|
||||
it('当组件的更新方法在卸载函数中,组件更新不会告警', () => {
|
||||
const App = () => {
|
||||
LogUtils.log('useEffect');
|
||||
const [num, setNum] = useState(0);
|
||||
useEffect(() => {
|
||||
LogUtils.log('effect');
|
||||
return () => {
|
||||
setNum(1);
|
||||
LogUtils.log('effect destroy');
|
||||
};
|
||||
}, []);
|
||||
return num;
|
||||
}
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(<App />, container, () => LogUtils.log('num effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual(['useEffect', 'num effect']);
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['effect']);
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(null, container);
|
||||
});
|
||||
// 不会处理setNum(1)
|
||||
expect(LogUtils.getAndClear()).toEqual(['effect destroy']);
|
||||
});
|
||||
|
||||
it('当组件的更新方法在卸载函数中,组件的子组件更新不会告警', () => {
|
||||
const App = () => {
|
||||
LogUtils.log('App');
|
||||
const appRef = React.createRef(null);
|
||||
useEffect(() => {
|
||||
LogUtils.log('App effect');
|
||||
return () => {
|
||||
appRef.current(1);
|
||||
LogUtils.log('App effect destroy');
|
||||
};
|
||||
}, []);
|
||||
return <AppChild ref={appRef} />;
|
||||
}
|
||||
|
||||
let AppChild = (props, ref) => {
|
||||
LogUtils.log('AppChild')
|
||||
const [num, setNum] = useState(0);
|
||||
useEffect(() => {
|
||||
LogUtils.log('Child effect');
|
||||
ref.current = setNum;
|
||||
}, []);
|
||||
return num;
|
||||
}
|
||||
AppChild = forwardRef(AppChild);
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(<App />, container, () => LogUtils.log('num effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'App',
|
||||
'AppChild',
|
||||
'num effect'
|
||||
]);
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['Child effect','App effect']);
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(null, container);
|
||||
});
|
||||
// 销毁时执行appRef.current(1)不会报错
|
||||
expect(LogUtils.getAndClear()).toEqual(['App effect destroy']);
|
||||
});
|
||||
|
||||
it('当组件的更新方法在卸载函数中,组件的父组件更新不会告警', () => {
|
||||
const App = () => {
|
||||
LogUtils.log('App');
|
||||
const [num, setNum] = useState(0);
|
||||
return <AppChild num={num} setNum={setNum} />;
|
||||
}
|
||||
|
||||
let AppChild = (props) => {
|
||||
LogUtils.log('AppChild')
|
||||
useEffect(() => {
|
||||
LogUtils.log('Child effect');
|
||||
return () => {
|
||||
LogUtils.log('Child effect destroy');
|
||||
props.setNum(1);
|
||||
};
|
||||
}, []);
|
||||
return props.num;
|
||||
}
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(<App />, container, () => LogUtils.log('num effect'));
|
||||
expect(LogUtils.getAndClear()).toEqual([
|
||||
'App',
|
||||
'AppChild',
|
||||
'num effect'
|
||||
]);
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['Child effect']);
|
||||
|
||||
act(() => {
|
||||
HorizonDOM.render(null, container);
|
||||
});
|
||||
// 销毁时执行 props.setNum(1);不会报错
|
||||
expect(LogUtils.getAndClear()).toEqual(['Child effect destroy']);
|
||||
});
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as React from '../../../libs/horizon/src/external/Horizon';
|
||||
import * as HorizonDOM from '../../../libs/horizon/src/dom/DOMExternal';
|
||||
import * as LogUtils from '../jest/logUtils';
|
||||
import { act } from '../jest/customMatcher';
|
||||
|
||||
describe('useState Hook Test', () => {
|
||||
const { useState, forwardRef, useImperativeHandle, memo } = React;
|
||||
|
@ -126,4 +127,45 @@ describe('useState Hook Test', () => {
|
|||
expect(LogUtils.getAndClear()).toEqual([1]);
|
||||
expect(container.querySelector('p').innerHTML).toBe('1');
|
||||
});
|
||||
|
||||
it('卸载useState', () => {
|
||||
let updateA;
|
||||
let updateB;
|
||||
let updateC;
|
||||
|
||||
const App = (props) => {
|
||||
const [A, _updateA] = useState(0);
|
||||
const [B, _updateB] = useState(0);
|
||||
updateA = _updateA;
|
||||
updateB = _updateB;
|
||||
|
||||
let C;
|
||||
if (props.loadC) {
|
||||
const [_C, _updateC] = useState(0);
|
||||
C = _C;
|
||||
updateC = _updateC;
|
||||
} else {
|
||||
C = '[not loaded]';
|
||||
}
|
||||
|
||||
return <Text text={`A: ${A}, B: ${B}, C: ${C}`} />;
|
||||
}
|
||||
|
||||
HorizonDOM.render(<App loadC={true} />, container);
|
||||
expect(LogUtils.getAndClear()).toEqual(['A: 0, B: 0, C: 0']);
|
||||
expect(container.textContent).toBe('A: 0, B: 0, C: 0');
|
||||
act(() => {
|
||||
updateA(2);
|
||||
updateB(3);
|
||||
updateC(4);
|
||||
});
|
||||
expect(LogUtils.getAndClear()).toEqual(['A: 2, B: 3, C: 4']);
|
||||
expect(container.textContent).toBe('A: 2, B: 3, C: 4');
|
||||
|
||||
expect(() => {
|
||||
HorizonDOM.render(<App loadC={false} />, container);
|
||||
}).toThrow(
|
||||
'Hooks are less than expected, please check whether the hook is written in the condition.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { runAsyncEffects } from '../../../libs/horizon/src/renderer/submit/HookEffectHandler';
|
||||
import { runAsyncEffects, callUseEffects } from '../../../libs/horizon/src/renderer/submit/HookEffectHandler';
|
||||
import { callRenderQueueImmediate } from '../../../libs/horizon/src/renderer/taskExecutor/RenderQueue';
|
||||
import { asyncUpdates } from '../../../libs/horizon/src/renderer/TreeBuilder';
|
||||
import { runAsync } from '../../../libs/horizon/src/renderer/taskExecutor/TaskExecutor';
|
||||
|
||||
function runAssertion(fn) {
|
||||
try {
|
||||
|
@ -21,7 +23,7 @@ function toMatchValue(LogUtils, expectedValues) {
|
|||
}
|
||||
|
||||
const act = (fun) => {
|
||||
fun();
|
||||
asyncUpdates(fun);
|
||||
callRenderQueueImmediate();
|
||||
runAsyncEffects();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue