Browse Source

container registry

Daniel Zlotin 7 years ago
parent
commit
a7b1ba640c
3 changed files with 101 additions and 66 deletions
  1. 11
    3
      src2/containers/ContainerRegistry.js
  2. 90
    62
      src2/containers/ContainerRegistry.test.js
  3. 0
    1
      src2/index.js

+ 11
- 3
src2/containers/ContainerRegistry.js View File

@@ -1,12 +1,19 @@
1 1
 import React, {Component} from 'react';
2 2
 import {AppRegistry} from 'react-native';
3
+import * as PropsStore from './PropsStore';
4
+import * as ContainerStore from './ContainerStore';
3 5
 
4 6
 export function registerContainer(containerKey, getContainerFunc) {
5 7
   const OriginalContainer = getContainerFunc();
6 8
   const NavigationContainer = wrapContainer(containerKey, OriginalContainer);
9
+  ContainerStore.saveContainerClass(containerKey, NavigationContainer);
7 10
   AppRegistry.registerComponent(containerKey, () => NavigationContainer);
8 11
 }
9 12
 
13
+export function getRegisteredContainer(containerKey) {
14
+  return ContainerStore.getContainerClass(containerKey);
15
+}
16
+
10 17
 function wrapContainer(containerKey, OriginalContainer) {
11 18
   return class extends Component {
12 19
     constructor(props) {
@@ -14,20 +21,21 @@ function wrapContainer(containerKey, OriginalContainer) {
14 21
       if (!props.screenId) {
15 22
         throw new Error(`Screen ${containerKey} does not have a screenId!`);
16 23
       }
24
+      this.screenId = props.screenId;
17 25
       this.state = {
18
-        allProps: {...props}
26
+        allProps: {...props, ...PropsStore.getPropsForScreenId(this.screenId)}
19 27
       };
20 28
     }
21 29
 
22 30
     componentWillReceiveProps(nextProps) {
23 31
       this.setState({
24
-        allProps: {...nextProps}
32
+        allProps: {...nextProps, ...PropsStore.getPropsForScreenId(this.screenId)}
25 33
       });
26 34
     }
27 35
 
28 36
     render() {
29 37
       return (
30
-        <OriginalContainer {...this.state.allProps}/>
38
+        <OriginalContainer {...this.state.allProps} screenId={this.screenId}/>
31 39
       );
32 40
     }
33 41
   };

+ 90
- 62
src2/containers/ContainerRegistry.test.js View File

@@ -2,97 +2,125 @@ import _ from 'lodash';
2 2
 import {AppRegistry, Text} from 'react-native';
3 3
 import React, {Component} from 'react';
4 4
 import renderer from 'react-test-renderer';
5
-import * as PropStore from './PropsStore';
6
-
7
-class MyContainer extends Component {
8
-  render() {
9
-    const txt = `Hello, ${_.get(this.props, 'name', 'World')}!`;
10
-    return (
11
-      <Text>{txt}</Text>
12
-    );
13
-  }
14
-}
15 5
 
16 6
 describe('ComponentRegistry', () => {
17 7
   let uut;
8
+  let myContainerRef;
9
+  let testParentRef;
18 10
 
19
-  beforeEach(() => {
20
-    AppRegistry.registerComponent = jest.fn(AppRegistry.registerComponent);
21
-    uut = require('./ContainerRegistry');
22
-  });
11
+  class MyContainer extends Component {
12
+    constructor(props) {
13
+      super(props);
14
+      myContainerRef = this; //eslint-disable-line
15
+    }
23 16
 
24
-  describe('registerContainer', () => {
25
-    function getRegisteredComponentClassFromAppRegistry() {
26
-      return AppRegistry.registerComponent.mock.calls[0][1]();
17
+    render() {
18
+      return <Text>{'Hello, World!'}</Text>;
27 19
     }
20
+  }
28 21
 
29
-    function renderRegisteredContainer(props) {
30
-      const Container = getRegisteredComponentClassFromAppRegistry();
31
-      return renderer.create(
32
-        <Container screenId="screen1" {...props}/>
22
+  class TestParent extends Component { //eslint-disable-line
23
+    constructor(props) {
24
+      super(props);
25
+      testParentRef = this; //eslint-disable-line
26
+      this.ChildClass = props.ChildClass;
27
+      this.state = {propsFromState: {}};
28
+    }
29
+
30
+    render() {
31
+      const Child = this.ChildClass;
32
+      return (
33
+        <Child screenId="screen1" {...this.state.propsFromState}/>
33 34
       );
34 35
     }
36
+  }
35 37
 
38
+  beforeEach(() => {
39
+    uut = require('./ContainerRegistry');
40
+  });
41
+
42
+  afterEach(() => {
43
+    myContainerRef = null;
44
+    testParentRef = null;
45
+  });
46
+
47
+  describe('registerContainer', () => {
36 48
     it('registers container component by containerKey into AppRegistry', () => {
49
+      AppRegistry.registerComponent = jest.fn(AppRegistry.registerComponent);
37 50
       expect(AppRegistry.registerComponent).not.toHaveBeenCalled();
38
-
39 51
       uut.registerContainer('example.MyContainer.key', () => MyContainer);
40
-
41 52
       expect(AppRegistry.registerComponent).toHaveBeenCalledTimes(1);
42 53
       expect(AppRegistry.registerComponent.mock.calls[0][0]).toEqual('example.MyContainer.key');
43 54
     });
44 55
 
45
-    it('wraps the container', () => {
46
-      uut.registerContainer('example.MyContainer', () => MyContainer);
47
-      const tree = renderRegisteredContainer();
56
+    it('resulting in a normal component', () => {
57
+      AppRegistry.registerComponent = jest.fn(AppRegistry.registerComponent);
58
+      uut.registerContainer('example.MyContainer.key', () => MyContainer);
59
+      const Container = AppRegistry.registerComponent.mock.calls[0][1]();
60
+      const tree = renderer.create(<Container screenId="123"/>);
48 61
       expect(tree.toJSON().children).toEqual(['Hello, World!']);
49 62
     });
63
+  });
50 64
 
51
-    it('passes props from wrapper into original container', () => {
52
-      uut.registerContainer('example.MyContainer', () => MyContainer);
53
-      const tree = renderRegisteredContainer({name: 'Daniel'});
54
-      expect(tree.toJSON().children).toEqual(['Hello, Daniel!']);
55
-    });
56
-
57
-    it('injects and updates props into original container', () => {
58
-      uut.registerContainer('example.MyContainer', () => MyContainer);
59
-
60
-      const NavigationContainer = getRegisteredComponentClassFromAppRegistry();
61
-      class TestParent extends Component { //eslint-disable-line
62
-        constructor(props) {
63
-          super(props);
64
-          this.state = {};
65
-        }
66
-
67
-        render() {
68
-          return (
69
-            <NavigationContainer screenId="screen1" name={this.state.name}/>
70
-          );
71
-        }
72
-      }
73
-
74
-      let testParentRef = null;
75
-      const tree = renderer.create(
76
-        <TestParent ref={(r) => testParentRef = r}/>
77
-      );
65
+  describe('wrapping NavigationContainer', () => {
66
+    const containerKey = 'example.MyContainer';
78 67
 
79
-      expect(tree.toJSON().children).toEqual(['Hello, World!']);
80
-      testParentRef.setState({name: 'Gandalf'});
81
-      expect(tree.toJSON().children).toEqual(['Hello, Gandalf!']);
68
+    beforeEach(() => {
69
+      uut.registerContainer(containerKey, () => MyContainer);
82 70
     });
83 71
 
84 72
     it('asserts has screenId as prop', () => {
85
-      uut.registerContainer('example.MyContainer.key', () => MyContainer);
86
-      const NavigationContainer = getRegisteredComponentClassFromAppRegistry();
73
+      const NavigationContainer = uut.getRegisteredContainer(containerKey);
87 74
       expect(() => {
88 75
         renderer.create(<NavigationContainer/>);
89
-      }).toThrow(new Error('Screen example.MyContainer.key does not have a screenId!'));
76
+      }).toThrow(new Error('Screen example.MyContainer does not have a screenId!'));
77
+    });
78
+
79
+    it('wraps the container and saves to store', () => {
80
+      const NavigationContainer = uut.getRegisteredContainer(containerKey);
81
+      const tree = renderer.create(<NavigationContainer screenId={'screen1'}/>);
82
+      expect(tree.toJSON().children).toEqual(['Hello, World!']);
83
+      expect(myContainerRef).toBeInstanceOf(MyContainer);
84
+    });
85
+
86
+    it('injects props from wrapper into original container', () => {
87
+      const NavigationContainer = uut.getRegisteredContainer(containerKey);
88
+      renderer.create(<NavigationContainer screenId={'screen1'} myProp={'yo'}/>);
89
+      expect(myContainerRef.props.myProp).toEqual('yo');
90
+    });
91
+
92
+    it('updates props from wrapper into original container', () => {
93
+      const NavigationContainer = uut.getRegisteredContainer(containerKey);
94
+      renderer.create(<TestParent ChildClass={NavigationContainer}/>);
95
+      expect(myContainerRef.props.foo).toEqual(undefined);
96
+      testParentRef.setState({propsFromState: {foo: 'yo'}});
97
+      expect(myContainerRef.props.foo).toEqual('yo');
90 98
     });
91 99
 
92 100
     it('pulls props from the PropsStore and injects them into the inner container', () => {
93
-      const props = {myProp: 1, otherProp: 'hello', yetAnotherProp: {a: 2}};
94
-      PropStore.setPropsForScreenId('my_screen_1', props);
95
-      // TODO
101
+      require('./PropsStore').setPropsForScreenId('screen123', {numberProp: 1, stringProp: 'hello', objectProp: {a: 2}});
102
+      const NavigationContainer = uut.getRegisteredContainer(containerKey);
103
+      renderer.create(<NavigationContainer screenId={'screen123'}/>);
104
+      expect(myContainerRef.props).toEqual({screenId: 'screen123', numberProp: 1, stringProp: 'hello', objectProp: {a: 2}});
105
+    });
106
+
107
+    it('updates props from PropsStore into inner container', () => {
108
+      const NavigationContainer = uut.getRegisteredContainer(containerKey);
109
+      renderer.create(<TestParent ChildClass={NavigationContainer}/>);
110
+      require('./PropsStore').setPropsForScreenId('screen1', {myProp: 'hello'});
111
+      expect(myContainerRef.props.foo).toEqual(undefined);
112
+      expect(myContainerRef.props.myProp).toEqual(undefined);
113
+      testParentRef.setState({propsFromState: {foo: 'yo'}});
114
+      expect(myContainerRef.props.foo).toEqual('yo');
115
+      expect(myContainerRef.props.myProp).toEqual('hello');
116
+    });
117
+
118
+    it('protects screenId from change', () => {
119
+      const NavigationContainer = uut.getRegisteredContainer(containerKey);
120
+      renderer.create(<TestParent ChildClass={NavigationContainer}/>);
121
+      expect(myContainerRef.props.screenId).toEqual('screen1');
122
+      testParentRef.setState({propsFromState: {screenId: 'ERROR'}});
123
+      expect(myContainerRef.props.screenId).toEqual('screen1');
96 124
     });
97 125
   });
98 126
 });

+ 0
- 1
src2/index.js View File

@@ -1 +0,0 @@
1
-