Browse Source

#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 years ago
parent
commit
969811ad6f

+ 1
- 1
CONTRIBUTING.md View File

72
 | `yarn test-unit-ios` | runs ios unit tests in debug/release <br> **Options:** `-- release` |
72
 | `yarn test-unit-ios` | runs ios unit tests in debug/release <br> **Options:** `-- release` |
73
 | `yarn test-unit-android` | runs android unit tests in debug/release <br> **Options:** `-- release` |
73
 | `yarn test-unit-android` | runs android unit tests in debug/release <br> **Options:** `-- release` |
74
 | `yarn test-e2e-ios` | runs the ios e2e suite (with detox) in debug/release |
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
 | `yarn test-all` | runs all tests in parallel |
76
 | `yarn test-all` | runs all tests in parallel |
77
 
77
 
78
 ## Workflow
78
 ## Workflow

+ 15
- 0
e2e/ScreenStyleDynamic.test.js View File

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 View File

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 View File

10
 import com.reactnativenavigation.react.NavigationEvent;
10
 import com.reactnativenavigation.react.NavigationEvent;
11
 import com.reactnativenavigation.viewcontrollers.ViewController;
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
 	private final String name;
15
 	private final String name;
16
 	private final NavigationOptions navigationOptions;
16
 	private final NavigationOptions navigationOptions;
29
 		this.reactInstanceManager = reactInstanceManager;
29
 		this.reactInstanceManager = reactInstanceManager;
30
 	}
30
 	}
31
 
31
 
32
+	public void mergeNavigationOptions(NavigationOptions options) {
33
+		navigationOptions.title = options.title;
34
+		applyNavigationOptions();
35
+	}
36
+
32
 	@Override
37
 	@Override
33
 	public void destroy() {
38
 	public void destroy() {
34
 		super.destroy();
39
 		super.destroy();
39
 	@Override
44
 	@Override
40
 	public void onViewAppeared() {
45
 	public void onViewAppeared() {
41
 		super.onViewAppeared();
46
 		super.onViewAppeared();
42
-		if (getParentStackController() != null)
43
-			getParentStackController().setTitle(navigationOptions.title);
47
+		applyNavigationOptions();
44
 		new NavigationEvent(reactInstanceManager.getCurrentReactContext()).containerStart(getId());
48
 		new NavigationEvent(reactInstanceManager.getCurrentReactContext()).containerStart(getId());
45
 	}
49
 	}
46
 
50
 
71
 		reactRootView.startReactApplication(this.reactInstanceManager, this.name, opts);
75
 		reactRootView.startReactApplication(this.reactInstanceManager, this.name, opts);
72
 		return reactRootView;
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 View File

6
 import android.widget.FrameLayout;
6
 import android.widget.FrameLayout;
7
 
7
 
8
 import com.reactnativenavigation.layout.NavigationOptions;
8
 import com.reactnativenavigation.layout.NavigationOptions;
9
+import com.reactnativenavigation.layout.NavigationOptionsHolder;
9
 import com.reactnativenavigation.utils.CompatUtils;
10
 import com.reactnativenavigation.utils.CompatUtils;
10
 
11
 
11
 import java.util.Collection;
12
 import java.util.Collection;
26
 		return new FrameLayout(getActivity());
27
 		return new FrameLayout(getActivity());
27
 	}
28
 	}
28
 
29
 
30
+	@NonNull
29
 	@Override
31
 	@Override
