react-native-navigation的迁移库

ComponentWrapper.test.tsx 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import * as React from 'react';
  2. import { View, Text } from 'react-native';
  3. import * as renderer from 'react-test-renderer';
  4. import { ComponentWrapper } from './ComponentWrapper';
  5. import { Store } from './Store';
  6. import { mock, verify, instance } from 'ts-mockito';
  7. import { ComponentEventsObserver } from '../events/ComponentEventsObserver';
  8. describe('ComponentWrapper', () => {
  9. const componentName = 'example.MyComponent';
  10. let store;
  11. let myComponentProps;
  12. let mockedComponentEventsObserver: ComponentEventsObserver;
  13. let componentEventsObserver: ComponentEventsObserver;
  14. let uut: ComponentWrapper;
  15. class MyComponent extends React.Component<any, any> {
  16. static options = {
  17. title: 'MyComponentTitle'
  18. };
  19. render() {
  20. myComponentProps = this.props;
  21. if (this.props.renderCount) {
  22. this.props.renderCount();
  23. }
  24. return <Text>{this.props.text || 'Hello, World!'}</Text>;
  25. }
  26. }
  27. class TestParent extends React.Component<any, any> {
  28. private ChildClass;
  29. constructor(props) {
  30. super(props);
  31. this.ChildClass = props.ChildClass;
  32. this.state = { propsFromState: {} };
  33. }
  34. render() {
  35. return (
  36. <this.ChildClass
  37. componentId='component1'
  38. {...this.state.propsFromState}
  39. />
  40. );
  41. }
  42. }
  43. beforeEach(() => {
  44. store = new Store();
  45. mockedComponentEventsObserver = mock(ComponentEventsObserver);
  46. componentEventsObserver = instance(mockedComponentEventsObserver);
  47. uut = new ComponentWrapper();
  48. });
  49. it('must have componentId as prop', () => {
  50. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  51. const orig = console.error;
  52. console.error = (a) => a;
  53. expect(() => {
  54. renderer.create(<NavigationComponent />);
  55. }).toThrowError('Component example.MyComponent does not have a componentId!');
  56. console.error = orig;
  57. });
  58. it('wraps the component', () => {
  59. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  60. expect(NavigationComponent).not.toBeInstanceOf(MyComponent);
  61. const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
  62. expect(tree.toJSON()!.children).toEqual(['Hello, World!']);
  63. });
  64. it('injects props from wrapper into original component', () => {
  65. const renderCount = jest.fn();
  66. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  67. const tree = renderer.create(<NavigationComponent componentId={'component1'} text={'yo'} renderCount={renderCount} />);
  68. expect(tree.toJSON()!.children).toEqual(['yo']);
  69. expect(renderCount).toHaveBeenCalledTimes(1);
  70. });
  71. it('updates props from wrapper into original component on state change', () => {
  72. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  73. const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
  74. expect(myComponentProps.foo).toEqual(undefined);
  75. (tree.getInstance() as any).setState({ propsFromState: { foo: 'yo' } });
  76. expect(myComponentProps.foo).toEqual('yo');
  77. });
  78. it('pulls props from the store and injects them into the inner component', () => {
  79. store.setPropsForId('component123', { numberProp: 1, stringProp: 'hello', objectProp: { a: 2 } });
  80. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  81. renderer.create(<NavigationComponent componentId={'component123'} />);
  82. expect(myComponentProps).toEqual({ componentId: 'component123', numberProp: 1, stringProp: 'hello', objectProp: { a: 2 } });
  83. });
  84. it('updates props from store into inner component', () => {
  85. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  86. const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
  87. store.setPropsForId('component1', { myProp: 'hello' });
  88. expect(myComponentProps.foo).toEqual(undefined);
  89. expect(myComponentProps.myProp).toEqual(undefined);
  90. (tree.getInstance() as any).setState({ propsFromState: { foo: 'yo' } });
  91. expect(myComponentProps.foo).toEqual('yo');
  92. expect(myComponentProps.myProp).toEqual('hello');
  93. });
  94. it('protects id from change', () => {
  95. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  96. const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
  97. expect(myComponentProps.componentId).toEqual('component1');
  98. (tree.getInstance() as any).setState({ propsFromState: { id: 'ERROR' } });
  99. expect(myComponentProps.componentId).toEqual('component1');
  100. });
  101. xit('assigns key by componentId', () => {
  102. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  103. const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
  104. expect(myComponentProps.componentId).toEqual('component1');
  105. console.log(Object.keys(tree.root.findByType(NavigationComponent).instance._reactInternalFiber));
  106. console.log(tree.root.findByType(NavigationComponent).instance._reactInternalFiber.child.child.child.return.return.key);
  107. expect((tree.getInstance() as any)._reactInternalInstance.child.child.Fibernode.key).toEqual('component1');
  108. });
  109. it('cleans props from store on unMount', () => {
  110. store.setPropsForId('component123', { foo: 'bar' });
  111. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  112. const tree = renderer.create(<NavigationComponent componentId={'component123'} />);
  113. expect(store.getPropsForId('component123')).toEqual({ foo: 'bar' });
  114. tree.unmount();
  115. expect(store.getPropsForId('component123')).toEqual({});
  116. });
  117. it('merges static members from wrapped component when generated', () => {
  118. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver) as any;
  119. expect(NavigationComponent.options).toEqual({ title: 'MyComponentTitle' });
  120. });
  121. it('calls unmounted on componentEventsObserver', () => {
  122. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  123. const tree = renderer.create(<NavigationComponent componentId={'component123'} />);
  124. verify(mockedComponentEventsObserver.unmounted('component123')).never();
  125. tree.unmount();
  126. verify(mockedComponentEventsObserver.unmounted('component123')).once();
  127. });
  128. it('renders HOC components correctly', () => {
  129. const generator = () => (props) => (
  130. <View>
  131. <MyComponent {...props}/>
  132. </View>
  133. );
  134. uut = new ComponentWrapper();
  135. const NavigationComponent = uut.wrap(componentName, generator, store, componentEventsObserver);
  136. const tree = renderer.create(<NavigationComponent componentId={'component123'} />);
  137. expect(tree.root.findByType(View)).toBeDefined()
  138. expect(tree.root.findByType(MyComponent).props).toEqual({componentId: 'component123'});
  139. });
  140. describe(`register with redux store`, () => {
  141. class MyReduxComp extends React.Component<any> {
  142. static get options() {
  143. return { foo: 123 };
  144. }
  145. render() {
  146. return (
  147. <Text>{this.props.txt}</Text>
  148. );
  149. }
  150. }
  151. function mapStateToProps(state) {
  152. return {
  153. txt: state.txt
  154. };
  155. }
  156. const ConnectedComp = require('react-redux').connect(mapStateToProps)(MyReduxComp);
  157. const ReduxProvider = require('react-redux').Provider;
  158. const initialState = { txt: 'it just works' };
  159. const reduxStore = require('redux').createStore((state = initialState) => state);
  160. it(`wraps the component with a react-redux provider with passed store`, () => {
  161. const NavigationComponent = uut.wrap(componentName, () => ConnectedComp, store, componentEventsObserver, undefined, ReduxProvider, reduxStore);
  162. const tree = renderer.create(<NavigationComponent componentId={'theCompId'} />);
  163. expect(tree.toJSON()!.children).toEqual(['it just works']);
  164. expect((NavigationComponent as any).options).toEqual({ foo: 123 });
  165. });
  166. });
  167. });