From 2bff70f3d7d698d4a926eb3f929299cfd9bfbf20 Mon Sep 17 00:00:00 2001 From: * <8> Date: Fri, 22 Apr 2022 18:24:44 +0800 Subject: [PATCH] Match-id-a90510ae54d3c1219ba977e400db2b3cdf8035fe --- .../__tests__/ComponentTest/Context.test.js | 361 +++++++++++++ .../ComponentTest/FunctionComponent.test.js | 48 ++ .../ComponentTest/HookTest/UseEffect.test.js | 3 +- .../HookTest/UseImperativeHandle.test.js | 5 +- .../HookTest/UseLayoutEffect.test.js | 4 +- .../ComponentTest/HookTest/UseMemo.test.js | 5 +- .../ComponentTest/HookTest/UseRef.test.js | 5 +- .../ComponentTest/HookTest/UseState.test.js | 5 +- .../__tests__/ComponentTest/LifeCycle.test.js | 475 ++++++++++++++++++ scripts/__tests__/DomTest/DomInput.test.js | 3 +- scripts/__tests__/DomTest/DomSelect.test.js | 2 +- scripts/__tests__/DomTest/DomTextarea.test.js | 150 ++++++ .../__snapshots__/DomTextarea.test.js.snap | 5 + scripts/__tests__/EventTest/EventMain.test.js | 2 +- .../__tests__/EventTest/FocusEvent.test.js | 5 +- .../__tests__/EventTest/KeyboardEvent.test.js | 3 +- .../__tests__/EventTest/MouseEvent.test.js | 4 +- .../__tests__/EventTest/WheelEvent.test.js | 4 +- scripts/__tests__/jest/commonComponents.js | 9 +- scripts/__tests__/jest/jestSetting.js | 7 +- scripts/__tests__/jest/logUtils.js | 26 - scripts/__tests__/jest/testUtils.js | 46 +- 22 files changed, 1120 insertions(+), 57 deletions(-) create mode 100644 scripts/__tests__/ComponentTest/Context.test.js create mode 100644 scripts/__tests__/ComponentTest/FunctionComponent.test.js create mode 100644 scripts/__tests__/ComponentTest/LifeCycle.test.js create mode 100644 scripts/__tests__/DomTest/DomTextarea.test.js create mode 100644 scripts/__tests__/DomTest/__snapshots__/DomTextarea.test.js.snap delete mode 100755 scripts/__tests__/jest/logUtils.js diff --git a/scripts/__tests__/ComponentTest/Context.test.js b/scripts/__tests__/ComponentTest/Context.test.js new file mode 100644 index 00000000..03760244 --- /dev/null +++ b/scripts/__tests__/ComponentTest/Context.test.js @@ -0,0 +1,361 @@ +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 ( + + {props.children} + + ); + }; + + const Consumer = () => { + LogUtils.log('Consumer'); + return ( + + {type => { + LogUtils.log('Consumer DOM mutations'); + return

{type}

; + }} +
+ ); + }; + + class Middle extends Horizon.Component { + shouldComponentUpdate() { + return false; + } + render() { + LogUtils.log('Middle'); + return this.props.children; + } + } + + const App = (props) => { + LogUtils.log('App'); + return ( + + + + + + + + ); + }; + + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('Java'); + expect(LogUtils.getAndClear()).toEqual([ + 'App', + 'SystemLanguageProvider', + 'Middle', + 'Middle', + 'Consumer', + 'Consumer DOM mutations' + ]); + + // 组件不变,Middle没有更新,消费者也不会执行 + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('Java'); + expect(LogUtils.getAndClear()).toEqual([ + 'App', + 'SystemLanguageProvider' + ]); + + Horizon.render(, 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 ( + + {props.children} + + ); + }; + + const Consumer = () => { + LogUtils.log('Consumer'); + return ( + + {type => { + LogUtils.log('Consumer DOM mutations'); + return

{type}

