Browse Source

pushes, start of lifecycle

Daniel Zlotin 7 years ago
parent
commit
7f7a586a08

+ 2
- 2
ios/RNN.m View File

43
 
43
 
44
 -(void)registerForJsEvents
44
 -(void)registerForJsEvents
45
 {
45
 {
46
-	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onJavaScriptLoaded) name:RCTJavaScriptDidLoadNotification object:nil];
46
+	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onJavaScriptLoaded) name:RCTJavaScriptDidLoadNotification object:self.bridge];
47
 	
47
 	
48
 #pragma GCC diagnostic push
48
 #pragma GCC diagnostic push
49
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
49
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
50
-	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onJavaScriptDevReload) name:RCTReloadNotification object:nil];
50
+	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onJavaScriptDevReload) name:RCTReloadNotification object:self.bridge];
51
 #pragma GCC diagnostic pop
51
 #pragma GCC diagnostic pop
52
 }
52
 }
53
 
53
 

+ 3
- 67
ios/RNNControllerFactory.m View File

1
 
1
 
2
 #import "RNNControllerFactory.h"
2
 #import "RNNControllerFactory.h"
3
-
4
-#import "RNN.h"
5
-#import "RCTRootView.h"
6
-
7
-@interface RNNLayoutNode : NSObject
8
-@property NSString* type;
9
-@property NSString* nodeId;
10
-@property NSDictionary* data;
11
-@property NSArray* children;
12
-@end
13
-
14
-@implementation RNNLayoutNode
15
-
16
-+(instancetype)create:(NSDictionary *)json
17
-{
18
-	RNNLayoutNode* node = [RNNLayoutNode new];
19
-	node.type = json[@"type"];
20
-	node.nodeId = json[@"id"];
21
-	node.data = json[@"data"];
22
-	node.children = json[@"children"];
23
-	return node;
24
-}
25
-
26
--(BOOL)isContainer
27
-{
28
-	return [self.type isEqualToString:@"Container"];
29
-}
30
-
31
--(BOOL)isContainerStack
32
-{
33
-	return [self.type isEqualToString:@"ContainerStack"];
34
-}
35
-
36
--(BOOL)isTabs
37
-{
38
-	return [self.type isEqualToString:@"Tabs"];
39
-}
40
-
41
--(BOOL)isSideMenuRoot
42
-{
43
-	return [self.type isEqualToString:@"SideMenuRoot"];
44
-}
45
-
46
--(BOOL)isSideMenuLeft
47
-{
48
-	return [self.type isEqualToString:@"SideMenuLeft"];
49
-}
50
-
51
--(BOOL)isSideMenuRight
52
-{
53
-	return [self.type isEqualToString:@"SideMenuRight"];
54
-}
55
-
56
--(BOOL)isSideMenuCenter
57
-{
58
-	return [self.type isEqualToString:@"SideMenuCenter"];
59
-}
60
-@end
3
+#import "RNNLayoutNode.h"
4
+#import "RNNRootViewController.h"
61
 
5
 
62
 @implementation RNNControllerFactory
6
 @implementation RNNControllerFactory
63
 
7
 
86
 
30
 
87
 -(UIViewController*)createContainer:(RNNLayoutNode*)node
31
 -(UIViewController*)createContainer:(RNNLayoutNode*)node
88
 {
32
 {
89
-	NSString* containerName = node.data[@"name"];
90
-	
91
-	RCTRootView *reactView = [[RCTRootView alloc] initWithBridge:RNN.instance.bridge
92
-													  moduleName:containerName
93
-											   initialProperties:@{@"id": node.nodeId}];
94
-	
95
-	UIViewController* controller = [UIViewController new];
96
-	controller.view = reactView;
97
-	return controller;
33
+	return [[RNNRootViewController alloc]initWithNode:node];
98
 }
34
 }
99
 
35
 
100
 -(UINavigationController*)createContainerStack:(RNNLayoutNode*)node
