Skip to content

Commit bce9853

Browse files
hborisoffe7mac
andauthored
Add snapshot testing framework (#400)
* work in progress * work in progress - add ui test to travis * wip - fix webview crash on android 5.1.1 * wip - try fix sdcard issue * wip - try fix sdcard issue * try snapshotting * test verify task * travis - use new sdkmanager and avdmanager * new image for test, other fixes * verify with new image * broke snapshot test intentionally * remove unnecessary code * try to run unit tests while emulator is loading to reduce build time * add README.md and small change in travis * Little change in README * Add snapshot test for Rich Interstitial message * Increase snapshot WebView wait time * Add Interstitial and WebInterstitial snapshot tests Co-authored-by: Mayank Sanganeria <[email protected]>
1 parent 11641a6 commit bce9853

14 files changed

+429
-2
lines changed

.travis.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ env:
44
global:
55
- BUILD_API=29
66
- BUILD_TOOLS=29.0.3
7+
- ABI=x86
8+
- EMU_API=22
9+
- EMU_FLAVOR=default
710
- ANDROID_HOME=/usr/local/android-sdk
811
- TOOLS=${ANDROID_HOME}/tools
912
# PATH order is important, the 'emulator' script exists in more than one place
@@ -21,19 +24,29 @@ licenses:
2124
before_install:
2225
- sudo wget "https://bouncycastle.org/download/bcprov-ext-jdk15on-165.jar" -O "${JAVA_HOME}/jre/lib/ext/bcprov-ext-jdk15on-165.jar"
2326
- sudo echo "security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider" | sudo tee -a ${JAVA_HOME}/jre/lib/security/java.security
27+
- python -m pip install Pillow --user # library for image manipulation in snapshot tests
2428

2529
before_script:
26-
# Install Android SDK
30+
# Install Android SDK and run emulator
2731
- echo 'count=0' > /home/travis/.android/repositories.cfg # avoid harmless sdkmanager warning
2832
- echo y | sdkmanager "platform-tools" >/dev/null
2933
- echo y | sdkmanager "tools" >/dev/null
3034
- echo y | sdkmanager "build-tools;$BUILD_TOOLS" >/dev/null
35+
- echo y | sdkmanager "platforms;android-$EMU_API" >/dev/null
3136
- echo y | sdkmanager "platforms;android-$BUILD_API" >/dev/null
3237
- echo y | sdkmanager "extras;android;m2repository" >/dev/null
38+
- echo y | sdkmanager "system-images;android-$EMU_API;$EMU_FLAVOR;$ABI"
39+
- echo no | avdmanager create avd --force -n test -k "system-images;android-$EMU_API;$EMU_FLAVOR;$ABI" -c 100M
40+
- emulator -verbose -avd test -no-accel -no-snapshot -no-window -no-audio -camera-back none -camera-front none -selinux permissive -qemu -m 2048 &
3341

3442
script:
3543
- ./gradlew assembleRelease testReleaseUnitTest
3644

45+
# wait emulator to come alive and start snapshot tests
46+
- android-wait-for-emulator
47+
- adb shell input keyevent 82 &
48+
- ./gradlew verifyDebugAndroidTestScreenshotTest
49+
3750
before_deploy:
3851
- ./Tools/verifyTag.sh
3952
- ./gradlew assembleRelease generatePomFileForAarPublication

AndroidSDKTests/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
Snapshot testing
2+
------------
3+
4+
This file shows how to execute and record the snapshot tests (macOS).
5+
6+
Tool used for snapshot testing is [screenshot-tests-for-android](https://facebook.github.io/screenshot-tests-for-android/).
7+
8+
Prerequisites
9+
------------
10+
11+
#### Install Pillow (python library for images):
12+
13+
$ sudo -H python -m ensurepip
14+
$ python -m pip install Pillow --user
15+
16+
#### Install and run emulator:
17+
18+
$ $ANDROID_HOME/tools/bin/sdkmanager "system-images;android-22;default;x86"
19+
$ echo no | $ANDROID_HOME/tools/bin/avdmanager create avd --force -n test -k "system-images;android-22;default;x86" -c 100M
20+
$ $ANDROID_HOME/emulator/emulator -verbose -avd test -no-snapshot -no-audio -camera-back none -camera-front none -selinux permissive -qemu -m 2048 &
21+
22+
Usage
23+
------------
24+
#### Executing tests
25+
26+
$ ./gradlew verifyDebugAndroidTestScreenshotTest
27+
28+
If tests are failing compare snapshots:
29+
- your snapshots - AndroidSDKTests/build/screenshotsDebugAndroidTest
30+
- reference snapshots - AndroidSDKTests/screenshots
31+
32+
You could use [ImageMagick](https://imagemagick.org/).
33+
34+
$ brew install imagemagick
35+
$ magick left.png right.png difference.png
36+
37+
#### Recording tests
38+
39+
$ ./gradlew recordDebugAndroidTestScreenshotTest
40+
41+
Commit newly created PNG files located in AndroidSDKTests/screenshots.

AndroidSDKTests/build.gradle

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
apply plugin: 'com.android.application'
22
apply from: "../common-methods.gradle"
3+
apply plugin: 'com.facebook.testing.screenshot'
4+
5+
buildscript {
6+
repositories {
7+
mavenCentral()
8+
}
9+
dependencies {
10+
classpath 'com.facebook.testing.screenshot:plugin:0.12.0'
11+
}
12+
}
313

414
android {
515
compileSdkVersion COMPILE_SDK_VERSION
@@ -10,6 +20,8 @@ android {
1020
minSdkVersion MIN_SDK_VERSION
1121
versionCode 1
1222
versionName "1.0"
23+
24+
testInstrumentationRunner "com.leanplum.ScreenshotTestRunner"
1325
}
1426
buildTypes {
1527
release {
@@ -50,7 +62,7 @@ dependencies {
5062
implementation project(':AndroidSDKPush')
5163
implementation project(':AndroidSDKLocation')
5264
implementation project(':AndroidSDKFcm')
53-
implementation "androidx.appcompat:appcompat:${APPCOMPAT_LIBRARY_VERSION}"
65+
implementation "androidx.appcompat:appcompat:1.2.0-beta01" // WebView in Emulator with API22 is failing with exception because of appcompat version. In 1.2.0-beta01 it is not reproduced.
5466
implementation 'com.google.android.gms:play-services-location:17.0.0'
5567

5668
// Dependencies used for unit tests.
@@ -66,6 +78,16 @@ dependencies {
6678
testImplementation 'org.powermock:powermock-api-mockito:1.6.6'
6779
testImplementation 'org.powermock:powermock-classloading-xstream:1.6.6'
6880
testImplementation 'org.bouncycastle:bcmail-jdk15on:1.65'
81+
82+
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
83+
androidTestImplementation 'androidx.test:runner:1.2.0'
84+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
85+
androidTestImplementation 'androidx.test:rules:1.2.0'
86+
androidTestImplementation 'org.mockito:mockito-core:1.10.19'
87+
androidTestImplementation "com.crittercism.dexmaker:dexmaker:1.4"
88+
androidTestImplementation "com.crittercism.dexmaker:dexmaker-mockito:1.4"
89+
androidTestImplementation "com.crittercism.dexmaker:dexmaker-dx:1.4"
90+
implementation 'com.facebook.testing.screenshot:core:0.12.0'
6991
}
7092

7193
task jarTests(type: Jar, dependsOn: "assembleDebugUnitTest") {
9.7 KB
Loading
10.4 KB
Loading
116 KB
Loading
24.6 KB
Loading
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.leanplum;
2+
3+
import android.os.Bundle;
4+
import androidx.test.runner.AndroidJUnitRunner;
5+
import com.facebook.testing.screenshot.ScreenshotRunner;
6+
7+
public class ScreenshotTestRunner extends AndroidJUnitRunner {
8+
@Override
9+
public void onCreate(Bundle args) {
10+
ScreenshotRunner.onCreate(this, args);
11+
super.onCreate(args);
12+
}
13+
14+
@Override
15+
public void finish(int resultCode, Bundle results) {
16+
ScreenshotRunner.onDestroy();
17+
super.finish(resultCode, results);
18+
}
19+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.leanplum.messagetemplates;
2+
3+
import android.app.Activity;
4+
import android.content.Context;
5+
import android.content.pm.PackageManager;
6+
import android.view.View;
7+
import androidx.annotation.NonNull;
8+
import androidx.test.ext.junit.runners.AndroidJUnit4;
9+
import androidx.test.rule.ActivityTestRule;
10+
import com.facebook.testing.screenshot.Screenshot;
11+
import com.facebook.testing.screenshot.ViewHelpers;
12+
import com.leanplum.tests.MainActivity;
13+
import org.junit.Rule;
14+
import org.junit.runner.RunWith;
15+
16+
@RunWith(AndroidJUnit4.class)
17+
public abstract class BaseSnapshotTest {
18+
private static final int SNAPSHOT_WIDTH_DP = 480;
19+
private static final int SNAPSHOT_HEIGHT_DP = 640;
20+
21+
@Rule
22+
public ActivityTestRule<MainActivity> activityRule = new ActivityTestRule<>(MainActivity.class);
23+
24+
protected abstract String getSnapshotName();
25+
26+
protected Activity getMainActivity() {
27+
return activityRule.getActivity();
28+
}
29+
30+
protected String getApplicationName() {
31+
PackageManager pm = getMainActivity().getPackageManager();
32+
return getMainActivity().getApplicationInfo().loadLabel(pm).toString();
33+
}
34+
35+
protected void setupView(@NonNull View view) {
36+
ViewHelpers.setupView(view)
37+
.setExactWidthDp(SNAPSHOT_WIDTH_DP)
38+
.setExactHeightDp(SNAPSHOT_HEIGHT_DP)
39+
.layout();
40+
}
41+
42+
protected void snapshotView(@NonNull View view) {
43+
Screenshot.snap(view).setName(getSnapshotName()).record();
44+
}
45+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.leanplum.messagetemplates;
2+
3+
import static org.mockito.Mockito.spy;
4+
import static org.mockito.Mockito.when;
5+
6+
import android.app.Activity;
7+
import android.graphics.Color;
8+
import androidx.test.annotation.UiThreadTest;
9+
import com.leanplum.ActionContext;
10+
import com.leanplum.Leanplum;
11+
import com.leanplum.messagetemplates.MessageTemplates.Args;
12+
import com.leanplum.messagetemplates.MessageTemplates.Values;
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
import org.junit.Test;
16+
17+
public class LPCenterPopupMessageSnapshotTest extends BaseSnapshotTest {
18+
19+
@Override
20+
public String getSnapshotName() {
21+
return "centerPopup";
22+
}
23+
24+
@Test
25+
@UiThreadTest
26+
public void testCenterPopup() {
27+
Activity mainActivity = getMainActivity();
28+
Leanplum.setApplicationContext(mainActivity);
29+
30+
String appName = getApplicationName();
31+
32+
Map<String, Object> args = new HashMap<>();
33+
args.put(Args.TITLE_TEXT, appName);
34+
args.put(Args.TITLE_COLOR, Color.RED);
35+
args.put(Args.MESSAGE_TEXT, Values.POPUP_MESSAGE);
36+
args.put(Args.MESSAGE_COLOR, Color.BLACK);
37+
args.put(Args.BACKGROUND_COLOR, Color.WHITE);
38+
args.put(Args.ACCEPT_BUTTON_TEXT, Values.OK_TEXT);
39+
args.put(Args.ACCEPT_BUTTON_BACKGROUND_COLOR, Color.WHITE);
40+
args.put(Args.ACCEPT_BUTTON_TEXT_COLOR, Color.BLACK);
41+
args.put(Args.LAYOUT_WIDTH, Values.CENTER_POPUP_WIDTH);
42+
args.put(Args.LAYOUT_HEIGHT, Values.CENTER_POPUP_HEIGHT);
43+
ActionContext realContext = new ActionContext(getSnapshotName(), args, null);
44+
45+
ActionContext mockedContext = spy(realContext);
46+
when(mockedContext.stringNamed(Args.TITLE_TEXT)).thenReturn(appName);
47+
when(mockedContext.numberNamed(Args.TITLE_COLOR)).thenReturn(Color.RED);
48+
when(mockedContext.stringNamed(Args.MESSAGE_TEXT)).thenReturn(Values.POPUP_MESSAGE);
49+
when(mockedContext.numberNamed(Args.MESSAGE_COLOR)).thenReturn(Color.BLACK);
50+
when(mockedContext.numberNamed(Args.BACKGROUND_COLOR)).thenReturn(Color.WHITE);
51+
when(mockedContext.stringNamed(Args.ACCEPT_BUTTON_TEXT)).thenReturn(Values.OK_TEXT);
52+
when(mockedContext.numberNamed(Args.ACCEPT_BUTTON_BACKGROUND_COLOR)).thenReturn(Color.WHITE);
53+
when(mockedContext.numberNamed(Args.ACCEPT_BUTTON_TEXT_COLOR)).thenReturn(Color.BLACK);
54+
when(mockedContext.numberNamed(Args.LAYOUT_WIDTH)).thenReturn(Values.CENTER_POPUP_WIDTH);
55+
when(mockedContext.numberNamed(Args.LAYOUT_HEIGHT)).thenReturn(Values.CENTER_POPUP_HEIGHT);
56+
57+
CenterPopupOptions options = new CenterPopupOptions(mockedContext);
58+
CenterPopup centerpopup = new CenterPopup(mainActivity, options);
59+
60+
setupView(centerpopup.dialogView);
61+
snapshotView(centerpopup.dialogView);
62+
}
63+
}

0 commit comments

Comments
 (0)