"use strict";

import * as React from 'react';
import { View, Text } from 'react-native';
import { render, act } from '@testing-library/react-native';
import { ComponentWrapper } from "./ComponentWrapper.js";
import { Store } from "./Store.js";
import { mock, verify, instance } from 'ts-mockito';
import { ComponentEventsObserver } from "../events/ComponentEventsObserver.js";
import { jsx as _jsx } from "react/jsx-runtime";
describe('ComponentWrapper', () => {
  const componentName = 'example.MyComponent';
  let store;
  let myComponentProps;
  let mockedComponentEventsObserver;
  let componentEventsObserver;
  let uut;
  class MyComponent extends React.Component {
    static options = {
      title: 'MyComponentTitle'
    };
    render() {
      myComponentProps = this.props;
      if (this.props.renderCount) {
        this.props.renderCount();
      }
      return /*#__PURE__*/_jsx(Text, {
        children: this.props.text || 'Hello, World!'
      });
    }
  }
  class TestParent extends React.Component {
    constructor(props) {
      super(props);
      this.ChildClass = props.ChildClass;
      this.state = {
        propsFromState: {}
      };
    }
    setStateFromTest = newState => {
      this.setState({
        propsFromState: newState
      });
    };
    render() {
      const {
        ChildClass
      } = this;
      return /*#__PURE__*/_jsx(ChildClass, {
        componentId: "component1",
        ...this.state.propsFromState
      });
    }
  }
  beforeEach(() => {
    store = new Store();
    mockedComponentEventsObserver = mock(ComponentEventsObserver);
    componentEventsObserver = instance(mockedComponentEventsObserver);
    uut = new ComponentWrapper();
  });
  it('must have componentId as prop', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    const orig = console.error;
    console.error = a => a;
    expect(() => {
      render(/*#__PURE__*/_jsx(NavigationComponent, {}));
    }).toThrowError('Component example.MyComponent does not have a componentId!');
    console.error = orig;
  });
  it('wraps the component', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    expect(NavigationComponent).not.toBeInstanceOf(MyComponent);
    const {
      getByText
    } = render(/*#__PURE__*/_jsx(NavigationComponent, {
      componentId: 'component1'
    }));
    expect(getByText('Hello, World!')).toBeTruthy();
  });
  it('injects props from wrapper into original component', () => {
    const renderCount = jest.fn();
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    const {
      getByText
    } = render(/*#__PURE__*/_jsx(NavigationComponent, {
      componentId: 'component1',
      text: 'yo',
      renderCount: renderCount
    }));
    expect(getByText('yo')).toBeTruthy();
    expect(renderCount).toHaveBeenCalledTimes(1);
  });
  it('updates props from wrapper into original component on state change', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    let parentRef = null;
    render(/*#__PURE__*/_jsx(TestParent, {
      ref: ref => {
        parentRef = ref;
      },
      ChildClass: NavigationComponent
    }));
    expect(myComponentProps.foo).toEqual(undefined);

    // Use the ref to call setState wrapped in act
    act(() => {
      if (parentRef) {
        parentRef.setStateFromTest({
          foo: 'yo'
        });
      }
    });
    expect(myComponentProps.foo).toEqual('yo');
  });
  it('pulls props from the store and injects them into the inner component', () => {
    store.updateProps('component123', {
      numberProp: 1,
      stringProp: 'hello',
      objectProp: {
        a: 2
      }
    });
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    render(/*#__PURE__*/_jsx(NavigationComponent, {
      componentId: 'component123'
    }));
    expect(myComponentProps).toEqual({
      componentId: 'component123',
      componentName,
      numberProp: 1,
      stringProp: 'hello',
      objectProp: {
        a: 2
      }
    });
  });
  it('update props with callback', done => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    render(/*#__PURE__*/_jsx(NavigationComponent, {
      componentId: 'component123'
    }));
    function callback() {
      try {
        expect(true).toBe(true);
        done();
      } catch (error) {
        done(error);
      }
    }
    store.updateProps('component123', {
      someProp: 'someValue'
    }, callback);
  });
  it('updates props from store into inner component', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    render(/*#__PURE__*/_jsx(TestParent, {
      ChildClass: NavigationComponent
    }));
    expect(myComponentProps.myProp).toEqual(undefined);
    act(() => {
      store.updateProps('component1', {
        myProp: 'hello'
      });
    });
    expect(myComponentProps.myProp).toEqual('hello');
  });
  it('updates props from state into inner component', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    let parentRef = null;
    render(/*#__PURE__*/_jsx(TestParent, {
      ref: ref => {
        parentRef = ref;
      },
      ChildClass: NavigationComponent
    }));
    expect(myComponentProps.foo).toEqual(undefined);
    act(() => {
      if (parentRef) {
        parentRef.setStateFromTest({
          foo: 'yo'
        });
      }
    });
    expect(myComponentProps.foo).toEqual('yo');
  });
  it('protects id from change', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    let parentRef = null;
    render(/*#__PURE__*/_jsx(TestParent, {
      ref: ref => {
        parentRef = ref;
      },
      ChildClass: NavigationComponent
    }));
    expect(myComponentProps.componentId).toEqual('component1');
    if (parentRef) {
      parentRef.setStateFromTest({
        id: 'ERROR'
      });
    }
    expect(myComponentProps.componentId).toEqual('component1');
  });
  it('cleans props from store on unMount', () => {
    store.updateProps('component123', {
      foo: 'bar'
    });
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    const {
      unmount
    } = render(/*#__PURE__*/_jsx(NavigationComponent, {
      componentId: 'component123'
    }));
    expect(store.getPropsForId('component123')).toEqual({
      foo: 'bar'
    });
    unmount();
    expect(store.getPropsForId('component123')).toEqual({});
  });
  it('merges static members from wrapped component when generated', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    expect(NavigationComponent.options).toEqual({
      title: 'MyComponentTitle'
    });
  });
  it('calls unmounted on componentEventsObserver', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    const {
      unmount
    } = render(/*#__PURE__*/_jsx(NavigationComponent, {
      componentId: 'component123'
    }));
    verify(mockedComponentEventsObserver.unmounted('component123')).never();
    unmount();
    verify(mockedComponentEventsObserver.unmounted('component123')).once();
  });
  it('renders HOC components correctly', () => {
    const generator = () => props => /*#__PURE__*/_jsx(View, {
      children: /*#__PURE__*/_jsx(MyComponent, {
        ...props
      })
    });
    uut = new ComponentWrapper();
    const NavigationComponent = uut.wrap(componentName, generator, store, componentEventsObserver);
    const {
      getByText
    } = render(/*#__PURE__*/_jsx(NavigationComponent, {
      componentId: 'component123'
    }));
    expect(getByText('Hello, World!')).toBeTruthy();
  });
  it('sets component instance in store when constructed', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    render(/*#__PURE__*/_jsx(NavigationComponent, {
      componentId: 'component1'
    }));
    expect(store.getComponentInstance('component1')).toBeTruthy();
  });
  it('Component generator is invoked only once', () => {
    const componentGenerator = jest.fn(() => MyComponent);
    uut.wrap(componentName, componentGenerator, store, componentEventsObserver);
    expect(componentGenerator.mock.calls.length).toBe(1);
  });
  describe(`register with redux store`, () => {
    class MyReduxComp extends React.Component {
      static options() {
        return {
          foo: 123
        };
      }
      render() {
        return /*#__PURE__*/_jsx(Text, {
          children: this.props.txt
        });
      }
    }
    function mapStateToProps(state) {
      return {
        txt: state.txt
      };
    }
    const ConnectedComp = require('react-redux').connect(mapStateToProps)(MyReduxComp);
    const ReduxProvider = require('react-redux').Provider;
    const initialState = {
      txt: 'it just works'
    };
    const reduxStore = {
      getState: () => initialState,
      dispatch: jest.fn(),
      subscribe: jest.fn(),
      replaceReducer: jest.fn()
    };
    it(`wraps the component with a react-redux provider with passed store`, () => {
      const NavigationComponent = uut.wrap(componentName, () => ConnectedComp, store, componentEventsObserver, undefined, ReduxProvider, reduxStore);
      const {
        getByText
      } = render(/*#__PURE__*/_jsx(ReduxProvider, {
        store: reduxStore,
        children: /*#__PURE__*/_jsx(NavigationComponent, {
          componentId: 'theCompId'
        })
      }));
      expect(getByText('it just works')).toBeTruthy();
      expect(NavigationComponent.options()).toEqual({
        foo: 123
      });
    });
  });
  it('initialize isMounted with false value', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    new NavigationComponent({
      componentId: 'component123'
    });
    expect(store.getComponentInstance('component123')?.isMounted).toEqual(false);
  });
  it('updates isMounted on componentDidMount', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    render(/*#__PURE__*/_jsx(NavigationComponent, {
      componentId: 'component123'
    }));
    expect(store.getComponentInstance('component123')?.isMounted).toEqual(true);
  });
  it('clears isMounted on componentDidUnmount', () => {
    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
    const {
      unmount
    } = render(/*#__PURE__*/_jsx(NavigationComponent, {
      componentId: 'component123'
    }));
    expect(store.getComponentInstance('component123')?.isMounted).toEqual(true);
    unmount();
    expect(store.getComponentInstance('component123')?.isMounted).toBeUndefined();
  });
});
//# sourceMappingURL=ComponentWrapper.test.js.map