/* eslint-disable consistent-this, react/no-multi-comp */ import React, { Component } from 'react'; import { AppRegistry, Text } from 'react-native'; import renderer from 'react-test-renderer'; import ContainerWrapper from './ContainerWrapper'; import Store from './Store'; describe('ContainerWrapper', () => { let myContainerRef; let testParentRef; let store; const containerName = 'example.MyContainer'; class MyContainer extends Component { constructor(props) { super(props); myContainerRef = this; } render() { return {'Hello, World!'}; } } class TestParent extends Component { constructor(props) { super(props); testParentRef = this; this.ChildClass = props.ChildClass; this.state = { propsFromState: {} }; } render() { const Child = this.ChildClass; return ( ); } } beforeEach(() => { store = new Store(); }); it('must have id as prop', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); expect(() => { renderer.create(); }).toThrow(new Error('Container example.MyContainer does not have an id!')); }); it('wraps the container', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); expect(NavigationContainer).not.toBeInstanceOf(MyContainer); const tree = renderer.create(); expect(tree.toJSON().children).toEqual(['Hello, World!']); expect(myContainerRef).toBeInstanceOf(MyContainer); }); it('injects props from wrapper into original container', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); renderer.create(); expect(myContainerRef.props.myProp).toEqual('yo'); }); it('updates props from wrapper into original container', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); renderer.create(); expect(myContainerRef.props.foo).toEqual(undefined); testParentRef.setState({ propsFromState: { foo: 'yo' } }); expect(myContainerRef.props.foo).toEqual('yo'); }); it('pulls props from the store and injects them into the inner container', () => { store.setPropsForContainerId('container123', { numberProp: 1, stringProp: 'hello', objectProp: { a: 2 } }); const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); renderer.create(); expect(myContainerRef.props).toEqual({ id: 'container123', numberProp: 1, stringProp: 'hello', objectProp: { a: 2 } }); }); it('updates props from store into inner container', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); renderer.create(); store.setPropsForContainerId('container1', { myProp: 'hello' }); expect(myContainerRef.props.foo).toEqual(undefined); expect(myContainerRef.props.myProp).toEqual(undefined); testParentRef.setState({ propsFromState: { foo: 'yo' } }); expect(myContainerRef.props.foo).toEqual('yo'); expect(myContainerRef.props.myProp).toEqual('hello'); }); it('protects id from change', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); renderer.create(); expect(myContainerRef.props.id).toEqual('container1'); testParentRef.setState({ propsFromState: { id: 'ERROR' } }); expect(myContainerRef.props.id).toEqual('container1'); }); it('assignes key by id', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); renderer.create(); expect(myContainerRef.props.id).toEqual('container1'); expect(myContainerRef._reactInternalInstance._currentElement.key).toEqual('container1'); }); it('saves self ref into store', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); const tree = renderer.create(); expect(store.getRefForId('container1')).toBeDefined(); expect(store.getRefForId('container1')).toBe(tree.getInstance()); }); it('cleans ref from store on unMount', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); const tree = renderer.create(); expect(store.getRefForId('container1')).toBeDefined(); tree.unmount(); expect(store.getRefForId('container1')).toBeUndefined(); }); it('holds ref to OriginalContainer', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); const tree = renderer.create(); expect(tree.getInstance().originalContainerRef).toBe(myContainerRef); }); it('cleans ref to internal container on unount', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); const tree = renderer.create(); const instance = tree.getInstance(); expect(instance.originalContainerRef).toBeInstanceOf(Component); tree.unmount(); expect(instance.originalContainerRef).toBeFalsy(); }); describe('container lifecycle', () => { const onStartCallback = jest.fn(); const onStopCallback = jest.fn(); class MyLifecycleContainer extends MyContainer { onStart() { onStartCallback(); } onStop() { onStopCallback(); } } it('onStart and onStop are optional', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store); const tree = renderer.create(); expect(() => tree.getInstance().onStart()).not.toThrow(); expect(() => tree.getInstance().onStop()).not.toThrow(); }); it('calls onStart on OriginalContainer', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyLifecycleContainer, store); const tree = renderer.create(); expect(onStartCallback).toHaveBeenCalledTimes(0); tree.getInstance().onStart(); expect(onStartCallback).toHaveBeenCalledTimes(1); }); it('calls onSop on OriginalContainer', () => { const NavigationContainer = ContainerWrapper.wrap(containerName, MyLifecycleContainer, store); const tree = renderer.create(); expect(onStopCallback).toHaveBeenCalledTimes(0); tree.getInstance().onStop(); expect(onStopCallback).toHaveBeenCalledTimes(1); }); }); });