react-native-navigation的迁移库

ComponentWrapper.test.tsx 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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: Store;
  11. let myComponentProps: any;
  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: any;
  29. constructor(props: any) {
  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: any) => 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.updateProps('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. renderer.create(<TestParent ChildClass={NavigationComponent} />);
  87. expect(myComponentProps.myProp).toEqual(undefined);
  88. store.updateProps('component1', { myProp: 'hello' });
  89. expect(myComponentProps.myProp).toEqual('hello');
  90. });
  91. it('updates props from state into inner component', () => {
  92. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  93. const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
  94. expect(myComponentProps.foo).toEqual(undefined);
  95. (tree.getInstance() as any).setState({ propsFromState: { foo: 'yo' } });
  96. expect(myComponentProps.foo).toEqual('yo');
  97. });
  98. it('protects id from change', () => {
  99. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  100. const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
  101. expect(myComponentProps.componentId).toEqual('component1');
  102. (tree.getInstance() as any).setState({ propsFromState: { id: 'ERROR' } });
  103. expect(myComponentProps.componentId).toEqual('component1');
  104. });
  105. xit('assigns key by componentId', () => {
  106. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  107. const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
  108. expect(myComponentProps.componentId).toEqual('component1');
  109. console.log(Object.keys(tree.root.findByType(NavigationComponent).instance._reactInternalFiber));
  110. console.log(tree.root.findByType(NavigationComponent).instance._reactInternalFiber.child.child.child.return.return.key);
  111. expect((tree.getInstance() as any)._reactInternalInstance.child.child.Fibernode.key).toEqual('component1');
  112. });
  113. it('cleans props from store on unMount', () => {
  114. store.updateProps('component123', { foo: 'bar' });
  115. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  116. const tree = renderer.create(<NavigationComponent componentId={'component123'} />);
  117. expect(store.getPropsForId('component123')).toEqual({ foo: 'bar' });
  118. tree.unmount();
  119. expect(store.getPropsForId('component123')).toEqual({});
  120. });
  121. it('merges static members from wrapped component when generated', () => {
  122. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver) as any;
  123. expect(NavigationComponent.options).toEqual({ title: 'MyComponentTitle' });
  124. });
  125. it('calls unmounted on componentEventsObserver', () => {
  126. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  127. const tree = renderer.create(<NavigationComponent componentId={'component123'} />);
  128. verify(mockedComponentEventsObserver.unmounted('component123')).never();
  129. tree.unmount();
  130. verify(mockedComponentEventsObserver.unmounted('component123')).once();
  131. });
  132. it('renders HOC components correctly', () => {
  133. const generator = () => (props: any) => (
  134. <View>
  135. <MyComponent {...props}/>
  136. </View>
  137. );
  138. uut = new ComponentWrapper();
  139. const NavigationComponent = uut.wrap(componentName, generator, store, componentEventsObserver);
  140. const tree = renderer.create(<NavigationComponent componentId={'component123'} />);
  141. expect(tree.root.findByType(View)).toBeDefined()
  142. expect(tree.root.findByType(MyComponent).props).toEqual({componentId: 'component123'});
  143. });
  144. it('sets component instance in store when constructed', () => {
  145. const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
  146. renderer.create(<NavigationComponent componentId={'component1'} />);
  147. expect(store.getComponentInstance('component1')).toBeTruthy();
  148. });
  149. describe(`register with redux store`, () => {
  150. class MyReduxComp extends React.Component<any> {
  151. static options() {
  152. return { foo: 123 };
  153. }
  154. render() {
  155. return (
  156. <Text>{this.props.txt}</Text>
  157. );
  158. }
  159. }
  160. interface RootState {
  161. txt: string;
  162. }
  163. function mapStateToProps(state: RootState) {
  164. return {
  165. txt: state.txt
  166. };
  167. }
  168. const ConnectedComp = require('react-redux').connect(mapStateToProps)(MyReduxComp);
  169. const ReduxProvider = require('react-redux').Provider;
  170. const initialState: RootState = { txt: 'it just works' };
  171. const reduxStore = require('redux').createStore((state: RootState = initialState) => state);
  172. it(`wraps the component with a react-redux provider with passed store`, () => {
  173. const NavigationComponent = uut.wrap(componentName, () => ConnectedComp, store, componentEventsObserver, undefined, ReduxProvider, reduxStore);
  174. const tree = renderer.create(<NavigationComponent componentId={'theCompId'} />);
  175. expect(tree.toJSON()!.children).toEqual(['it just works']);
  176. expect((NavigationComponent as any).options()).toEqual({ foo: 123 });
  177. });
  178. });
  179. });