aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/preact/test/browser/components.js
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/preact/test/browser/components.js')
-rw-r--r--thirdparty/preact/test/browser/components.js713
1 files changed, 713 insertions, 0 deletions
diff --git a/thirdparty/preact/test/browser/components.js b/thirdparty/preact/test/browser/components.js
new file mode 100644
index 000000000..b4649a719
--- /dev/null
+++ b/thirdparty/preact/test/browser/components.js
@@ -0,0 +1,713 @@
+import { h, render, rerender, Component } from '../../src/preact';
+/** @jsx h */
+
+let spyAll = obj => Object.keys(obj).forEach( key => sinon.spy(obj,key) );
+
+function getAttributes(node) {
+ let attrs = {};
+ if (node.attributes) {
+ for (let i=node.attributes.length; i--; ) {
+ attrs[node.attributes[i].name] = node.attributes[i].value;
+ }
+ }
+ return attrs;
+}
+
+// hacky normalization of attribute order across browsers.
+function sortAttributes(html) {
+ return html.replace(/<([a-z0-9-]+)((?:\s[a-z0-9:_.-]+=".*?")+)((?:\s*\/)?>)/gi, (s, pre, attrs, after) => {
+ let list = attrs.match(/\s[a-z0-9:_.-]+=".*?"/gi).sort( (a, b) => a>b ? 1 : -1 );
+ if (~after.indexOf('/')) after = '></'+pre+'>';
+ return '<' + pre + list.join('') + after;
+ });
+}
+
+const Empty = () => null;
+
+describe('Components', () => {
+ let scratch;
+
+ before( () => {
+ scratch = document.createElement('div');
+ (document.body || document.documentElement).appendChild(scratch);
+ });
+
+ beforeEach( () => {
+ let c = scratch.firstElementChild;
+ if (c) render(<Empty />, scratch, c);
+ scratch.innerHTML = '';
+ });
+
+ after( () => {
+ scratch.parentNode.removeChild(scratch);
+ scratch = null;
+ });
+
+ it('should render components', () => {
+ class C1 extends Component {
+ render() {
+ return <div>C1</div>;
+ }
+ }
+ sinon.spy(C1.prototype, 'render');
+ render(<C1 />, scratch);
+
+ expect(C1.prototype.render)
+ .to.have.been.calledOnce
+ .and.to.have.been.calledWithMatch({}, {})
+ .and.to.have.returned(sinon.match({ nodeName:'div' }));
+
+ expect(scratch.innerHTML).to.equal('<div>C1</div>');
+ });
+
+
+ it('should render functional components', () => {
+ const PROPS = { foo:'bar', onBaz:()=>{} };
+
+ const C3 = sinon.spy( props => <div {...props} /> );
+
+ render(<C3 {...PROPS} />, scratch);
+
+ expect(C3)
+ .to.have.been.calledOnce
+ .and.to.have.been.calledWith(PROPS)
+ .and.to.have.returned(sinon.match({
+ nodeName: 'div',
+ attributes: PROPS
+ }));
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar"></div>');
+ });
+
+
+ it('should render components with props', () => {
+ const PROPS = { foo:'bar', onBaz:()=>{} };
+ let constructorProps;
+
+ class C2 extends Component {
+ constructor(props) {
+ super(props);
+ constructorProps = props;
+ }
+ render(props) {
+ return <div {...props} />;
+ }
+ }
+ sinon.spy(C2.prototype, 'render');
+
+ render(<C2 {...PROPS} />, scratch);
+
+ expect(constructorProps).to.deep.equal(PROPS);
+
+ expect(C2.prototype.render)
+ .to.have.been.calledOnce
+ .and.to.have.been.calledWithMatch(PROPS, {})
+ .and.to.have.returned(sinon.match({
+ nodeName: 'div',
+ attributes: PROPS
+ }));
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar"></div>');
+ });
+
+
+ // Test for Issue #73
+ it('should remove orphaned elements replaced by Components', () => {
+ class Comp extends Component {
+ render() {
+ return <span>span in a component</span>;
+ }
+ }
+
+ let root;
+ function test(content) {
+ root = render(content, scratch, root);
+ }
+
+ test(<Comp />);
+ test(<div>just a div</div>);
+ test(<Comp />);
+
+ expect(scratch.innerHTML).to.equal('<span>span in a component</span>');
+ });
+
+
+ // Test for Issue #176
+ it('should remove children when root changes to text node', () => {
+ let comp;
+
+ class Comp extends Component {
+ render(_, { alt }) {
+ return alt ? 'asdf' : <div>test</div>;
+ }
+ }
+
+ render(<Comp ref={c=>comp=c} />, scratch);
+
+ comp.setState({ alt:true });
+ comp.forceUpdate();
+ expect(scratch.innerHTML, 'switching to textnode').to.equal('asdf');
+
+ comp.setState({ alt:false });
+ comp.forceUpdate();
+ expect(scratch.innerHTML, 'switching to element').to.equal('<div>test</div>');
+
+ comp.setState({ alt:true });
+ comp.forceUpdate();
+ expect(scratch.innerHTML, 'switching to textnode 2').to.equal('asdf');
+ });
+
+
+ describe('props.children', () => {
+ it('should support passing children as a prop', () => {
+ const Foo = props => <div {...props} />;
+
+ render(<Foo a="b" children={[
+ <span class="bar">bar</span>,
+ '123',
+ 456
+ ]} />, scratch);
+
+ expect(scratch.innerHTML).to.equal('<div a="b"><span class="bar">bar</span>123456</div>');
+ });
+
+ it('should be ignored when explicit children exist', () => {
+ const Foo = props => <div {...props}>a</div>;
+
+ render(<Foo children={'b'} />, scratch);
+
+ expect(scratch.innerHTML).to.equal('<div>a</div>');
+ });
+ });
+
+
+ describe('High-Order Components', () => {
+ it('should render nested functional components', () => {
+ const PROPS = { foo:'bar', onBaz:()=>{} };
+
+ const Outer = sinon.spy(
+ props => <Inner {...props} />
+ );
+
+ const Inner = sinon.spy(
+ props => <div {...props}>inner</div>
+ );
+
+ render(<Outer {...PROPS} />, scratch);
+
+ expect(Outer)
+ .to.have.been.calledOnce
+ .and.to.have.been.calledWith(PROPS)
+ .and.to.have.returned(sinon.match({
+ nodeName: Inner,
+ attributes: PROPS
+ }));
+
+ expect(Inner)
+ .to.have.been.calledOnce
+ .and.to.have.been.calledWith(PROPS)
+ .and.to.have.returned(sinon.match({
+ nodeName: 'div',
+ attributes: PROPS,
+ children: ['inner']
+ }));
+
+ expect(scratch.innerHTML).to.equal('<div foo="bar">inner</div>');
+ });
+
+ it('should re-render nested functional components', () => {
+ let doRender = null;
+ class Outer extends Component {
+ componentDidMount() {
+ let i = 1;
+ doRender = () => this.setState({ i: ++i });
+ }
+ componentWillUnmount() {}
+ render(props, { i }) {
+ return <Inner i={i} {...props} />;
+ }
+ }
+ sinon.spy(Outer.prototype, 'render');
+ sinon.spy(Outer.prototype, 'componentWillUnmount');
+
+ let j = 0;
+ const Inner = sinon.spy(
+ props => <div j={ ++j } {...props}>inner</div>
+ );
+
+ render(<Outer foo="bar" />, scratch);
+
+ // update & flush
+ doRender();
+ rerender();
+
+ expect(Outer.prototype.componentWillUnmount)
+ .not.to.have.been.called;
+
+ expect(Inner).to.have.been.calledTwice;
+
+ expect(Inner.secondCall)
+ .to.have.been.calledWith({ foo:'bar', i:2 })
+ .and.to.have.returned(sinon.match({
+ attributes: {
+ j: 2,
+ i: 2,
+ foo: 'bar'
+ }
+ }));
+
+ expect(getAttributes(scratch.firstElementChild)).to.eql({
+ j: '2',
+ i: '2',
+ foo: 'bar'
+ });
+
+ // update & flush
+ doRender();
+ rerender();
+
+ expect(Inner).to.have.been.calledThrice;
+
+ expect(Inner.thirdCall)
+ .to.have.been.calledWith({ foo:'bar', i:3 })
+ .and.to.have.returned(sinon.match({
+ attributes: {
+ j: 3,
+ i: 3,
+ foo: 'bar'
+ }
+ }));
+
+ expect(getAttributes(scratch.firstElementChild)).to.eql({
+ j: '3',
+ i: '3',
+ foo: 'bar'
+ });
+ });
+
+ it('should re-render nested components', () => {
+ let doRender = null,
+ alt = false;
+
+ class Outer extends Component {
+ componentDidMount() {
+ let i = 1;
+ doRender = () => this.setState({ i: ++i });
+ }
+ componentWillUnmount() {}
+ render(props, { i }) {
+ if (alt) return <div is-alt />;
+ return <Inner i={i} {...props} />;
+ }
+ }
+ sinon.spy(Outer.prototype, 'render');
+ sinon.spy(Outer.prototype, 'componentDidMount');
+ sinon.spy(Outer.prototype, 'componentWillUnmount');
+
+ let j = 0;
+ class Inner extends Component {
+ constructor(...args) {
+ super();
+ this._constructor(...args);
+ }
+ _constructor() {}
+ componentWillMount() {}
+ componentDidMount() {}
+ componentWillUnmount() {}
+ componentDidUnmount() {}
+ render(props) {
+ return <div j={ ++j } {...props}>inner</div>;
+ }
+ }
+ sinon.spy(Inner.prototype, '_constructor');
+ sinon.spy(Inner.prototype, 'render');
+ sinon.spy(Inner.prototype, 'componentWillMount');
+ sinon.spy(Inner.prototype, 'componentDidMount');
+ sinon.spy(Inner.prototype, 'componentDidUnmount');
+ sinon.spy(Inner.prototype, 'componentWillUnmount');
+
+ render(<Outer foo="bar" />, scratch);
+
+ expect(Outer.prototype.componentDidMount).to.have.been.calledOnce;
+
+ // update & flush
+ doRender();
+ rerender();
+
+ expect(Outer.prototype.componentWillUnmount).not.to.have.been.called;
+
+ expect(Inner.prototype._constructor).to.have.been.calledOnce;
+ expect(Inner.prototype.componentWillUnmount).not.to.have.been.called;
+ expect(Inner.prototype.componentDidUnmount).not.to.have.been.called;
+ expect(Inner.prototype.componentWillMount).to.have.been.calledOnce;
+ expect(Inner.prototype.componentDidMount).to.have.been.calledOnce;
+ expect(Inner.prototype.render).to.have.been.calledTwice;
+
+ expect(Inner.prototype.render.secondCall)
+ .to.have.been.calledWith({ foo:'bar', i:2 })
+ .and.to.have.returned(sinon.match({
+ attributes: {
+ j: 2,
+ i: 2,
+ foo: 'bar'
+ }
+ }));
+
+ expect(getAttributes(scratch.firstElementChild)).to.eql({
+ j: '2',
+ i: '2',
+ foo: 'bar'
+ });
+
+ expect(sortAttributes(scratch.innerHTML)).to.equal(sortAttributes('<div foo="bar" j="2" i="2">inner</div>'));
+
+ // update & flush
+ doRender();
+ rerender();
+
+ expect(Inner.prototype.componentWillUnmount).not.to.have.been.called;
+ expect(Inner.prototype.componentDidUnmount).not.to.have.been.called;
+ expect(Inner.prototype.componentWillMount).to.have.been.calledOnce;
+ expect(Inner.prototype.componentDidMount).to.have.been.calledOnce;
+ expect(Inner.prototype.render).to.have.been.calledThrice;
+
+ expect(Inner.prototype.render.thirdCall)
+ .to.have.been.calledWith({ foo:'bar', i:3 })
+ .and.to.have.returned(sinon.match({
+ attributes: {
+ j: 3,
+ i: 3,
+ foo: 'bar'
+ }
+ }));
+
+ expect(getAttributes(scratch.firstElementChild)).to.eql({
+ j: '3',
+ i: '3',
+ foo: 'bar'
+ });
+
+
+ // update & flush
+ alt = true;
+ doRender();
+ rerender();
+
+ expect(Inner.prototype.componentWillUnmount).to.have.been.calledOnce;
+ expect(Inner.prototype.componentDidUnmount).to.have.been.calledOnce;
+
+ expect(scratch.innerHTML).to.equal('<div is-alt="true"></div>');
+
+ // update & flush
+ alt = false;
+ doRender();
+ rerender();
+
+ expect(sortAttributes(scratch.innerHTML)).to.equal(sortAttributes('<div foo="bar" j="4" i="5">inner</div>'));
+ });
+
+ it('should resolve intermediary functional component', () => {
+ let ctx = {};
+ class Root extends Component {
+ getChildContext() {
+ return { ctx };
+ }
+ render() {
+ return <Func />;
+ }
+ }
+ const Func = sinon.spy( () => <Inner /> );
+ class Inner extends Component {
+ componentWillMount() {}
+ componentDidMount() {}
+ componentWillUnmount() {}
+ componentDidUnmount() {}
+ render() {
+ return <div>inner</div>;
+ }
+ }
+
+ spyAll(Inner.prototype);
+
+ let root = render(<Root />, scratch);
+
+ expect(Inner.prototype.componentWillMount).to.have.been.calledOnce;
+ expect(Inner.prototype.componentDidMount).to.have.been.calledOnce;
+ expect(Inner.prototype.componentWillMount).to.have.been.calledBefore(Inner.prototype.componentDidMount);
+
+ root = render(<asdf />, scratch, root);
+
+ expect(Inner.prototype.componentWillUnmount).to.have.been.calledOnce;
+ expect(Inner.prototype.componentDidUnmount).to.have.been.calledOnce;
+ expect(Inner.prototype.componentWillUnmount).to.have.been.calledBefore(Inner.prototype.componentDidUnmount);
+ });
+
+ it('should unmount children of high-order components without unmounting parent', () => {
+ let outer, inner2, counter=0;
+
+ class Outer extends Component {
+ constructor(props, context) {
+ super(props, context);
+ outer = this;
+ this.state = {
+ child: this.props.child
+ };
+ }
+ componentWillUnmount(){}
+ componentDidUnmount(){}
+ componentWillMount(){}
+ componentDidMount(){}
+ render(_, { child:C }) {
+ return <C />;
+ }
+ }
+ spyAll(Outer.prototype);
+
+ class Inner extends Component {
+ componentWillUnmount(){}
+ componentDidUnmount(){}
+ componentWillMount(){}
+ componentDidMount(){}
+ render() {
+ return h('element'+(++counter));
+ }
+ }
+ spyAll(Inner.prototype);
+
+ class Inner2 extends Component {
+ constructor(props, context) {
+ super(props, context);
+ inner2 = this;
+ }
+ componentWillUnmount(){}
+ componentDidUnmount(){}
+ componentWillMount(){}
+ componentDidMount(){}
+ render() {
+ return h('element'+(++counter));
+ }
+ }
+ spyAll(Inner2.prototype);
+
+ render(<Outer child={Inner} />, scratch);
+
+ // outer should only have been mounted once
+ expect(Outer.prototype.componentWillMount, 'outer initial').to.have.been.calledOnce;
+ expect(Outer.prototype.componentDidMount, 'outer initial').to.have.been.calledOnce;
+ expect(Outer.prototype.componentWillUnmount, 'outer initial').not.to.have.been.called;
+ expect(Outer.prototype.componentDidUnmount, 'outer initial').not.to.have.been.called;
+
+ // inner should only have been mounted once
+ expect(Inner.prototype.componentWillMount, 'inner initial').to.have.been.calledOnce;
+ expect(Inner.prototype.componentDidMount, 'inner initial').to.have.been.calledOnce;
+ expect(Inner.prototype.componentWillUnmount, 'inner initial').not.to.have.been.called;
+ expect(Inner.prototype.componentDidUnmount, 'inner initial').not.to.have.been.called;
+
+ outer.setState({ child:Inner2 });
+ outer.forceUpdate();
+
+ expect(Inner2.prototype.render).to.have.been.calledOnce;
+
+ // outer should still only have been mounted once
+ expect(Outer.prototype.componentWillMount, 'outer swap').to.have.been.calledOnce;
+ expect(Outer.prototype.componentDidMount, 'outer swap').to.have.been.calledOnce;
+ expect(Outer.prototype.componentWillUnmount, 'outer swap').not.to.have.been.called;
+ expect(Outer.prototype.componentDidUnmount, 'outer swap').not.to.have.been.called;
+
+ // inner should only have been mounted once
+ expect(Inner2.prototype.componentWillMount, 'inner2 swap').to.have.been.calledOnce;
+ expect(Inner2.prototype.componentDidMount, 'inner2 swap').to.have.been.calledOnce;
+ expect(Inner2.prototype.componentWillUnmount, 'inner2 swap').not.to.have.been.called;
+ expect(Inner2.prototype.componentDidUnmount, 'inner2 swap').not.to.have.been.called;
+
+ inner2.forceUpdate();
+
+ expect(Inner2.prototype.render, 'inner2 update').to.have.been.calledTwice;
+ expect(Inner2.prototype.componentWillMount, 'inner2 update').to.have.been.calledOnce;
+ expect(Inner2.prototype.componentDidMount, 'inner2 update').to.have.been.calledOnce;
+ expect(Inner2.prototype.componentWillUnmount, 'inner2 update').not.to.have.been.called;
+ expect(Inner2.prototype.componentDidUnmount, 'inner2 update').not.to.have.been.called;
+ });
+
+ it('should remount when swapping between HOC child types', () => {
+ class Outer extends Component {
+ render({ child: Child }) {
+ return <Child />;
+ }
+ }
+
+ class Inner extends Component {
+ componentWillMount() {}
+ componentWillUnmount() {}
+ render() {
+ return <div class="inner">foo</div>;
+ }
+ }
+ spyAll(Inner.prototype);
+
+ const InnerFunc = () => (
+ <div class="inner-func">bar</div>
+ );
+
+ let root = render(<Outer child={Inner} />, scratch, root);
+
+ expect(Inner.prototype.componentWillMount, 'initial mount').to.have.been.calledOnce;
+ expect(Inner.prototype.componentWillUnmount, 'initial mount').not.to.have.been.called;
+
+ Inner.prototype.componentWillMount.reset();
+ root = render(<Outer child={InnerFunc} />, scratch, root);
+
+ expect(Inner.prototype.componentWillMount, 'unmount').not.to.have.been.called;
+ expect(Inner.prototype.componentWillUnmount, 'unmount').to.have.been.calledOnce;
+
+ Inner.prototype.componentWillUnmount.reset();
+ root = render(<Outer child={Inner} />, scratch, root);
+
+ expect(Inner.prototype.componentWillMount, 'remount').to.have.been.calledOnce;
+ expect(Inner.prototype.componentWillUnmount, 'remount').not.to.have.been.called;
+ });
+ });
+
+ describe('Component Nesting', () => {
+ let useIntermediary = false;
+
+ let createComponent = (Intermediary) => {
+ class C extends Component {
+ componentWillMount() {}
+ componentDidUnmount() {}
+ render({ children }) {
+ if (!useIntermediary) return children[0];
+ let I = useIntermediary===true ? Intermediary : useIntermediary;
+ return <I>{children}</I>;
+ }
+ }
+ spyAll(C.prototype);
+ return C;
+ };
+
+ let createFunction = () => sinon.spy( ({ children }) => children[0] );
+
+ let root;
+ let rndr = n => root = render(n, scratch, root);
+
+ let F1 = createFunction();
+ let F2 = createFunction();
+ let F3 = createFunction();
+
+ let C1 = createComponent(F1);
+ let C2 = createComponent(F2);
+ let C3 = createComponent(F3);
+
+ let reset = () => [C1, C2, C3].reduce(
+ (acc, c) => acc.concat( Object.keys(c.prototype).map(key => c.prototype[key]) ),
+ [F1, F2, F3]
+ ).forEach( c => c.reset && c.reset() );
+
+
+ it('should handle lifecycle for no intermediary in component tree', () => {
+ reset();
+ rndr(<C1><C2><C3>Some Text</C3></C2></C1>);
+
+ expect(C1.prototype.componentWillMount, 'initial mount').to.have.been.calledOnce;
+ expect(C2.prototype.componentWillMount, 'initial mount').to.have.been.calledOnce;
+ expect(C3.prototype.componentWillMount, 'initial mount').to.have.been.calledOnce;
+
+ reset();
+ rndr(<C1><C2>Some Text</C2></C1>);
+
+ expect(C1.prototype.componentWillMount, 'unmount innermost, C1').not.to.have.been.called;
+ expect(C2.prototype.componentWillMount, 'unmount innermost, C2').not.to.have.been.called;
+ expect(C3.prototype.componentDidUnmount, 'unmount innermost, C3').to.have.been.calledOnce;
+
+ reset();
+ rndr(<C1><C3>Some Text</C3></C1>);
+
+ expect(C1.prototype.componentWillMount, 'swap innermost').not.to.have.been.called;
+ expect(C2.prototype.componentDidUnmount, 'swap innermost').to.have.been.calledOnce;
+ expect(C3.prototype.componentWillMount, 'swap innermost').to.have.been.calledOnce;
+
+ reset();
+ rndr(<C1><C2><C3>Some Text</C3></C2></C1>);
+
+ expect(C1.prototype.componentDidUnmount, 'inject between, C1').not.to.have.been.called;
+ expect(C1.prototype.componentWillMount, 'inject between, C1').not.to.have.been.called;
+ expect(C2.prototype.componentWillMount, 'inject between, C2').to.have.been.calledOnce;
+ expect(C3.prototype.componentDidUnmount, 'inject between, C3').to.have.been.calledOnce;
+ expect(C3.prototype.componentWillMount, 'inject between, C3').to.have.been.calledOnce;
+ });
+
+
+ it('should handle lifecycle for nested intermediary functional components', () => {
+ useIntermediary = true;
+
+ rndr(<div />);
+ reset();
+ rndr(<C1><C2><C3>Some Text</C3></C2></C1>);
+
+ expect(C1.prototype.componentWillMount, 'initial mount w/ intermediary fn, C1').to.have.been.calledOnce;
+ expect(C2.prototype.componentWillMount, 'initial mount w/ intermediary fn, C2').to.have.been.calledOnce;
+ expect(C3.prototype.componentWillMount, 'initial mount w/ intermediary fn, C3').to.have.been.calledOnce;
+
+ reset();
+ rndr(<C1><C2>Some Text</C2></C1>);
+
+ expect(C1.prototype.componentWillMount, 'unmount innermost w/ intermediary fn, C1').not.to.have.been.called;
+ expect(C2.prototype.componentWillMount, 'unmount innermost w/ intermediary fn, C2').not.to.have.been.called;
+ expect(C3.prototype.componentDidUnmount, 'unmount innermost w/ intermediary fn, C3').to.have.been.calledOnce;
+
+ reset();
+ rndr(<C1><C3>Some Text</C3></C1>);
+
+ expect(C1.prototype.componentWillMount, 'swap innermost w/ intermediary fn').not.to.have.been.called;
+ expect(C2.prototype.componentDidUnmount, 'swap innermost w/ intermediary fn').to.have.been.calledOnce;
+ expect(C3.prototype.componentWillMount, 'swap innermost w/ intermediary fn').to.have.been.calledOnce;
+
+ reset();
+ rndr(<C1><C2><C3>Some Text</C3></C2></C1>);
+
+ expect(C1.prototype.componentDidUnmount, 'inject between, C1 w/ intermediary fn').not.to.have.been.called;
+ expect(C1.prototype.componentWillMount, 'inject between, C1 w/ intermediary fn').not.to.have.been.called;
+ expect(C2.prototype.componentWillMount, 'inject between, C2 w/ intermediary fn').to.have.been.calledOnce;
+ expect(C3.prototype.componentDidUnmount, 'inject between, C3 w/ intermediary fn').to.have.been.calledOnce;
+ expect(C3.prototype.componentWillMount, 'inject between, C3 w/ intermediary fn').to.have.been.calledOnce;
+ });
+
+
+ it('should handle lifecycle for nested intermediary elements', () => {
+ useIntermediary = 'div';
+
+ rndr(<div />);
+ reset();
+ rndr(<C1><C2><C3>Some Text</C3></C2></C1>);
+
+ expect(C1.prototype.componentWillMount, 'initial mount w/ intermediary div, C1').to.have.been.calledOnce;
+ expect(C2.prototype.componentWillMount, 'initial mount w/ intermediary div, C2').to.have.been.calledOnce;
+ expect(C3.prototype.componentWillMount, 'initial mount w/ intermediary div, C3').to.have.been.calledOnce;
+
+ reset();
+ rndr(<C1><C2>Some Text</C2></C1>);
+
+ expect(C1.prototype.componentWillMount, 'unmount innermost w/ intermediary div, C1').not.to.have.been.called;
+ expect(C2.prototype.componentDidUnmount, 'unmount innermost w/ intermediary div, C2 ummount').not.to.have.been.called;
+ // @TODO this was just incorrect?
+ // expect(C2.prototype.componentWillMount, 'unmount innermost w/ intermediary div, C2').not.to.have.been.called;
+ expect(C3.prototype.componentDidUnmount, 'unmount innermost w/ intermediary div, C3').to.have.been.calledOnce;
+
+ reset();
+ rndr(<C1><C3>Some Text</C3></C1>);
+
+ expect(C1.prototype.componentWillMount, 'swap innermost w/ intermediary div').not.to.have.been.called;
+ expect(C2.prototype.componentDidUnmount, 'swap innermost w/ intermediary div').to.have.been.calledOnce;
+ expect(C3.prototype.componentWillMount, 'swap innermost w/ intermediary div').to.have.been.calledOnce;
+
+ reset();
+ rndr(<C1><C2><C3>Some Text</C3></C2></C1>);
+
+ expect(C1.prototype.componentDidUnmount, 'inject between, C1 w/ intermediary div').not.to.have.been.called;
+ expect(C1.prototype.componentWillMount, 'inject between, C1 w/ intermediary div').not.to.have.been.called;
+ expect(C2.prototype.componentWillMount, 'inject between, C2 w/ intermediary div').to.have.been.calledOnce;
+ expect(C3.prototype.componentDidUnmount, 'inject between, C3 w/ intermediary div').to.have.been.calledOnce;
+ expect(C3.prototype.componentWillMount, 'inject between, C3 w/ intermediary div').to.have.been.calledOnce;
+ });
+ });
+});