36
 -(UINavigationController*)createContainerStack:(RNNLayoutNode*)node

+ 22
- 0
ios/RNNLayoutNode.h View File

1
+
2
+#import <Foundation/Foundation.h>
3
+#import <UIKit/UIKit.h>
4
+
5
+@interface RNNLayoutNode : NSObject
6
+
7
+@property NSString* type;
8
+@property NSString* nodeId;
9
+@property NSDictionary* data;
10
+@property NSArray* children;
11
+
12
++(instancetype)create:(NSDictionary *)json;
13
+
14
+-(BOOL)isContainer;
15
+-(BOOL)isContainerStack;
16
+-(BOOL)isTabs;
17
+-(BOOL)isSideMenuRoot;
18
+-(BOOL)isSideMenuLeft;
19
+-(BOOL)isSideMenuRight;
20
+-(BOOL)isSideMenuCenter;
21
+
22
+@end

+ 45
- 0
ios/RNNLayoutNode.m View File

1
+
2
+#import "RNNLayoutNode.h"
3
+
4
+@implementation RNNLayoutNode
5
+
6
++(instancetype)create:(NSDictionary *)json
7
+{
8
+	RNNLayoutNode* node = [RNNLayoutNode new];
9
+	node.type = json[@"type"];
10
+	node.nodeId = json[@"id"];
11
+	node.data = json[@"data"];
12
+	node.children = json[@"children"];
13
+	return node;
14
+}
15
+
16
+-(BOOL)isContainer
17
+{
18
+	return [self.type isEqualToString:@"Container"];
19
+}
20
+-(BOOL)isContainerStack
21
+{
22
+	return [self.type isEqualToString:@"ContainerStack"];
23
+}
24
+-(BOOL)isTabs
25
+{
26
+	return [self.type isEqualToString:@"Tabs"];
27
+}
28
+-(BOOL)isSideMenuRoot
29
+{
30
+	return [self.type isEqualToString:@"SideMenuRoot"];
31
+}
32
+-(BOOL)isSideMenuLeft
33
+{
34
+	return [self.type isEqualToString:@"SideMenuLeft"];
35
+}
36
+-(BOOL)isSideMenuRight
37
+{
38
+	return [self.type isEqualToString:@"SideMenuRight"];
39
+}
40
+-(BOOL)isSideMenuCenter
41
+{
42
+	return [self.type isEqualToString:@"SideMenuCenter"];
43
+}
44
+
45
+@end

+ 10
- 0
ios/RNNRootViewController.h View File

1
+
2
+#import <Foundation/Foundation.h>
3
+#import <UIKit/UIKit.h>
4
+#import "RNNLayoutNode.h"
5
+
6
+@interface RNNRootViewController : UIViewController
7
+
8
+-(instancetype)initWithNode:(RNNLayoutNode*)node;
9
+
10
+@end

+ 34
- 0
ios/RNNRootViewController.m View File

1
+
2
+#import "RNNRootViewController.h"
3
+#import "RCTRootView.h"
4
+#import "RNN.h"
5
+
6
+@interface RNNRootViewController()
7
+@end
8
+
9
+@implementation RNNRootViewController
10
+
11
+-(instancetype)initWithNode:(RNNLayoutNode*)node
12
+{
13
+	self = [super init];
14
+	NSString* containerName = node.data[@"name"];
15
+	
16
+	self.view = [[RCTRootView alloc] initWithBridge:RNN.instance.bridge
17
+													  moduleName:containerName
18
+											   initialProperties:@{@"id": node.nodeId}];
19
+	return self;
20
+}
21
+
22
+-(void)viewDidAppear:(BOOL)animated
23
+{
24
+	[super viewDidAppear:animated];
25
+	//send the event onAppear
26
+}
27
+
28
+-(void)viewDidDisappear:(BOOL)animated
29
+{
30
+	[super viewDidDisappear:animated];
31
+	//send the event onDisappear
32
+}
33
+
34
+@end

