import PropTypes from '../../lib/ReactPropTypes';
import ReactTestUtils from "../../lib/ReactTestUtils";
import React from '../../src/May';
import { render, unmountComponentAtNode, findDOMNode } from '../../src/may-dom/MayDom'
var ReactDOM = {
render: render,
unmountComponentAtNode: unmountComponentAtNode,
findDOMNode: findDOMNode
}
React.render = render;
// import React from "../../dist/ReactANU";
// var ReactDOM = React;
describe("ReactComponentLifeCycle-test", function() {
// this.timeout(200000);
it('should not reuse an instance when it has been unmounted', () => {
var container = document.createElement('div');
class StatefulComponent extends React.Component {
state = {};
render() {
return
;
}
}
var element = ;
var firstInstance = ReactDOM.render(element, container);
ReactDOM.unmountComponentAtNode(container);
var secondInstance = ReactDOM.render(element, container);
expect(firstInstance).not.toBe(secondInstance);
});
/**
* If a state update triggers rerendering that in turn fires an onDOMReady,
* that second onDOMReady should not fail.
*/
it('it should fire onDOMReady when already in onDOMReady', () => {
var _testJournal = [];
class Child extends React.Component {
componentDidMount() {
_testJournal.push('Child:onDOMReady');
}
render() {
return ;
}
}
class SwitcherParent extends React.Component {
constructor(props) {
super(props);
_testJournal.push('SwitcherParent:getInitialState');
this.state = {showHasOnDOMReadyComponent: false};
}
componentDidMount() {
_testJournal.push('SwitcherParent:onDOMReady');
this.switchIt();
}
switchIt = () => {
this.setState({showHasOnDOMReadyComponent: true});
};
render() {
return (
{this.state.showHasOnDOMReadyComponent ?
:
}
);
}
}
ReactTestUtils.renderIntoDocument();
expect(_testJournal).toEqual([
'SwitcherParent:getInitialState',
'SwitcherParent:onDOMReady',
'Child:onDOMReady',
]);
});
// You could assign state here, but not access members of it, unless you
// had provided a getInitialState method.
it('throws when accessing state in componentWillMount', () => {
class StatefulComponent extends React.Component {
componentWillMount() {
void this.state.yada;
}
render() {
return ;
}
}
var instance = ;
expect(function() {
instance = ReactTestUtils.renderIntoDocument(instance);
}).toThrow();
});
it('should allow update state inside of componentWillMount', () => {
class StatefulComponent extends React.Component {
componentWillMount() {
this.setState({stateField: 'something'});
}
render() {
return ;
}
}
var instance = ;
expect(function() {
instance = ReactTestUtils.renderIntoDocument(instance);
}).not.toThrow();
});
it('should not allow update state inside of getInitialState', () => {
class StatefulComponent extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {stateField: 'somethingelse'};
// this.setState({stateField: 'something'});
}
render() {
return {this.state.stateField}
;
}
}
var container = document.createElement('div');
ReactDOM.render(, container);
expect(container.textContent).toBe("somethingelse");
});
it('should correctly determine if a component is mounted', () => {
class Component extends React.Component {
componentWillMount() {
expect(this.isMounted()).toBeFalsy();
}
componentDidMount() {
expect(this.isMounted()).toBeTruthy();
}
render() {
expect(this.isMounted()).toBeFalsy();
return ;
}
}
var element = ;
var instance = ReactTestUtils.renderIntoDocument(element);
expect(instance.isMounted()).toBeTruthy();
});
it('should correctly determine if a null component is mounted', () => {
class Component extends React.Component {
componentWillMount() {
expect(this.isMounted()).toBeFalsy();
}
componentDidMount() {
expect(this.isMounted()).toBeTruthy();
}
render() {
expect(this.isMounted()).toBeFalsy();
return null;
}
}
var element = ;
var instance = ReactTestUtils.renderIntoDocument(element);
expect(instance.isMounted()).toBeTruthy();
})
it('isMounted should return false when unmounted', () => {
class Component extends React.Component {
render() {
return ;
}
}
var container = document.createElement('div');
var instance = ReactDOM.render(, container);
// No longer a public API, but we can test that it works internally by
// reaching into the updater.
expect(instance.isMounted()).toBe(true);
ReactDOM.unmountComponentAtNode(container);
// expect(instance.isMounted()).toBe(false);
});
it('warns if findDOMNode is used inside render', () => {
class Component extends React.Component {
state = {isMounted: false};
componentDidMount() {
this.setState({isMounted: true});
}
render() {
if (this.state.isMounted) {
expect(ReactDOM.findDOMNode(this).tagName).toBe('DIV');
}
return ;
}
}
ReactTestUtils.renderIntoDocument();
});
it('should carry through each of the phases of setup', () => {
var clone = function(o) {
return JSON.parse(JSON.stringify(o));
};
var GET_INIT_STATE_RETURN_VAL = {
hasWillMountCompleted: false,
hasRenderCompleted: false,
hasDidMountCompleted: false,
hasWillUnmountCompleted: false,
};
var INIT_RENDER_STATE = {
hasWillMountCompleted: true,
hasRenderCompleted: false,
hasDidMountCompleted: false,
hasWillUnmountCompleted: false,
};
var DID_MOUNT_STATE = {
hasWillMountCompleted: true,
hasRenderCompleted: true,
hasDidMountCompleted: false,
hasWillUnmountCompleted: false,
};
var NEXT_RENDER_STATE = {
hasWillMountCompleted: true,
hasRenderCompleted: true,
hasDidMountCompleted: true,
hasWillUnmountCompleted: false,
};
var WILL_UNMOUNT_STATE = {
hasWillMountCompleted: true,
hasDidMountCompleted: true,
hasRenderCompleted: true,
hasWillUnmountCompleted: false,
};
var POST_WILL_UNMOUNT_STATE = {
hasWillMountCompleted: true,
hasDidMountCompleted: true,
hasRenderCompleted: true,
hasWillUnmountCompleted: true,
};
function getLifeCycleState(instance) {
return instance.isMounted() ? 'MOUNTED' : 'UNMOUNTED';
}
spyOn(console, 'error');
class LifeCycleComponent extends React.Component {
constructor(props, context) {
super(props, context);
this._testJournal = {};
var initState = {
hasWillMountCompleted: false,
hasDidMountCompleted: false,
hasRenderCompleted: false,
hasWillUnmountCompleted: false,
};
this._testJournal.returnedFromGetInitialState = clone(initState);
this._testJournal.lifeCycleAtStartOfGetInitialState = getLifeCycleState(
this,
);
this.state = initState;
}
componentWillMount() {
this._testJournal.stateAtStartOfWillMount = clone(this.state);
this._testJournal.lifeCycleAtStartOfWillMount = getLifeCycleState(this);
this.state.hasWillMountCompleted = true;
}
componentDidMount() {
this._testJournal.stateAtStartOfDidMount = clone(this.state);
this._testJournal.lifeCycleAtStartOfDidMount = getLifeCycleState(this);
this.setState({hasDidMountCompleted: true});
}
render() {
var isInitialRender = !this.state.hasRenderCompleted;
if (isInitialRender) {
this._testJournal.stateInInitialRender = clone(this.state);
this._testJournal.lifeCycleInInitialRender = getLifeCycleState(this);
} else {
this._testJournal.stateInLaterRender = clone(this.state);
this._testJournal.lifeCycleInLaterRender = getLifeCycleState(this);
}
// you would *NEVER* do anything like this in real code!
this.state.hasRenderCompleted = true;
return (
I am the inner DIV
);
}
componentWillUnmount() {
this._testJournal.stateAtStartOfWillUnmount = clone(this.state);
this._testJournal.lifeCycleAtStartOfWillUnmount = getLifeCycleState(
this,
);
this.state.hasWillUnmountCompleted = true;
}
}
// A component that is merely "constructed" (as in "constructor") but not
// yet initialized, or rendered.
//
var container = document.createElement('div');
var instance = ReactDOM.render(, container);
// getInitialState
expect(instance._testJournal.returnedFromGetInitialState).toEqual(
GET_INIT_STATE_RETURN_VAL,
);
expect(instance._testJournal.lifeCycleAtStartOfGetInitialState).toBe(
'UNMOUNTED',
);
// componentWillMount
expect(instance._testJournal.stateAtStartOfWillMount).toEqual(
instance._testJournal.returnedFromGetInitialState,
);
expect(instance._testJournal.lifeCycleAtStartOfWillMount).toBe('UNMOUNTED');
// componentDidMount
expect(instance._testJournal.stateAtStartOfDidMount).toEqual(
DID_MOUNT_STATE,
);
expect(instance._testJournal.lifeCycleAtStartOfDidMount).toBe('MOUNTED');
// initial render
expect(instance._testJournal.stateInInitialRender).toEqual(
INIT_RENDER_STATE,
);
expect(instance._testJournal.lifeCycleInInitialRender).toBe('UNMOUNTED');
expect(getLifeCycleState(instance)).toBe('MOUNTED');
// Now *update the component*
instance.forceUpdate();
// render 2nd time
expect(instance._testJournal.stateInLaterRender).toEqual(NEXT_RENDER_STATE);
expect(instance._testJournal.lifeCycleInLaterRender).toBe('MOUNTED');
expect(getLifeCycleState(instance)).toBe('MOUNTED');
ReactDOM.unmountComponentAtNode(container);
expect(instance._testJournal.stateAtStartOfWillUnmount).toEqual(
WILL_UNMOUNT_STATE,
);
// componentWillUnmount called right before unmount.
expect(instance._testJournal.lifeCycleAtStartOfWillUnmount).toBe('MOUNTED');
// But the current lifecycle of the component is unmounted.
/*expect(getLifeCycleState(instance)).toBe('UNMOUNTED');
expect(instance.state).toEqual(POST_WILL_UNMOUNT_STATE);*/
});
it('should allow state updates in componentDidMount', () => {
/**
* calls setState in an componentDidMount.
*/
class SetStateInComponentDidMount extends React.Component {
state = {
stateField: this.props.valueToUseInitially,
};
componentDidMount() {
this.setState({stateField: this.props.valueToUseInOnDOMReady});
}
render() {
return ;
}
}
var instance = (
);
instance = ReactTestUtils.renderIntoDocument(instance);
expect(instance.state.stateField).toBe('goodbye');
});
it('should call nested lifecycle methods in the right order', () => {
var log;
var logger = function(msg) {
return function() {
// return true for shouldComponentUpdate
log.push(msg);
return true;
};
};
class Outer extends React.Component {
componentWillMount = logger('outer componentWillMount');
componentDidMount = logger('outer componentDidMount');
componentWillReceiveProps = logger('outer componentWillReceiveProps');
shouldComponentUpdate = logger('outer shouldComponentUpdate');
componentWillUpdate = logger('outer componentWillUpdate');
componentDidUpdate = logger('outer componentDidUpdate');
componentWillUnmount = logger('outer componentWillUnmount');
render() {
return
;
}
}
class Inner extends React.Component {
componentWillMount = logger('inner componentWillMount');
componentDidMount = logger('inner componentDidMount');
componentWillReceiveProps = logger('inner componentWillReceiveProps');
shouldComponentUpdate = logger('inner shouldComponentUpdate');
componentWillUpdate = logger('inner componentWillUpdate');
componentDidUpdate = logger('inner componentDidUpdate');
componentWillUnmount = logger('inner componentWillUnmount');
render() {
return {this.props.x};
}
}
var container = document.createElement('div');
log = [];
ReactDOM.render(, container);
expect(log).toEqual([
'outer componentWillMount',
'inner componentWillMount',
'inner componentDidMount',
'outer componentDidMount',
]);
log = [];
ReactDOM.render(, container);
expect(log).toEqual([
'outer componentWillReceiveProps',
'outer shouldComponentUpdate',
'outer componentWillUpdate',
'inner componentWillReceiveProps',
'inner shouldComponentUpdate',
'inner componentWillUpdate',
'inner componentDidUpdate',
'outer componentDidUpdate',
]);
log = [];
ReactDOM.unmountComponentAtNode(container);
expect(log).toEqual([
'outer componentWillUnmount',
'inner componentWillUnmount',
]);
});
//暂不支持这种形式的component
/*it('calls effects on module-pattern component', function() {
const log = [];
function Parent() {
return {
render() {
expect(typeof this.props).toBe('object');
log.push('render');
return ;
},
componentWillMount() {
log.push('will mount');
},
componentDidMount() {
log.push('did mount');
},
componentDidUpdate() {
log.push('did update');
},
getChildContext() {
return {x: 2};
},
};
}
Parent.childContextTypes = {
x: PropTypes.number,
};
function Child(props, context) {
expect(context.x).toBe(2);
return ;
}
Child.contextTypes = {
x: PropTypes.number,
};
const div = document.createElement('div');
ReactDOM.render( c && log.push('ref')} />, div);
ReactDOM.render( c && log.push('ref')} />, div);
expect(log).toEqual([
'will mount',
'render',
'did mount',
'ref',
'render',
'did update',
'ref',
]);
});*/
});