const React = require('react');
const { Component } = require('react');
const { Text } = require('react-native');
const renderer = require('react-test-renderer');
const ComponentWrapper = require('./ComponentWrapper');
const Store = require('./Store');
describe('ComponentWrapper', () => {
let store;
const componentName = 'example.MyComponent';
let childRef;
class MyComponent extends Component {
render() {
return {'Hello, World!'};
}
}
class TestParent extends Component {
constructor(props) {
super(props);
this.ChildClass = props.ChildClass;
this.state = { propsFromState: {} };
}
render() {
const Child = this.ChildClass;
return (
childRef = r}
componentId="component1"
{...this.state.propsFromState}
/>
);
}
}
beforeEach(() => {
store = new Store();
});
it('must have componentId as prop', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const orig = console.error;
console.error = (a) => a;
expect(() => {
renderer.create();
}).toThrow(new Error('Component example.MyComponent does not have a componentId!'));
console.error = orig;
});
it('wraps the component', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
expect(NavigationComponent).not.toBeInstanceOf(MyComponent);
const tree = renderer.create();
expect(tree.toJSON().children).toEqual(['Hello, World!']);
expect(tree.getInstance().originalComponentRef).toBeInstanceOf(MyComponent);
});
it('injects props from wrapper into original component', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const tree = renderer.create();
expect(tree.getInstance().originalComponentRef.props.myProp).toEqual('yo');
});
it('updates props from wrapper into original component', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const tree = renderer.create();
expect(childRef.props.foo).toEqual(undefined);
tree.getInstance().setState({ propsFromState: { foo: 'yo' } });
expect(childRef.props.foo).toEqual('yo');
});
it('pulls props from the store and injects them into the inner component', () => {
store.setPropsForComponentId('component123', { numberProp: 1, stringProp: 'hello', objectProp: { a: 2 } });
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const tree = renderer.create();
const originalComponentProps = tree.getInstance().originalComponentRef.props;
expect(originalComponentProps).toEqual({ componentId: 'component123', numberProp: 1, stringProp: 'hello', objectProp: { a: 2 } });
});
it('updates props from store into inner component', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const tree = renderer.create();
store.setPropsForComponentId('component1', { myProp: 'hello' });
expect(childRef.originalComponentRef.props.foo).toEqual(undefined);
expect(childRef.originalComponentRef.props.myProp).toEqual(undefined);
tree.getInstance().setState({ propsFromState: { foo: 'yo' } });
expect(childRef.originalComponentRef.props.foo).toEqual('yo');
expect(childRef.originalComponentRef.props.myProp).toEqual('hello');
});
it('protects id from change', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const tree = renderer.create();
expect(childRef.originalComponentRef.props.componentId).toEqual('component1');
tree.getInstance().setState({ propsFromState: { id: 'ERROR' } });
expect(childRef.originalComponentRef.props.componentId).toEqual('component1');
});
it('assignes key by id', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const tree = renderer.create();
expect(tree.getInstance().originalComponentRef.props.componentId).toEqual('component1');
expect(tree.getInstance().originalComponentRef._reactInternalInstance.key).toEqual('component1');
});
it('saves self ref into store', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const tree = renderer.create();
expect(store.getRefForComponentId('component1')).toBeDefined();
expect(store.getRefForComponentId('component1')).toBe(tree.getInstance());
});
it('cleans ref from store on unMount', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const tree = renderer.create();
expect(store.getRefForComponentId('component1')).toBeDefined();
tree.unmount();
expect(store.getRefForComponentId('component1')).toBeUndefined();
});
it('holds ref to OriginalComponent', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const tree = renderer.create();
expect(tree.getInstance().originalComponentRef).toBeDefined();
expect(tree.getInstance().originalComponentRef).toBeInstanceOf(MyComponent);
});
it('cleans ref to internal component on unount', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const tree = renderer.create();
const instance = tree.getInstance();
expect(instance.originalComponentRef).toBeInstanceOf(Component);
tree.unmount();
expect(instance.originalComponentRef).toBeFalsy();
});
describe('component lifecycle', () => {
const didAppearCallback = jest.fn();
const didDisappearCallback = jest.fn();
const onNavigationButtonPressedCallback = jest.fn();
class MyLifecycleComponent extends MyComponent {
didAppear() {
didAppearCallback();
}
didDisappear() {
didDisappearCallback();
}
onNavigationButtonPressed() {
onNavigationButtonPressedCallback();
}
}
it('didAppear, didDisappear and onNavigationButtonPressed are optional', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
const tree = renderer.create();
expect(() => tree.getInstance().didAppear()).not.toThrow();
expect(() => tree.getInstance().didDisappear()).not.toThrow();
expect(() => tree.getInstance().onNavigationButtonPressed()).not.toThrow();
});
it('calls didAppear on OriginalComponent', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyLifecycleComponent, store);
const tree = renderer.create();
expect(didAppearCallback).toHaveBeenCalledTimes(0);
tree.getInstance().didAppear();
expect(didAppearCallback).toHaveBeenCalledTimes(1);
});
it('calls didDisappear on OriginalComponent', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyLifecycleComponent, store);
const tree = renderer.create();
expect(didDisappearCallback).toHaveBeenCalledTimes(0);
tree.getInstance().didDisappear();
expect(didDisappearCallback).toHaveBeenCalledTimes(1);
});
it('calls onNavigationButtonPressed on OriginalComponent', () => {
const NavigationComponent = ComponentWrapper.wrap(componentName, MyLifecycleComponent, store);
const tree = renderer.create();
expect(onNavigationButtonPressedCallback).toHaveBeenCalledTimes(0);
tree.getInstance().onNavigationButtonPressed();
expect(onNavigationButtonPressedCallback).toHaveBeenCalledTimes(1);
});
});
});