30
 	public Collection<ViewController> getChildControllers() {
32
 	public Collection<ViewController> getChildControllers() {
31
 		return root == null ? Collections.<ViewController>emptyList() : Collections.singletonList(root);
33
 		return root == null ? Collections.<ViewController>emptyList() : Collections.singletonList(root);
57
 
59
 
58
 	public void setOptions(final String containerId, NavigationOptions options) {
60
 	public void setOptions(final String containerId, NavigationOptions options) {
59
 		ViewController target = findControllerById(containerId);
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
 	public void push(final String fromId, final ViewController viewController) {
67
 	public void push(final String fromId, final ViewController viewController) {

+ 11
- 1
lib/android/app/src/test/java/com/reactnativenavigation/mocks/SimpleViewController.java View File

3
 import android.app.Activity;
3
 import android.app.Activity;
4
 import android.view.View;
4
 import android.view.View;
5
 
5
 
6
+import com.reactnativenavigation.layout.NavigationOptions;
7
+import com.reactnativenavigation.layout.NavigationOptionsHolder;
6
 import com.reactnativenavigation.viewcontrollers.ViewController;
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
 	public SimpleViewController(final Activity activity, String id) {
14
 	public SimpleViewController(final Activity activity, String id) {
10
 		super(activity, id);
15
 		super(activity, id);
11
 	}
16
 	}
19
 	public String toString() {
24
 	public String toString() {
20
 		return "SimpleViewController " + getId();
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 View File

4
 import android.support.annotation.NonNull;
4
 import android.support.annotation.NonNull;
5
 
5
 
6
 import com.reactnativenavigation.BaseTest;
6
 import com.reactnativenavigation.BaseTest;
7
+import com.reactnativenavigation.layout.NavigationOptions;
7
 import com.reactnativenavigation.mocks.SimpleViewController;
8
 import com.reactnativenavigation.mocks.SimpleViewController;
8
 import com.reactnativenavigation.mocks.TestStackAnimator;
9
 import com.reactnativenavigation.mocks.TestStackAnimator;
9
 import com.reactnativenavigation.utils.CompatUtils;
10
 import com.reactnativenavigation.utils.CompatUtils;
21
 public class NavigatorTest extends BaseTest {
22
 public class NavigatorTest extends BaseTest {
22
 	private Activity activity;
23
 	private Activity activity;
23
 	private Navigator uut;
24
 	private Navigator uut;
24
-	private ViewController child1;
25
+	private SimpleViewController child1;
25
 	private ViewController child2;
26
 	private ViewController child2;
26
 	private ViewController child3;
27
 	private ViewController child3;
27
 	private ViewController child4;
28
 	private ViewController child4;
187
 		verify(spy, times(1)).handleBack();
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
 	@NonNull
199
 	@NonNull
191
 	private BottomTabsController newTabs() {
200
 	private BottomTabsController newTabs() {
192
 		return new BottomTabsController(activity, "tabsController");
201
 		return new BottomTabsController(activity, "tabsController");

+ 4
- 0
lib/ios/RNNBridgeModule.m View File

22
 	[_commandsHandler setRoot:layout];
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
 RCT_EXPORT_METHOD(push:(NSString*)containerId layout:(NSDictionary*)layout) {
29
 RCT_EXPORT_METHOD(push:(NSString*)containerId layout:(NSDictionary*)layout) {
26
 	[_commandsHandler push:containerId layout:layout];
30
 	[_commandsHandler push:containerId layout:layout];
27
 }
31
 }

+ 2
- 0
lib/ios/RNNCommandsHandler.h View File

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

+ 5
- 0
lib/ios/RNNCommandsHandler.m View File

33
 	[UIApplication.sharedApplication.delegate.window makeKeyAndVisible];
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
 -(void) push:(NSString*)containerId layout:(NSDictionary*)layout {
41
 -(void) push:(NSString*)containerId layout:(NSDictionary*)layout {
37
 	[self assertReady];
42
 	[self assertReady];
38
 	UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];
43
 	UIViewController *newVc = [_controllerFactory createLayoutAndSaveToStore:layout];

+ 5
- 1
scripts/test.e2e.android.js View File

10
 
10
 
11
 const release = _.includes(process.argv, 'release');
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
 run();
16
 run();
14
 
17
 
15
 function run() {
18
 function run() {
23
 function runTests() {
26
 function runTests() {
24
   exec.execSync(`yarn run uninstall-android`);
27
   exec.execSync(`yarn run uninstall-android`);
25
   exec.execSync(`yarn run install-android ${release ? '-- release' : ''}`);
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
 function installEmulator() {
33
 function installEmulator() {