Skip to content

Commit 12faae3

Browse files
authored
✨ Adds UI tests for Android & iOS (#88)
1 parent e54fe35 commit 12faae3

File tree

15 files changed

+658
-37
lines changed

15 files changed

+658
-37
lines changed

.circleci/config.yml

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,81 @@
11
version: 2
22
jobs:
3-
build:
4-
docker:
5-
- image: cirrusci/flutter
6-
steps:
7-
- checkout
8-
- run: bundle check || sudo bundle install
9-
- run: bundle exec danger
10-
- run: flutter doctor
11-
- run: pub get
12-
- run: flutter test --coverage
13-
- run: bash <(curl -s https://codecov.io/bash)
14-
- run: dartanalyzer --options analysis_options.yaml --fatal-warnings lib
15-
android_test:
3+
android_tests:
164
working_directory: ~/project/example/android
17-
docker:
18-
- image: cirrusci/flutter
5+
macos:
6+
xcode: "9.4.0"
197
environment:
208
JVM_OPTS: -Xmx3200m
219
steps:
2210
- checkout:
2311
path: ~/project
2412
- restore_cache:
25-
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
26-
- run: flutter doctor
27-
- run:
28-
name: Flutter build
29-
command: cd ..; flutter build aot
13+
keys:
14+
- android_cache
15+
- run:
16+
name: Setup environment variables
17+
command: |
18+
echo 'export PATH="$PATH:/usr/local/opt/node@8/bin:${HOME}/.yarn/bin:${HOME}/${CIRCLE_PROJECT_REPONAME}/node_modules/.bin:/usr/local/share/android-sdk/tools/bin"' >> $BASH_ENV
19+
echo 'export ANDROID_HOME="/usr/local/share/android-sdk"' >> $BASH_ENV
20+
echo 'export ANDROID_SDK_HOME="/usr/local/share/android-sdk"' >> $BASH_ENV
21+
echo 'export ANDROID_SDK_ROOT="/usr/local/share/android-sdk"' >> $BASH_ENV
22+
echo 'export QEMU_AUDIO_DRV=none' >> $BASH_ENV
23+
echo 'export JAVA_HOME=/Library/Java/Home' >> $BASH_ENV
24+
echo 'export PATH="$PATH:`pwd`/flutter/bin"' >> $BASH_ENV
25+
- run:
26+
name: Install Android sdk
27+
command: |
28+
HOMEBREW_NO_AUTO_UPDATE=1 brew tap homebrew/cask
29+
HOMEBREW_NO_AUTO_UPDATE=1 brew cask install android-sdk
30+
- run:
31+
name: Install emulator dependencies
32+
command: (yes | sdkmanager "platform-tools" "platforms;android-26" "extras;intel;Hardware_Accelerated_Execution_Manager" "build-tools;26.0.0" "system-images;android-26;google_apis;x86" "emulator" --verbose) || true
33+
- run:
34+
name: download flutter SDK
35+
command: if ! test -f "flutter_sdk.zip"; then curl -o flutter_sdk.zip https://storage.googleapis.com/flutter_infra/releases/stable/macos/flutter_macos_v1.5.4-hotfix.2-stable.zip; fi
36+
- run:
37+
name: unzip flutter SDK
38+
command: unzip flutter_sdk.zip
3039
- run:
3140
name: chmod permissions
3241
command: chmod +x ./gradlew
42+
- run: avdmanager create avd -n Pixel_2_API_26 -k "system-images;android-26;google_apis;x86" -g google_apis -d "Nexus 5"
3343
- run:
34-
name: Download Dependencies
44+
name: Run emulator in background
45+
command: /usr/local/share/android-sdk/tools/emulator @Pixel_2_API_26 -noaudio -no-boot-anim -no-window
46+
background: true
47+
- run:
48+
name: Flutter build
49+
command: cd ..; flutter build aot
50+
- run:
51+
name: Download Android Dependencies
3552
command: ./gradlew androidDependencies
53+
- run:
54+
name: Run UI Tests
55+
command: ./gradlew app:connectedAndroidTest
56+
- run:
57+
name: Run Unit Tests
58+
command: ./gradlew test
3659
- save_cache:
60+
key: android_cache
3761
paths:
3862
- ~/.gradle
39-
key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
40-
- run:
41-
name: Run UnitTest
42-
command: ./gradlew test
43-
ios_test:
63+
- flutter_sdk.zip
64+
65+
flutter_tests:
66+
docker:
67+
- image: cirrusci/flutter
68+
steps:
69+
- checkout
70+
- run: bundle check || sudo bundle install
71+
- run: bundle exec danger
72+
- run: flutter doctor
73+
- run: pub get
74+
- run: flutter test --coverage
75+
- run: bash <(curl -s https://codecov.io/bash)
76+
- run: dartanalyzer --options analysis_options.yaml --fatal-warnings lib
77+
78+
ios_tests:
4479
macos:
4580
xcode: "10.2.0"
4681
working_directory: ~/project/example/ios
@@ -79,6 +114,7 @@ jobs:
79114
paths:
80115
- flutter_sdk.zip
81116
- Pods
117+
82118
release:
83119
docker:
84120
- image: cirrusci/flutter
@@ -100,15 +136,15 @@ workflows:
100136
version: 2
101137
build-test-and-approval-deploy:
102138
jobs:
103-
- build
104-
- android_test
105-
- ios_test
139+
- flutter_tests
140+
- android_tests
141+
- ios_tests
106142
- hold:
107143
type: approval
108144
requires:
109-
- build
110-
- android_test
111-
- ios_test
145+
- flutter_tests
146+
- android_tests
147+
- ios_tests
112148
filters:
113149
branches:
114150
only: master

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,4 @@
7272
Adds the following APIs:
7373

7474
* start(String token, List<InvocationEvent> invocationEvents)
75-
* showWelcomeMessageWithMode(WelcomeMessageMode welcomeMessageMode)
75+
* showWelcomeMessageWithMode(WelcomeMessageMode welcomeMessageMode)

example/android/app/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ android {
4848
signingConfig signingConfigs.debug
4949
}
5050
}
51+
configurations.all {
52+
resolutionStrategy.force 'org.hamcrest:hamcrest-core:1.3'
53+
}
5154
}
5255

5356
flutter {
@@ -57,6 +60,7 @@ flutter {
5760
dependencies {
5861
testImplementation 'junit:junit:4.12'
5962
androidTestImplementation 'com.android.support.test:runner:1.0.2'
63+
androidTestImplementation 'com.android.support.test:rules:1.0.2'
6064
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
6165
testImplementation 'org.mockito:mockito-core:1.10.19'
6266
implementation 'org.mockito:mockito-core:1.10.19'
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.instabug.instabugflutterexample;
2+
3+
import android.support.test.rule.ActivityTestRule;
4+
import android.support.test.runner.AndroidJUnit4;
5+
6+
import org.junit.Rule;
7+
import org.junit.Test;
8+
import org.junit.runner.RunWith;
9+
10+
import java.lang.reflect.InvocationTargetException;
11+
import java.lang.reflect.Method;
12+
13+
import static android.support.test.espresso.Espresso.onView;
14+
import static android.support.test.espresso.action.ViewActions.click;
15+
import static android.support.test.espresso.action.ViewActions.replaceText;
16+
import static android.support.test.espresso.matcher.ViewMatchers.withResourceName;
17+
import static android.support.test.espresso.matcher.ViewMatchers.withText;
18+
19+
@RunWith(AndroidJUnit4.class)
20+
public class InvokeInstabugUITest {
21+
22+
@Rule
23+
public ActivityTestRule<MainActivity> mActivityRule =
24+
new ActivityTestRule<>(MainActivity.class);
25+
26+
@Test
27+
public void ensureInstabugInvocati1on() throws InterruptedException {
28+
disableScreenShotByMediaProjection();
29+
onView(withResourceName("instabug_floating_button")).perform(click());
30+
Thread.sleep(5000);
31+
onView(withText("Report a problem")).perform(click());
32+
Thread.sleep(5000);
33+
onView(withResourceName("instabug_edit_text_email")).perform(replaceText("[email protected]"));
34+
onView(withResourceName("instabug_bugreporting_send")).perform(click());
35+
onView(withResourceName("instabug_success_dialog_container")).perform(click());
36+
}
37+
38+
private void disableScreenShotByMediaProjection() {
39+
try {
40+
Method method = getMethod(Class.forName("com.instabug.bug.BugReporting"), "setScreenshotByMediaProjectionEnabled", boolean.class);
41+
if (method != null) {
42+
method.invoke(null, false);
43+
}
44+
} catch (ClassNotFoundException e) {
45+
e.printStackTrace();
46+
} catch (IllegalAccessException e) {
47+
e.printStackTrace();
48+
} catch (InvocationTargetException e) {
49+
e.printStackTrace();
50+
}
51+
}
52+
53+
public static Method getMethod(Class clazz, String methodName, Class... parameterType) {
54+
final Method[] methods = clazz.getDeclaredMethods();
55+
for (Method method : methods) {
56+
if (method.getName().equals(methodName) && method.getParameterTypes().length ==
57+
parameterType.length) {
58+
for (int i = 0; i < parameterType.length; i++) {
59+
if (method.getParameterTypes()[i] == parameterType[i]) {
60+
if (i == method.getParameterTypes().length - 1) {
61+
method.setAccessible(true);
62+
return method;
63+
}
64+
} else {
65+
break;
66+
}
67+
}
68+
}
69+
}
70+
return null;
71+
}
72+
}

example/android/app/src/main/java/com/instabug/instabugflutterexample/CustomFlutterApplication.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ public void onCreate() {
1111
super.onCreate();
1212
ArrayList<String> invocation_events = new ArrayList<>();
1313
invocation_events.add(InstabugFlutterPlugin.INVOCATION_EVENT_FLOATING_BUTTON);
14-
new InstabugFlutterPlugin().start(CustomFlutterApplication.this, "YOUR_TOKEN", invocation_events);
14+
InstabugFlutterPlugin instabug = new InstabugFlutterPlugin();
15+
instabug.start(CustomFlutterApplication.this, "efa41f402620b5654f2af2b86e387029", invocation_events);
16+
instabug.setWelcomeMessageMode("WelcomeMessageMode.disabled");
1517
}
1618
}

example/android/app/src/main/java/com/instabug/instabugflutterexample/MainActivity.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
public class MainActivity extends FlutterActivity {
88
@Override
99
protected void onCreate(Bundle savedInstanceState) {
10+
getIntent().putExtra("enable-software-rendering", true);
1011
super.onCreate(savedInstanceState);
1112
GeneratedPluginRegistrant.registerWith(this);
1213
}

example/ios/Podfile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,34 @@ target 'Runner' do
5959
}
6060
end
6161

62+
target 'instabug_flutter_exampleUITests' do
63+
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
64+
# referring to absolute paths on developers' machines.
65+
system('rm -rf .symlinks')
66+
system('mkdir -p .symlinks/plugins')
67+
68+
# Flutter Pods
69+
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
70+
if generated_xcode_build_settings.empty?
71+
puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
72+
end
73+
generated_xcode_build_settings.map { |p|
74+
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
75+
symlink = File.join('.symlinks', 'flutter')
76+
File.symlink(File.dirname(p[:path]), symlink)
77+
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
78+
end
79+
}
80+
81+
# Plugin Pods
82+
plugin_pods = parse_KV_file('../.flutter-plugins')
83+
plugin_pods.map { |p|
84+
symlink = File.join('.symlinks', 'plugins', p[:name])
85+
File.symlink(p[:path], symlink)
86+
pod p[:name], :path => File.join(symlink, 'ios')
87+
}
88+
end
89+
6290
post_install do |installer|
6391
installer.pods_project.targets.each do |target|
6492
target.build_configurations.each do |config|

0 commit comments

Comments
 (0)