; + }} +
+ ); + }; + + class Middle extends Horizon.Component { + shouldComponentUpdate() { + return false; + } + render() { + LogUtils.log('Middle'); + return this.props.children; + } + } + + const App = (props) => { + LogUtils.log('App'); + return ( + + + + + + + + ); + }; + + // Consumer决定于距离它最近的provider + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('2'); + expect(LogUtils.getAndClear()).toEqual([ + 'App', + 'SystemLanguageProvider: 1', + 'SystemLanguageProvider: 2', + 'Middle', + 'Consumer', + 'Consumer DOM mutations' + ]); + // 更新 + Horizon.render(, 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 ( + + {props.children} + + ); + }; + const NewNumberProvider = props => { + return ( + + {props.children} + + ); + }; + + class Middle extends Horizon.Component { + shouldComponentUpdate() { + return false; + } + render() { + return this.props.children; + } + } + + const NewApp = (props) => { + return ( + + + + {type => { + LogUtils.log('Consumer DOM mutations'); + return

{type}

; + }} +
+
+
+ ); + }; + + const App = (props) => { + return ( + + + + {type => { + LogUtils.log('Consumer DOM mutations'); + return

{type}

; + }} +
+
+
+ ); + }; + + Horizon.render(, container); + // 没有匹配到Provider,会使用defaultValue + expect(container.querySelector('p').innerHTML).toBe('0'); + + // 更新,设置value为undefined + Horizon.render(, 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 ( + + {value => ( + + {props.children} + + )} + + ); + } + + class Middle extends Horizon.Component { + shouldComponentUpdate() { + return false; + } + render() { + return this.props.children; + } + } + + const App = props => { + return ( + + + + + + {value =>