+ 16
- 0
ios/ReactNativeNavigation.xcodeproj/project.pbxproj View File

19
 		7BBFE5441E25330E002A6182 /* RNNBridgeModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BBFE5431E25330E002A6182 /* RNNBridgeModule.m */; };
19
 		7BBFE5441E25330E002A6182 /* RNNBridgeModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BBFE5431E25330E002A6182 /* RNNBridgeModule.m */; };
20
 		7BBFE5611E253F97002A6182 /* RNN.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BBFE5601E253F97002A6182 /* RNN.m */; };
20
 		7BBFE5611E253F97002A6182 /* RNN.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BBFE5601E253F97002A6182 /* RNN.m */; };
21
 		7BC9346E1E26886E00EFA125 /* RNNControllerFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BC9346D1E26886E00EFA125 /* RNNControllerFactory.m */; };
21
 		7BC9346E1E26886E00EFA125 /* RNNControllerFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BC9346D1E26886E00EFA125 /* RNNControllerFactory.m */; };
22
+		7BEF0D181E437684003E96B0 /* RNNRootViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BEF0D161E437684003E96B0 /* RNNRootViewController.h */; };
23
+		7BEF0D191E437684003E96B0 /* RNNRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BEF0D171E437684003E96B0 /* RNNRootViewController.m */; };
24
+		7BEF0D1C1E43771B003E96B0 /* RNNLayoutNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BEF0D1A1E43771B003E96B0 /* RNNLayoutNode.h */; };
25
+		7BEF0D1D1E43771B003E96B0 /* RNNLayoutNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */; };
22
 /* End PBXBuildFile section */
26
 /* End PBXBuildFile section */
23
 
27
 
24
 /* Begin PBXCopyFilesBuildPhase section */
28
 /* Begin PBXCopyFilesBuildPhase section */
46
 		7BBFE5601E253F97002A6182 /* RNN.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNN.m; sourceTree = "<group>"; };
50
 		7BBFE5601E253F97002A6182 /* RNN.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNN.m; sourceTree = "<group>"; };
47
 		7BC9346C1E26886E00EFA125 /* RNNControllerFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNControllerFactory.h; sourceTree = "<group>"; };
51
 		7BC9346C1E26886E00EFA125 /* RNNControllerFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNControllerFactory.h; sourceTree = "<group>"; };
48
 		7BC9346D1E26886E00EFA125 /* RNNControllerFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNControllerFactory.m; sourceTree = "<group>"; };
52
 		7BC9346D1E26886E00EFA125 /* RNNControllerFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNControllerFactory.m; sourceTree = "<group>"; };
53
+		7BEF0D161E437684003E96B0 /* RNNRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNRootViewController.h; sourceTree = "<group>"; };
54
+		7BEF0D171E437684003E96B0 /* RNNRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNRootViewController.m; sourceTree = "<group>"; };
55
+		7BEF0D1A1E43771B003E96B0 /* RNNLayoutNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNLayoutNode.h; sourceTree = "<group>"; };
56
+		7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNLayoutNode.m; sourceTree = "<group>"; };
49
 		D8AFADBD1BEE6F3F00A4592D /* libReactNativeNavigation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativeNavigation.a; sourceTree = BUILT_PRODUCTS_DIR; };
57
 		D8AFADBD1BEE6F3F00A4592D /* libReactNativeNavigation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativeNavigation.a; sourceTree = BUILT_PRODUCTS_DIR; };
50
 /* End PBXFileReference section */
58
 /* End PBXFileReference section */
51
 
59
 
