Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 81 additions & 13 deletions src/ShallowWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,19 @@ export default class ShallowWrapper {
this.root = this;
this.unrendered = nodes;
this.renderer = createShallowRenderer();
this.renderer.render(nodes, options.context);
withSetStateAllowed(() => {
batchedUpdates(() => {
this.renderer.render(nodes, options.context);
const instance = this.instance();
if (
options.lifecycleExperimental &&
instance &&
typeof instance.componentDidMount === 'function'
) {
instance.componentDidMount();
}
});
});
this.node = this.renderer.getRenderOutput();
this.nodes = [this.node];
this.length = 1;
Expand Down Expand Up @@ -105,7 +117,7 @@ export default class ShallowWrapper {
if (this.root !== this) {
throw new Error('ShallowWrapper::instance() can only be called on the root');
}
return this.renderer._instance._instance;
return this.renderer._instance ? this.renderer._instance._instance : null;
}

/**
Expand All @@ -127,6 +139,71 @@ export default class ShallowWrapper {
return this;
}

/**
* A method is for re-render with new props and context.
* This calls componentDidUpdate method if lifecycleExperimental is enabled.
*
* NOTE: can only be called on a wrapper instance that is also the root instance.
*
* @param {Object} props
* @param {Object} context
* @returns {ShallowWrapper}
*/
rerender(props, context) {
this.single(() => {
withSetStateAllowed(() => {
const instance = this.instance();
const state = instance.state;
const prevProps = instance.props;
const prevContext = instance.context;
const nextProps = props || prevProps;
const nextContext = context || prevContext;
batchedUpdates(() => {
let shouldRender = true;
// dirty hack:
// make sure that componentWillReceiveProps is called before shouldComponentUpdate
let originalComponentWillReceiveProps;
if (
this.options.lifecycleExperimental &&
instance &&
typeof instance.componentWillReceiveProps === 'function'
) {
instance.componentWillReceiveProps(nextProps, nextContext);
originalComponentWillReceiveProps = instance.componentWillReceiveProps;
instance.componentWillReceiveProps = () => {};
}
if (
this.options.lifecycleExperimental &&
instance &&
typeof instance.shouldComponentUpdate === 'function'
) {
shouldRender = instance.shouldComponentUpdate(nextProps, state, nextContext);
}
if (shouldRender) {
if (props) this.unrendered = React.cloneElement(this.unrendered, props);
// dirty hack: avoid calling shouldComponentUpdate twice
const originalShouldComponentUpdate = instance.shouldComponentUpdate;
instance.shouldComponentUpdate = () => true;
this.renderer.render(this.unrendered, nextContext);
instance.shouldComponentUpdate = originalShouldComponentUpdate;
if (
this.options.lifecycleExperimental &&
instance &&
typeof instance.componentDidUpdate === 'function'
) {
instance.componentDidUpdate(prevProps, state, prevContext);
}
this.update();
}
if (originalComponentWillReceiveProps) {
instance.componentWillReceiveProps = originalComponentWillReceiveProps;
}
});
});
});
return this;
}

/**
* A method that sets the props of the root component, and re-renders. Useful for when you are
* wanting to test how the component behaves over time with changing props. Calling this, for
Expand All @@ -144,14 +221,7 @@ export default class ShallowWrapper {
if (this.root !== this) {
throw new Error('ShallowWrapper::setProps() can only be called on the root');
}
this.single(() => {
withSetStateAllowed(() => {
this.unrendered = React.cloneElement(this.unrendered, props);
this.renderer.render(this.unrendered, this.options.context);
this.update();
});
});
return this;
return this.rerender(props);
}

/**
Expand Down Expand Up @@ -201,9 +271,7 @@ export default class ShallowWrapper {
'a context option'
);
}
this.renderer.render(this.unrendered, context);
this.update();
return this;
return this.rerender(null, context);
}

/**
Expand Down
Loading