{value}

} +
+
+
+ + + {value =>

{value}

} +
+
+
+
+ ); + }; + + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('4'); + expect(container.querySelector('#p').innerHTML).toBe('2'); + + Horizon.render(, 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 ( +

{`Context: ${props.context}, Num: ${num}`}

+ ); + }; + + const App = props => { + return ( + + + {value => { + LogUtils.log('Consumer'); + return ; + }} + + + ); + }; + + Horizon.render(, 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 ( + + {value => { + LogUtils.log('Consumer'); + return

{`Num: ${value}, Type: ${type}`}

; + }} +
+ ); + }; + + const App = props => { + return ( + + + + + + ); + }; + + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('Num: 2, Type: typeB'); + + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('Num: 2, Type: typeR'); + + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('Num: 8, Type: typeR'); + }); +}); diff --git a/scripts/__tests__/ComponentTest/FunctionComponent.test.js b/scripts/__tests__/ComponentTest/FunctionComponent.test.js new file mode 100644 index 00000000..004dc15d --- /dev/null +++ b/scripts/__tests__/ComponentTest/FunctionComponent.test.js @@ -0,0 +1,48 @@ +import * as Horizon from '@cloudsop/horizon/index.ts'; +describe('FunctionComponent Test', () => { + it('渲染无状态组件', () => { + const App = (props) => { + return

{props.text}

; + }; + + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('app'); + }); + + it('更新无状态组件', () => { + const App = (props) => { + return

{props.text}

; + }; + + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('app'); + + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('ABC'); + + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('abc'); + }); + + it('卸载无状态组件', () => { + const App = (props) => { + return

{props.text}

; + }; + + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('app'); + + Horizon.unmountComponentAtNode(container); + expect(container.querySelector('p')).toBe(null); + }); + + it('渲染空组件返回空子节点', () => { + const App = () => { + return
; + }; + + const realNode = Horizon.render(, container); + expect(realNode).toBe(null); + }); + +}); \ No newline at end of file diff --git a/scripts/__tests__/ComponentTest/HookTest/UseEffect.test.js b/scripts/__tests__/ComponentTest/HookTest/UseEffect.test.js index 38ab9e71..0acee64f 100644 --- a/scripts/__tests__/ComponentTest/HookTest/UseEffect.test.js +++ b/scripts/__tests__/ComponentTest/HookTest/UseEffect.test.js @@ -1,5 +1,5 @@ import * as Horizon from '@cloudsop/horizon/index.ts'; -import * as LogUtils from '../../jest/logUtils'; +import { getLogUtils } from '../../jest/testUtils'; import { Text } from '../../jest/commonComponents'; describe('useEffect Hook Test', () => { @@ -12,6 +12,7 @@ describe('useEffect Hook Test', () => { act, } = Horizon; + const LogUtils =getLogUtils(); it('简单使用useEffect', () => { const App = () => { const [num, setNum] = useState(0); diff --git a/scripts/__tests__/ComponentTest/HookTest/UseImperativeHandle.test.js b/scripts/__tests__/ComponentTest/HookTest/UseImperativeHandle.test.js index 6924610c..f4efe0ef 100644 --- a/scripts/__tests__/ComponentTest/HookTest/UseImperativeHandle.test.js +++ b/scripts/__tests__/ComponentTest/HookTest/UseImperativeHandle.test.js @@ -1,6 +1,6 @@ import * as Horizon from '@cloudsop/horizon/index.ts'; -import * as LogUtils from '../../jest/logUtils'; import { Text } from '../../jest/commonComponents'; +import { getLogUtils } from '../../jest/testUtils'; describe('useImperativeHandle Hook Test', () => { const { @@ -10,7 +10,7 @@ describe('useImperativeHandle Hook Test', () => { act, } = Horizon; const { unmountComponentAtNode } = Horizon; - + const LogUtils =getLogUtils(); it('测试useImperativeHandle', () => { let App = (props, ref) => { @@ -48,7 +48,6 @@ describe('useImperativeHandle Hook Test', () => { }); it('useImperativeHandle没有配置dep时自动更新', () => { - let App = (props, ref) => { const [num, setNum] = useState(0); useImperativeHandle(ref, () => ({ num, setNum })); diff --git a/scripts/__tests__/ComponentTest/HookTest/UseLayoutEffect.test.js b/scripts/__tests__/ComponentTest/HookTest/UseLayoutEffect.test.js index 4a087112..e5951589 100644 --- a/scripts/__tests__/ComponentTest/HookTest/UseLayoutEffect.test.js +++ b/scripts/__tests__/ComponentTest/HookTest/UseLayoutEffect.test.js @@ -1,5 +1,5 @@ import * as Horizon from '@cloudsop/horizon/index.ts'; -import * as LogUtils from '../../jest/logUtils'; +import { getLogUtils } from '../../jest/testUtils'; import { Text } from '../../jest/commonComponents'; describe('useLayoutEffect Hook Test', () => { @@ -9,7 +9,7 @@ describe('useLayoutEffect Hook Test', () => { useLayoutEffect, act, } = Horizon; - + const LogUtils =getLogUtils(); it('简单使用useLayoutEffect', () => { const App = () => { const [num, setNum] = useState(0); diff --git a/scripts/__tests__/ComponentTest/HookTest/UseMemo.test.js b/scripts/__tests__/ComponentTest/HookTest/UseMemo.test.js index 1170e6ee..8d379f85 100644 --- a/scripts/__tests__/ComponentTest/HookTest/UseMemo.test.js +++ b/scripts/__tests__/ComponentTest/HookTest/UseMemo.test.js @@ -1,10 +1,11 @@ import * as Horizon from '@cloudsop/horizon/index.ts'; -import * as LogUtils from '../../jest/logUtils'; +import { getLogUtils } from '../../jest/testUtils'; import { Text } from '../../jest/commonComponents'; describe('useMemo Hook Test', () => { const { useMemo, useState } = Horizon; - + const LogUtils =getLogUtils(); + it('测试useMemo', () => { let setMemo; const App = () => { diff --git a/scripts/__tests__/ComponentTest/HookTest/UseRef.test.js b/scripts/__tests__/ComponentTest/HookTest/UseRef.test.js index a873a0d4..13110d1c 100644 --- a/scripts/__tests__/ComponentTest/HookTest/UseRef.test.js +++ b/scripts/__tests__/ComponentTest/HookTest/UseRef.test.js @@ -1,10 +1,11 @@ import * as Horizon from '@cloudsop/horizon/index.ts'; -import * as LogUtils from '../../jest/logUtils'; +import { getLogUtils } from '../../jest/testUtils'; import { Text } from '../../jest/commonComponents'; describe('useRef Hook Test', () => { const { useState, useRef } = Horizon; - + const LogUtils =getLogUtils(); + it('测试useRef', () => { const App = () => { const [num, setNum] = useState(1); diff --git a/scripts/__tests__/ComponentTest/HookTest/UseState.test.js b/scripts/__tests__/ComponentTest/HookTest/UseState.test.js index 01db57c1..b015fcc5 100644 --- a/scripts/__tests__/ComponentTest/HookTest/UseState.test.js +++ b/scripts/__tests__/ComponentTest/HookTest/UseState.test.js @@ -1,5 +1,5 @@ import * as Horizon from '@cloudsop/horizon/index.ts'; -import * as LogUtils from '../../jest/logUtils'; +import { getLogUtils } from '../../jest/testUtils'; import { Text } from '../../jest/commonComponents'; describe('useState Hook Test', () => { @@ -10,6 +10,7 @@ describe('useState Hook Test', () => { memo, act, } = Horizon; + const LogUtils =getLogUtils(); it('简单使用useState', () => { const App = () => { @@ -112,7 +113,7 @@ describe('useState Hook Test', () => { it('useState与memo一起使用', () => { let setNum; - const App = memo((props) => { + const App = memo(() => { const [num, _setNum] = useState(0); setNum = _setNum; return ; diff --git a/scripts/__tests__/ComponentTest/LifeCycle.test.js b/scripts/__tests__/ComponentTest/LifeCycle.test.js new file mode 100644 index 00000000..1e975acf --- /dev/null +++ b/scripts/__tests__/ComponentTest/LifeCycle.test.js @@ -0,0 +1,475 @@ +import * as Horizon from '@cloudsop/horizon/index.ts'; +import { getLogUtils } from '../jest/testUtils'; + +describe('LifeCycle Test', () => { + const LogUtils =getLogUtils(); + describe('LifeCycle function', () => { + it('不能在componentWillMount里setState', () => { + class App extends Horizon.Component { + state = {}; + + UNSAFE_componentWillMount() { + this.setState = { + num: 1 + }; + } + + render() { + return

{this.state.num}

; + } + } + + const realNode = Horizon.render(, container); + // 不能在componentWillMount里setState + expect(realNode.textContent).toBe(undefined); + }); + + it('componentDidMount里调用setState()将触发额外渲染', () => { + class ChildApp extends Horizon.Component { + constructor(props) { + super(props); + } + + componentDidMount() { + LogUtils.log(this.props.isShow); + } + + render() { + return

{this.props.isShow}

; + } + } + + class App extends Horizon.Component { + constructor(props) { + super(props); + LogUtils.log('constructor'); + this.state = { shouldShowChild: false }; + } + + componentDidMount() { + LogUtils.log('componentDidMount'); + this.setState({ shouldShowChild: true }); + } + + render() { + return ( +
+ {this.state.shouldShowChild ? :
} +
+ ); + } + } + + const realNode = Horizon.render(, container); + // 确实触发了额外渲染 + expect(LogUtils.getAndClear()).toEqual([ + 'constructor', + 'componentDidMount', + true + ]); + // 可以在 componentDidMount() 里直接调用 setState()。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前 + expect(container.querySelector('p').innerHTML).toBe(''); + // 在 componentDidMount() 里可以更新state + expect(realNode.state).toStrictEqual({ 'shouldShowChild': true }); + }); + + it('调用 this.setState() 通常不会触发 UNSAFE_componentWillReceiveProps()', () => { + class App extends Horizon.Component { + state = {}; + + update = () => { + this.setState({ num: 4 }); + } + + UNSAFE_componentWillReceiveProps() { + LogUtils.log('componentWillReceiveProps'); + this.setState = { + num: 1 + }; + } + + render() { + return

{this.state.num}

; + } + } + + const realNode = Horizon.render(, container); + expect(realNode.textContent).toBe(undefined); + realNode.update(); + expect(LogUtils.getAndClear()).toEqual([]); + }); + + it('不能在componentWillReceiveProps里setState', () => { + class ChildApp extends Horizon.Component { + state = {}; + + UNSAFE_componentWillReceiveProps() { + this.state = { text: 'text' }; + } + + render() { + LogUtils.log(this.state.text); + return
{this.state.text}
; + } + } + class App extends Horizon.Component { + state = {}; + + update = () => { + this.setState({ num: 4 }); + } + + render() { + return ; + } + } + + const realNode = Horizon.render(, container); + expect(realNode.textContent).toBe(undefined); + realNode.update(); + expect(LogUtils.getAndClear()).toEqual([ + undefined, + 'text', + ]); + // 不能在componentWillMount里setState + expect(realNode.textContent).toBe(undefined); + }); + + it('shouldComponentUpdate与getDerivedStateFromProps', () => { + class App extends Horizon.Component { + constructor(props) { + super(props); + this.state = { + num: props.num, + }; + } + static getDerivedStateFromProps(nextProps, prevState) { + if (nextProps.num === prevState.num) { + return null; + } + return { num: nextProps.num }; + } + + shouldComponentUpdate(nextProps, nextState) { + LogUtils.log('shouldComponentUpdate'); + return nextState.num !== this.state.num; + } + + render() { + return

{this.state.num}

; + } + } + + Horizon.render(, container); + // 初次渲染不会调用shouldComponentUpdate + expect(LogUtils.getAndClear()).toEqual([]); + expect(container.querySelector('p').innerHTML).toBe('1'); + + Horizon.render(, container); + // getDerivedStateFromProps判断state没有变化时,会调用shouldComponentUpdate + expect(LogUtils.getAndClear()).toEqual(['shouldComponentUpdate']); + expect(container.querySelector('p').innerHTML).toBe('1'); + + Horizon.render(, container); + // getDerivedStateFromProps判断state变化时,会调用shouldComponentUpdate + expect(LogUtils.getAndClear()).toEqual(['shouldComponentUpdate']); + expect(container.querySelector('p').innerHTML).toBe('2'); + }); + + it('如果shouldComponentUpdate()返回值为false,则不会调用componentDidUpdate()', () => { + class App extends Horizon.Component { + constructor(props) { + super(props); + this.state = { + num: props.num, + }; + } + static getDerivedStateFromProps(nextProps, prevState) { + if (nextProps.num === prevState.num) { + return null; + } + return { num: nextProps.num }; + } + + shouldComponentUpdate(nextProps, nextState) { + return nextState.num !== this.state.num; + } + + componentDidUpdate(){ + LogUtils.log('componentDidUpdate'); + } + + render() { + return

{this.state.num}

; + } + } + + Horizon.render(, container); + expect(container.querySelector('p').innerHTML).toBe('1'); + + Horizon.render(, container); + // 不会调用componentDidUpdate() + expect(LogUtils.getAndClear()).toEqual([]); + expect(container.querySelector('p').innerHTML).toBe('1'); + + Horizon.render(, container); + // 调用componentDidUpdate() + expect(LogUtils.getAndClear()).toEqual(['componentDidUpdate']); + expect(container.querySelector('p').innerHTML).toBe('2'); + }); + + it('getSnapshotBeforeUpdate()的返回值会作为componentDidUpdate()的第三个参数', () => { + class App extends Horizon.Component { + constructor(props) { + super(props); + this.state = { + num: 0, + }; + } + static getDerivedStateFromProps(nextProps, prevState) { + if (nextProps.num === prevState.num) { + return null; + } + return { num: nextProps.num }; + } + getSnapshotBeforeUpdate(prevProps, prevState) { + LogUtils.log( + `getSnapshotBeforeUpdate prevProps:${prevProps.num} prevState:${prevState.num}`, + ); + return 'Snapshot'; + } + componentDidUpdate(prevProps, prevState, snapshot) { + LogUtils.log( + `componentDidUpdate prevProps:${prevProps.num} prevState:${prevState.num} snapshot:${snapshot}`, + ); + } + + render() { + return

{this.state.num}

; + } + } + Horizon.render(, container); + expect(LogUtils.getAndClear()).toEqual([]); + expect(container.querySelector('p').innerHTML).toBe(''); + + Horizon.render(, container); + // Snapshot作为componentDidUpdate()的第三个参数 + expect(LogUtils.getAndClear()).toEqual([ + 'getSnapshotBeforeUpdate prevProps:undefined prevState:undefined', + 'componentDidUpdate prevProps:undefined prevState:undefined snapshot:Snapshot', + ]); + expect(container.querySelector('p').innerHTML).toBe('1'); + + Horizon.render(, container); + expect(LogUtils.getAndClear()).toEqual([ + 'getSnapshotBeforeUpdate prevProps:1 prevState:1', + 'componentDidUpdate prevProps:1 prevState:1 snapshot:Snapshot', + ]); + expect(container.querySelector('p').innerHTML).toBe('1'); + + Horizon.render(, container); + expect(LogUtils.getAndClear()).toEqual([ + 'getSnapshotBeforeUpdate prevProps:1 prevState:1', + 'componentDidUpdate prevProps:1 prevState:1 snapshot:Snapshot', + ]); + expect(container.querySelector('p').innerHTML).toBe('2'); + }); + + it('无论什么原因触发了渲染,只要有渲染就会触发getDerivedStateFromProps',() => { + class App extends Horizon.Component { + constructor(props) { + super(props); + this.state = { + num: 0, + }; + } + static getDerivedStateFromProps(nextProps, prevState) { + LogUtils.log( + `getDerivedStateFromProps nextProps:${nextProps.num} prevState:${prevState.num}`, + ); + } + + render() { + return

{this.state.num}

; + } + } + let realNode = Horizon.render(, container); + realNode = Horizon.render(, container); + realNode.forceUpdate(); + // 触发了3次渲染 + expect(LogUtils.getAndClear()).toEqual([ + 'getDerivedStateFromProps nextProps:undefined prevState:0', + 'getDerivedStateFromProps nextProps:1 prevState:0', + 'getDerivedStateFromProps nextProps:1 prevState:0', + ]); + }); + }); + + it('生命周期执行顺序', () => { + class InnerApp extends Horizon.Component { + UNSAFE_componentWillMount() { + LogUtils.log('Inner componentWillMount'); + } + componentDidMount() { + LogUtils.log('Inner componentDidMount'); + } + UNSAFE_componentWillReceiveProps() { + LogUtils.log('Inner componentWillReceiveProps'); + } + shouldComponentUpdate(nextProps, nextState) { + LogUtils.log('Inner shouldComponentUpdates'); + return this.props.number !== nextProps.number; + } + UNSAFE_componentWillUpdate() { + LogUtils.log('Inner componentWillUpdate'); + } + componentDidUpdate() { + LogUtils.log('Inner componentDidUpdate'); + } + componentWillUnmount() { + LogUtils.log('Inner componentWillUnmount'); + } + + render() { + return

{this.props.number}

; + } + } + + class App extends Horizon.Component { + UNSAFE_componentWillMount() { + LogUtils.log('componentWillMount'); + } + componentDidMount() { + LogUtils.log('componentDidMount'); + } + UNSAFE_componentWillReceiveProps() { + LogUtils.log('componentWillReceiveProps'); + } + shouldComponentUpdate(nextProps, nextState) { + LogUtils.log('shouldComponentUpdates'); + return this.props.num !== nextProps.num; + } + UNSAFE_componentWillUpdate() { + LogUtils.log('componentWillUpdate'); + } + componentDidUpdate() { + LogUtils.log('componentDidUpdate'); + } + componentWillUnmount() { + LogUtils.log('componentWillUnmount'); + } + + render() { + return ; + } + } + + Horizon.render(, container); + expect(container.textContent).toBe('1'); + expect(LogUtils.getAndClear()).toEqual([ + 'componentWillMount', + 'Inner componentWillMount', + 'Inner componentDidMount', + 'componentDidMount' + ]); + Horizon.render(, container); + expect(container.textContent).toBe('2'); + expect(LogUtils.getAndClear()).toEqual([ + 'componentWillReceiveProps', + 'shouldComponentUpdates', + 'componentWillUpdate', + 'Inner componentWillReceiveProps', + 'Inner shouldComponentUpdates', + 'Inner componentWillUpdate', + 'Inner componentDidUpdate', + 'componentDidUpdate' + ]); + Horizon.unmountComponentAtNode(container); + expect(container.textContent).toBe(''); + expect(LogUtils.getAndClear()).toEqual([ + 'componentWillUnmount', + 'Inner componentWillUnmount' + ]); + }); + + it('新生命周期执行顺序', () => { + class InnerApp extends Horizon.Component { + static getDerivedStateFromProps(props, state) { + LogUtils.log('Inner getDerivedStateFromProps'); + } + componentDidMount() { + LogUtils.log('Inner componentDidMount'); + } + shouldComponentUpdate(nextProps, nextState) { + LogUtils.log('Inner shouldComponentUpdates'); + return this.props.number !== nextProps.number; + } + componentDidUpdate() { + LogUtils.log('Inner componentDidUpdate'); + } + getSnapshotBeforeUpdate() { + LogUtils.log('Inner getSnapshotBeforeUpdate'); + } + componentWillUnmount() { + LogUtils.log('Inner componentWillUnmount'); + } + + render() { + return

{this.props.number}

; + } + } + + class App extends Horizon.Component { + static getDerivedStateFromProps(props, state) { + LogUtils.log('getDerivedStateFromProps'); + } + componentDidMount() { + LogUtils.log('componentDidMount'); + } + shouldComponentUpdate(nextProps, nextState) { + LogUtils.log('shouldComponentUpdates'); + return this.props.num !== nextProps.num; + } + getSnapshotBeforeUpdate() { + LogUtils.log('getSnapshotBeforeUpdate'); + } + componentDidUpdate() { + LogUtils.log('componentDidUpdate'); + } + componentWillUnmount() { + LogUtils.log('componentWillUnmount'); + } + + render() { + return ; + } + } + + Horizon.render(, container); + expect(container.textContent).toBe('1'); + expect(LogUtils.getAndClear()).toEqual([ + 'getDerivedStateFromProps', + 'Inner getDerivedStateFromProps', + 'Inner componentDidMount', + 'componentDidMount' + ]); + Horizon.render(, container); + expect(container.textContent).toBe('2'); + expect(LogUtils.getAndClear()).toEqual([ + 'getDerivedStateFromProps', + 'shouldComponentUpdates', + 'Inner getDerivedStateFromProps', + 'Inner shouldComponentUpdates', + 'Inner getSnapshotBeforeUpdate', + 'getSnapshotBeforeUpdate', + 'Inner componentDidUpdate', + 'componentDidUpdate' + ]); + Horizon.unmountComponentAtNode(container); + expect(container.textContent).toBe(''); + expect(LogUtils.getAndClear()).toEqual([ + 'componentWillUnmount', + 'Inner componentWillUnmount' + ]); + }); +}); diff --git a/scripts/__tests__/DomTest/DomInput.test.js b/scripts/__tests__/DomTest/DomInput.test.js index 218cecc6..33ee5efd 100755 --- a/scripts/__tests__/DomTest/DomInput.test.js +++ b/scripts/__tests__/DomTest/DomInput.test.js @@ -1,9 +1,10 @@ /* eslint-disable @typescript-eslint/no-empty-function */ import * as Horizon from '@cloudsop/horizon/index.ts'; -import * as LogUtils from '../jest/logUtils'; +import { getLogUtils } from '../jest/testUtils'; describe('Dom Input', () => { const { act } = Horizon; + const LogUtils =getLogUtils(); describe('type checkbox', () => { it('没有设置checked属性时,控制台不会报错', () => { diff --git a/scripts/__tests__/DomTest/DomSelect.test.js b/scripts/__tests__/DomTest/DomSelect.test.js index 29548fc8..dfd1828e 100755 --- a/scripts/__tests__/DomTest/DomSelect.test.js +++ b/scripts/__tests__/DomTest/DomSelect.test.js @@ -130,7 +130,7 @@ describe('Dom Select', () => { expect(realNode.options[1].selected).toBe(true); }); - it('设置defaultValue后,select不受控', () => { + it('设置defaultValue后,select不受控', () => { const selectNode = ( , container); + expect(realNode.value).toBe('false'); + }); + + it('设置defaultValue为对象', () => { + let textareaValue = { + toString: () => { + return 'Vue'; + } + }; + const textareaNode = ( + , container); + expect(realNode.value).toBe('1234'); + realNode = Horizon.render(, container); + // realNode.value依旧为1234 + expect(realNode.value).toBe('1234'); + }); + +}); \ No newline at end of file diff --git a/scripts/__tests__/DomTest/__snapshots__/DomTextarea.test.js.snap b/scripts/__tests__/DomTest/__snapshots__/DomTextarea.test.js.snap new file mode 100644 index 00000000..c2975807 --- /dev/null +++ b/scripts/__tests__/DomTest/__snapshots__/DomTextarea.test.js.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Dom Textarea should not incur unnecessary DOM mutations 1`] = `