65
 			children = (
73
 			children = (
66
 				7BA500761E254908001B9E1B /* RNNSplashScreen.h */,
74
 				7BA500761E254908001B9E1B /* RNNSplashScreen.h */,
67
 				7BA500771E254908001B9E1B /* RNNSplashScreen.m */,
75
 				7BA500771E254908001B9E1B /* RNNSplashScreen.m */,
76
+				7BEF0D1A1E43771B003E96B0 /* RNNLayoutNode.h */,
77
+				7BEF0D1B1E43771B003E96B0 /* RNNLayoutNode.m */,
68
 				7BC9346C1E26886E00EFA125 /* RNNControllerFactory.h */,
78
 				7BC9346C1E26886E00EFA125 /* RNNControllerFactory.h */,
69
 				7BC9346D1E26886E00EFA125 /* RNNControllerFactory.m */,
79
 				7BC9346D1E26886E00EFA125 /* RNNControllerFactory.m */,
80
+				7BEF0D161E437684003E96B0 /* RNNRootViewController.h */,
81
+				7BEF0D171E437684003E96B0 /* RNNRootViewController.m */,
70
 			);
82
 			);
71
 			name = Controllers;
83
 			name = Controllers;
72
 			sourceTree = "<group>";
84
 			sourceTree = "<group>";
116
 				7B1126A41E2D2B6C00F9B03B /* ReactNativeNavigation.h in Headers */,
128
 				7B1126A41E2D2B6C00F9B03B /* ReactNativeNavigation.h in Headers */,
117
 				7B1126A31E2D2B6C00F9B03B /* RNNSplashScreen.h in Headers */,
129
 				7B1126A31E2D2B6C00F9B03B /* RNNSplashScreen.h in Headers */,
118
 				7B1126A51E2D2B6C00F9B03B /* RNN.h in Headers */,
130
 				7B1126A51E2D2B6C00F9B03B /* RNN.h in Headers */,
131
+				7BEF0D181E437684003E96B0 /* RNNRootViewController.h in Headers */,
119
 				7B1126A61E2D2B6C00F9B03B /* RNNBridgeModule.h in Headers */,
132
 				7B1126A61E2D2B6C00F9B03B /* RNNBridgeModule.h in Headers */,
120
 				7B1126A71E2D2B6C00F9B03B /* RNNEventEmitter.h in Headers */,
133
 				7B1126A71E2D2B6C00F9B03B /* RNNEventEmitter.h in Headers */,
121
 				7B1126A91E2D2B6C00F9B03B /* RNNControllerFactory.h in Headers */,
134
 				7B1126A91E2D2B6C00F9B03B /* RNNControllerFactory.h in Headers */,
135
+				7BEF0D1C1E43771B003E96B0 /* RNNLayoutNode.h in Headers */,
122
 			);
136
 			);
123
 			runOnlyForDeploymentPostprocessing = 0;
137
 			runOnlyForDeploymentPostprocessing = 0;
124
 		};
138
 		};
179
 			isa = PBXSourcesBuildPhase;
193
 			isa = PBXSourcesBuildPhase;
180
 			buildActionMask = 2147483647;
194
 			buildActionMask = 2147483647;
181
 			files = (
195
 			files = (
196
+				7BEF0D191E437684003E96B0 /* RNNRootViewController.m in Sources */,
182
 				7B1126A01E2D263F00F9B03B /* RNNEventEmitter.m in Sources */,
197
 				7B1126A01E2D263F00F9B03B /* RNNEventEmitter.m in Sources */,
183
 				7BA500751E2544B9001B9E1B /* ReactNativeNavigation.m in Sources */,
198
 				7BA500751E2544B9001B9E1B /* ReactNativeNavigation.m in Sources */,
184
 				7BBFE5441E25330E002A6182 /* RNNBridgeModule.m in Sources */,
199
 				7BBFE5441E25330E002A6182 /* RNNBridgeModule.m in Sources */,
200
+				7BEF0D1D1E43771B003E96B0 /* RNNLayoutNode.m in Sources */,
185
 				7BA500781E254908001B9E1B /* RNNSplashScreen.m in Sources */,
201
 				7BA500781E254908001B9E1B /* RNNSplashScreen.m in Sources */,
186
 				7BBFE5611E253F97002A6182 /* RNN.m in Sources */,
202
 				7BBFE5611E253F97002A6182 /* RNN.m in Sources */,
187
 				7BC9346E1E26886E00EFA125 /* RNNControllerFactory.m in Sources */,
203
 				7BC9346E1E26886E00EFA125 /* RNNControllerFactory.m in Sources */,

+ 5
- 0
playground/e2e/app.test.js View File

23
     elementByLabel('Switch to tab based app with side menus').swipeRight();
23
     elementByLabel('Switch to tab based app with side menus').swipeRight();
24
     expect(elementByLabel('This is a side menu screen')).toBeVisible();
24
     expect(elementByLabel('This is a side menu screen')).toBeVisible();
25
   });
