Przeglądaj źródła

#1071 Add Android tests (#1489)

* #1071 Test that Navigator forwards NavigationOptions to ViewController

* Add an argument allowing to run a single Android e2e test

* Fix style issue

* #1071 Allow changing navigation title in iOS

* Update readme to document an option for running a single test

* Update ScreenStyleDynamic.test.js
Juozas Kontvainis 7 lat temu
rodzic
commit
969811ad6f

+ 1
- 1
CONTRIBUTING.md Wyświetl plik

@@ -72,7 +72,7 @@ brew tap facebook/fb && brew install fbsimctl
72 72
 | `yarn test-unit-ios` | runs ios unit tests in debug/release <br> **Options:** `-- release` |
73 73
 | `yarn test-unit-android` | runs android unit tests in debug/release <br> **Options:** `-- release` |
74 74
 | `yarn test-e2e-ios` | runs the ios e2e suite (with detox) in debug/release |
75
-| `yarn test-e2e-android` | runs the android e2e suite (with uiautomator) in debug/release on running devices/emulators <br> **Options:** `-- release` |
75
+| `yarn test-e2e-android` | runs the android e2e suite (with uiautomator) in debug/release on running devices/emulators <br> **Options:** `-- [release] [just com.TestClass#testMethod]` |
76 76
 | `yarn test-all` | runs all tests in parallel |
77 77
 
78 78
 ## Workflow

+ 15
- 0
e2e/ScreenStyleDynamic.test.js Wyświetl plik

@@ -0,0 +1,15 @@
1
+const Utils = require('./Utils');
2
+const elementByLabel = Utils.elementByLabel;
3
+
4
+describe('screen style - dynamic', () => {
5
+  beforeEach(async () => {
6
+    await device.relaunchApp();
7
+  });
8
+
9
+  it('change title on container component', async () => {
10
+    await elementByLabel('Push Options Screen').tap();
11
+    await expect(element(by.label('Static Title').and(by.type('UILabel')))).toBeVisible();
12
+    await elementByLabel('Dynamic Options').tap();
13
+    await expect(element(by.label('Dynamic Title').and(by.type('UILabel')))).toBeVisible();
14
+  });
15
+});

+ 5
- 0
lib/android/app/src/main/java/com/reactnativenavigation/layout/NavigationOptionsHolder.java Wyświetl plik

@@ -0,0 +1,5 @@
1
+package com.reactnativenavigation.layout;
2
+
3
+public interface NavigationOptionsHolder {
4
+	void mergeNavigationOptions(NavigationOptions options);
5
+}

+ 12
- 3
lib/android/app/src/main/java/com/reactnativenavigation/layout/ReactRootViewController.java Wyświetl plik

@@ -10,7 +10,7 @@ import com.facebook.react.ReactRootView;
10 10
 import com.reactnativenavigation.react.NavigationEvent;
11 11
 import com.reactnativenavigation.viewcontrollers.ViewController;
12 12
 