25
   });
26
+
27
+  xit('screen lifecycle', () => {
28
+    elementByLabel('Switch to lifecycle screen').tap();
29
+    expect(elementByLabel('Appeared!')).toBeVisible();
30
+  });
26
 });
31
 });
27
 
32
 
28
 function elementByLabel(label) {
33
 function elementByLabel(label) {

+ 42
- 0
playground/src/containers/LifecycleScreen.js View File

1
+import React, { Component } from 'react';
2
+import { View, Text } from 'react-native';
3
+
4
+class LifecycleScreen extends Component {
5
+  constructor(props) {
6
+    super(props);
7
+    this.state = {
8
+      text: 'nothing yet'
9
+    };
10
+  }
11
+
12
+  onAppear() {
13
+    this.setState({ text: 'Appeared!' });
14
+  }
15
+
16
+  onDisappear() {
17
+    this.setState({ text: 'Disappeared!' });
18
+  }
19
+
20
+  render() {
21
+    return (
22
+      <View style={styles.root}>
23
+        <Text style={styles.h1}>{this.state.text}</Text>
24
+      </View>
25
+    );
26
+  }
27
+}
28
+export default LifecycleScreen;
29
+
30
+const styles = {
31
+  root: {
32
+    flexGrow: 1,
33
+    justifyContent: 'center',
34
+    alignItems: 'center',
35
+    backgroundColor: '#f5fcff'
36
+  },
37
+  h1: {
38
+    fontSize: 24,
39
+    textAlign: 'center',
40
+    margin: 10
41
+  }
42
+};

+ 7
- 0
playground/src/containers/WelcomeScreen.js View File

15
         <Text style={styles.h1}>{`React Native Navigation!`}</Text>
15
         <Text style={styles.h1}>{`React Native Navigation!`}</Text>
16
         <Button title="Switch to tab based app" onPress={this.onClickSwitchToTabs} />
16
         <Button title="Switch to tab based app" onPress={this.onClickSwitchToTabs} />
17
         <Button title="Switch to app with side menus" onPress={this.onClickSwitchToSideMenus} />
17
         <Button title="Switch to app with side menus" onPress={this.onClickSwitchToSideMenus} />
18
+        <Button title="Switch to lifecycle screen" onPress={this.onClickLifecycleScreen} />
18
         <Button title="Push" onPress={this.onClickPush} />
19
         <Button title="Push" onPress={this.onClickPush} />
19
         <Text style={styles.footer}>{`this.props.id = ${this.props.id}`}</Text>
20
         <Text style={styles.footer}>{`this.props.id = ${this.props.id}`}</Text>
20
       </View>
21
       </View>
87
       }
88
       }
88
     });
89
     });
89
   }
90
   }
91
+
92
+  onClickLifecycleScreen() {
93
+    Navigation.on(this.props.id).push({
94
+      name: 'com.example.LifecycleScreen'
95
+    });
96
+  }
90
 }
97
 }
91
 
98
 
92
 export default WelcomeScreen;
99
 export default WelcomeScreen;

+ 2
- 0
playground/src/containers/index.js View File

2
 
2
 
3
 import WelcomeScreen from './WelcomeScreen';
3
 import WelcomeScreen from './WelcomeScreen';
4
 import SimpleScreen from './SimpleScreen';
4
 import SimpleScreen from './SimpleScreen';
5
+import LifecycleScreen from './LifecycleScreen';
5
 
6
 
6
 export function registerContainers() {
7
 export function registerContainers() {
7
   Navigation.registerContainer(`com.example.WelcomeScreen`, () => WelcomeScreen);
8
   Navigation.registerContainer(`com.example.WelcomeScreen`, () => WelcomeScreen);
8
   Navigation.registerContainer(`com.example.SimpleScreen`, () => SimpleScreen);
9
   Navigation.registerContainer(`com.example.SimpleScreen`, () => SimpleScreen);
10
+  Navigation.registerContainer(`com.example.LifecycleScreen`, () => LifecycleScreen);
9
 }
11
 }

+ 1
- 0
src/containers/ContainerWrapper.js View File

25
           <OriginalContainer
25
           <OriginalContainer
26
             {...this.state.allProps}
26
             {...this.state.allProps}
27
             id={this.state.id}
27
             id={this.state.id}
28
+            key={this.state.id}
28
           />
29
           />
29
         );
30
         );
30
       }
31
       }

+ 30
- 3
src/containers/ContainerWrapper.test.js View File

1
+/* eslint-disable consistent-this, react/no-multi-comp */
1
 import React, { Component } from 'react';
2
 import React, { Component } from 'react';
2
 import { AppRegistry, Text } from 'react-native';
3
 import { AppRegistry, Text } from 'react-native';
3
 import renderer from 'react-test-renderer';
4
 import renderer from 'react-test-renderer';
14
   class MyContainer extends Component {
15
   class MyContainer extends Component {
15
     constructor(props) {
16
     constructor(props) {
16
       super(props);
17
       super(props);
17
-      myContainerRef = this; //eslint-disable-line
18
+      myContainerRef = this;
18
     }
19
     }
19
 
20
 
20
     render() {
21
     render() {
22
     }
23
     }
23
   }
24
   }
24
 
25
 
25
-  class TestParent extends Component { //eslint-disable-line
26
+  class TestParent extends Component {
26
     constructor(props) {
27
     constructor(props) {
27
       super(props);
28
       super(props);
28
-      testParentRef = this; //eslint-disable-line
29
+      testParentRef = this;
29
       this.ChildClass = props.ChildClass;
30
       this.ChildClass = props.ChildClass;
30
       this.state = { propsFromState: {} };
31
       this.state = { propsFromState: {} };
31
     }
32
     }
96
     testParentRef.setState({ propsFromState: { id: 'ERROR' } });
97
     testParentRef.setState({ propsFromState: { id: 'ERROR' } });
97
     expect(myContainerRef.props.id).toEqual('container1');
98
     expect(myContainerRef.props.id).toEqual('container1');
98
   });
99
   });
100
+
101
+  it('assignes key by id', () => {
102
+    const NavigationContainer = ContainerWrapper.wrap(containerName, MyContainer, store);
103
+    renderer.create(<NavigationContainer id={'container123'} />);
104
+    expect(myContainerRef.props.id).toEqual('container123');
105
+    expect(myContainerRef._reactInternalInstance._currentElement.key).toEqual('container123');
106
+  });
107
+
108
+  xdescribe('container lifecycle', () => {
109
+    const onStartCallback = jest.fn();
110
+    const onStopCallback = jest.fn();
111
+
112
+    class MyLifecycleContainer extends MyContainer {
113
+      onStart() {
114
+        onStartCallback();
115
+      }
116
+
117
+      onStop() {
118
+        onStopCallback();
119
+      }
120
+    }
121
+
122
+    it('', () => {
123
+      //
124
+    });
125
+  });
99
 });
126
 });