13
-public class ReactRootViewController extends ViewController {
13
+public class ReactRootViewController extends ViewController implements NavigationOptionsHolder {
14 14
 
15 15
 	private final String name;
16 16
 	private final NavigationOptions navigationOptions;
@@ -29,6 +29,11 @@ public class ReactRootViewController extends ViewController {
29 29
 		this.reactInstanceManager = reactInstanceManager;
30 30
 	}
31 31
 
32
+	public void mergeNavigationOptions(NavigationOptions options) {
33
+		navigationOptions.title = options.title;
34
+		applyNavigationOptions();
35
+	}
36
+
32 37
 	@Override
33 38
 	public void destroy() {
34 39
 		super.destroy();
@@ -39,8 +44,7 @@ public class ReactRootViewController extends ViewController {
39 44
 	@Override
40 45
 	public void onViewAppeared() {
41 46
 		super.onViewAppeared();
42
-		if (getParentStackController() != null)
43
-			getParentStackController().setTitle(navigationOptions.title);
47
+		applyNavigationOptions();
44 48
 		new NavigationEvent(reactInstanceManager.getCurrentReactContext()).containerStart(getId());
45 49
 	}
46 50
 
@@ -71,4 +75,9 @@ public class ReactRootViewController extends ViewController {
71 75
 		reactRootView.startReactApplication(this.reactInstanceManager, this.name, opts);
72 76
 		return reactRootView;
73 77
 	}
78
+
79
+	private void applyNavigationOptions() {
80
+		if (getParentStackController() != null)
81
+			getParentStackController().setTitle(navigationOptions.title);
82
+	}
74 83
 }

+ 5
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/Navigator.java Wyświetl plik

@@ -6,6 +6,7 @@ import android.view.ViewGroup;
6 6
 import android.widget.FrameLayout;
7 7
 
8 8
 import com.reactnativenavigation.layout.NavigationOptions;
9
+import com.reactnativenavigation.layout.NavigationOptionsHolder;
9 10
 import com.reactnativenavigation.utils.CompatUtils;
10 11
 
11 12
 import java.util.Collection;
@@ -26,6 +27,7 @@ public class Navigator extends ParentController {
26 27
 		return new FrameLayout(getActivity());
27 28
 	}
28 29
 
30
+	@NonNull
29 31
 	@Override
30 32
 	public Collection<ViewController> getChildControllers() {
31 33
 		return root == null ? Collections.<ViewController>emptyList() : Collections.singletonList(root);
@@ -57,7 +59,9 @@ public class Navigator extends ParentController {
57 59
 
58 60
 	public void setOptions(final String containerId, NavigationOptions options) {
59 61
 		ViewController target = findControllerById(containerId);
60
-		target.getParentStackController().setTitle(options.title);
62
+		if (target instanceof NavigationOptionsHolder) {
63
+			((NavigationOptionsHolder) target).mergeNavigationOptions(options);
64
+		}
61 65
 	}
62 66
 
63 67
 	public void push(final String fromId, final ViewController viewController) {

+ 11
- 1
lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleViewController.java Wyświetl plik

@@ -3,9 +3,14 @@ package com.reactnativenavigation.mocks;
3 3
 import android.app.Activity;
4 4
 import android.view.View;
5 5
 
6
+import com.reactnativenavigation.layout.NavigationOptions;
7
+import com.reactnativenavigation.layout.NavigationOptionsHolder;
6 8
 import com.reactnativenavigation.viewcontrollers.ViewController;
7 9
 
8
-public class SimpleViewController extends ViewController {
10
+public class SimpleViewController extends ViewController implements NavigationOptionsHolder {
11
+
12
+	public NavigationOptions lastNavigationOptions;
13
+
9 14
 	public SimpleViewController(final Activity activity, String id) {
10 15
 		super(activity, id);
11 16
 	}
@@ -19,4 +24,9 @@ public class SimpleViewController extends ViewController {
19 24
 	public String toString() {
20 25
 		return "SimpleViewController " + getId();
21 26
 	}
27
+
28
+	@Override
29
+	public void mergeNavigationOptions(NavigationOptions options) {
30
+		lastNavigationOptions = options;
31
+	}
22 32
 }

+ 10
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java Wyświetl plik

@@ -4,6 +4,7 @@ import android.app.Activity;
4 4
 import android.support.annotation.NonNull;
5 5
 
6 6
 import com.reactnativenavigation.BaseTest;
7
+import com.reactnativenavigation.layout.NavigationOptions;
7 8
 import com.reactnativenavigation.mocks.SimpleViewController;
8 9
 import com.reactnativenavigation.mocks.TestStackAnimator;
9 10
 import com.reactnativenavigation.utils.CompatUtils;
@@ -21,7 +22,7 @@ import static org.mockito.Mockito.when;
21 22
 public class NavigatorTest extends BaseTest {
22 23
 	private Activity activity;
23 24
 	private Navigator uut;
24
-	private ViewController child1;
25
+	private SimpleViewController child1;
25 26
 	private ViewController child2;
26 27
 	private ViewController child3;
27 28
 	private ViewController child4;
@@ -187,6 +188,14 @@ public class NavigatorTest extends BaseTest {
187 188
 		verify(spy, times(1)).handleBack();
188 189
 	}
189 190
 
191
+	@Test
192
+	public void setOptions_CallsMergeNavigationOptions() {
193
+		uut.setRoot(child1);
194
+		NavigationOptions options = new NavigationOptions();
195
+		uut.setOptions(child1.getId(), options);
196
+		assertThat(child1.lastNavigationOptions).isEqualTo(options);
197
+	}
198
+
190 199
 	@NonNull
191 200
 	private BottomTabsController newTabs() {
192 201
 		return new BottomTabsController(activity, "tabsController");

+ 4
- 0
lib/ios/RNNBridgeModule.m Wyświetl plik

@@ -22,6 +22,10 @@ RCT_EXPORT_METHOD(setRoot:(NSDictionary*)layout) {
22 22
 	[_commandsHandler setRoot:layout];
23 23
 }
24 24
 
25
+RCT_EXPORT_METHOD(setOptions:(NSString*)containerId options:(NSDictionary*)options) {
26
+	[_commandsHandler setOptions:containerId options:options];
27
+}
28
+
25 29
 RCT_EXPORT_METHOD(push:(NSString*)containerId layout:(NSDictionary*)layout) {
26 30
 	[_commandsHandler push:containerId layout:layout];
27 31
 }

+ 2
- 0
lib/ios/RNNCommandsHandler.h Wyświetl plik

@@ -10,6 +10,8 @@
10 10
 
11 11
 -(void) setRoot:(NSDictionary*)layout;
12 12
 
13
+-(void) setOptions:(NSString*)containerId options:(NSDictionary*)options;
14
+
13 15
 -(void) push:(NSString*)containerId layout:(NSDictionary*)layout;
14 16
 
15 17
 -(void) pop:(NSString*)containerId;

+ 5
- 0
lib/ios/RNNCommandsHandler.m Wyświetl plik

@@ -33,6 +33,11 @@
33 33
 	[UIApplication.sharedApplication.delegate.window makeKeyAndVisible];
34 34
 }
35 35
 
36
+-(void) setOptions:(NSString*)containerId options:(NSDictionary*)options {
37
+	[self assertReady];
38
+	[_store findContainerForId:containerId].navigationItem.title = options[@"title"];
39
+}
40
+
36 41
 -(void) push:(NSString*)containerId layout:(NSDictionary*)layout {
37 42
 	[self assertReady];
38 43
 	UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];

+ 5
- 1
scripts/test.e2e.android.js Wyświetl plik

@@ -10,6 +10,9 @@ const packageName = `system-images;${sdk};${apis};${abi}`;
10 10
 
11 11
 const release = _.includes(process.argv, 'release');
12 12
 
13
+// Run just a single test, e.g. yarn test-e2e-android -- just com.MyClass#myMethod
14
+const filter = _(process.argv).dropWhile((a) => a !== 'just').take(2).last();
15
+
13 16
 run();
14 17
 
15 18
 function run() {
@@ -23,7 +26,8 @@ function run() {
23 26
 function runTests() {
24 27
   exec.execSync(`yarn run uninstall-android`);
25 28
   exec.execSync(`yarn run install-android ${release ? '-- release' : ''}`);
26
-  exec.execSync(`cd AndroidE2E && ./gradlew connectedDebugAndroidTest`);
29
+  const filterParam = filter ? '-Pandroid.testInstrumentationRunnerArguments.class=' + filter : '';
30
+  exec.execSync(`cd AndroidE2E && ./gradlew ${filterParam} connectedDebugAndroidTest`);
27 31
 }
28 32
 
29 33
 function installEmulator() {