diff --git a/Demo/build.gradle b/Demo/build.gradle index 331f93a3f1..c67560d5d8 100644 --- a/Demo/build.gradle +++ b/Demo/build.gradle @@ -5,7 +5,7 @@ android { buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion + minSdkVersion 18 targetSdkVersion rootProject.ext.targetSdkVersion versionCode rootProject.ext.versionCode versionName rootProject.ext.versionName @@ -14,16 +14,16 @@ android { signingConfigs { debug { - storeFile file("debug.keystore") - storePassword "android" - keyAlias "androiddebugkey" - keyPassword "android" + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' } release { - storeFile file("debug.keystore") - storePassword "android" - keyAlias "androiddebugkey" - keyPassword "android" + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' } } @@ -49,6 +49,12 @@ android { } } +repositories { + maven { + url "https://jitpack.io" + } +} + configurations.all { resolutionStrategy.force 'com.android.support:support-annotations:23.0.1' } @@ -65,4 +71,6 @@ dependencies { releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' testCompile 'com.android.support.test.espresso:espresso-core:2.2.1' + androidTestCompile project(':TestUtils') + androidTestCompile 'com.github.lkorth:device-automator:e2f12ded31' } diff --git a/Demo/src/androidTest/java/com/braintreepayments/demo/test/CustomTest.java b/Demo/src/androidTest/java/com/braintreepayments/demo/test/CustomTest.java new file mode 100644 index 0000000000..09e5b22253 --- /dev/null +++ b/Demo/src/androidTest/java/com/braintreepayments/demo/test/CustomTest.java @@ -0,0 +1,40 @@ +package com.braintreepayments.demo.test; + +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.LargeTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.braintreepayments.demo.test.utilities.TestHelper.clearPreferences; +import static com.braintreepayments.demo.test.utilities.TestHelper.ensureEnvironmentIsSandbox; +import static com.braintreepayments.demo.test.utilities.TestHelper.launchDemoApp; +import static com.lukekorth.deviceautomator.AutomatorAction.click; +import static com.lukekorth.deviceautomator.AutomatorAction.setText; +import static com.lukekorth.deviceautomator.AutomatorAssertion.text; +import static com.lukekorth.deviceautomator.DeviceAutomator.onDevice; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withText; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withTextStartingWith; +import static org.hamcrest.CoreMatchers.containsString; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class CustomTest { + + @Before + public void setup() { + clearPreferences(); + launchDemoApp(); + ensureEnvironmentIsSandbox(); + onDevice(withText("Custom")).waitForEnabled().perform(click()); + } + + @Test(timeout = 60000) + public void tokenizesACard() { + onDevice(withText("Card Number")).perform(setText("4111111111111111")); + onDevice(withText("Expiration")).perform(setText("1220")); + onDevice(withText("Purchase")).perform(click()); + onDevice(withTextStartingWith("Card Last Two:")).check(text(containsString("11"))); + } +} diff --git a/Demo/src/androidTest/java/com/braintreepayments/demo/test/DropInTest.java b/Demo/src/androidTest/java/com/braintreepayments/demo/test/DropInTest.java new file mode 100644 index 0000000000..0beea078e6 --- /dev/null +++ b/Demo/src/androidTest/java/com/braintreepayments/demo/test/DropInTest.java @@ -0,0 +1,41 @@ +package com.braintreepayments.demo.test; + +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.LargeTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.braintreepayments.demo.test.utilities.TestHelper.clearPreferences; +import static com.braintreepayments.demo.test.utilities.TestHelper.ensureEnvironmentIsSandbox; +import static com.braintreepayments.demo.test.utilities.TestHelper.launchDemoApp; +import static com.lukekorth.deviceautomator.AutomatorAction.click; +import static com.lukekorth.deviceautomator.AutomatorAction.setText; +import static com.lukekorth.deviceautomator.AutomatorAssertion.text; +import static com.lukekorth.deviceautomator.DeviceAutomator.onDevice; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withText; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withTextContaining; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withTextStartingWith; +import static org.hamcrest.CoreMatchers.containsString; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class DropInTest { + + @Before + public void setup() { + clearPreferences(); + launchDemoApp(); + ensureEnvironmentIsSandbox(); + onDevice(withText("Drop-In")).waitForEnabled().perform(click()); + } + + @Test(timeout = 60000) + public void tokenizesACard() { + onDevice(withText("Card Number")).perform(setText("4111111111111111")); + onDevice(withText("Expiration")).perform(setText("1220")); + onDevice(withTextContaining("BUY")).perform(click()); + onDevice(withTextStartingWith("Card Last Two:")).check(text(containsString("11"))); + } +} diff --git a/Demo/src/androidTest/java/com/braintreepayments/demo/test/PayPalTest.java b/Demo/src/androidTest/java/com/braintreepayments/demo/test/PayPalTest.java new file mode 100644 index 0000000000..18a58a1067 --- /dev/null +++ b/Demo/src/androidTest/java/com/braintreepayments/demo/test/PayPalTest.java @@ -0,0 +1,129 @@ +package com.braintreepayments.demo.test; + +import android.os.SystemClock; +import android.support.test.filters.SdkSuppress; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.LargeTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.braintreepayments.demo.test.utilities.TestHelper.clearPreferences; +import static com.braintreepayments.demo.test.utilities.TestHelper.ensureEnvironmentIsSandbox; +import static com.braintreepayments.demo.test.utilities.TestHelper.installPayPalWallet; +import static com.braintreepayments.demo.test.utilities.TestHelper.isAppInstalled; +import static com.braintreepayments.demo.test.utilities.TestHelper.launchDemoApp; +import static com.braintreepayments.demo.test.utilities.TestHelper.uninstallPayPalWallet; +import static com.lukekorth.deviceautomator.AutomatorAction.click; +import static com.lukekorth.deviceautomator.AutomatorAction.setText; +import static com.lukekorth.deviceautomator.AutomatorAssertion.text; +import static com.lukekorth.deviceautomator.DeviceAutomator.onDevice; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withContentDescription; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withText; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withTextContaining; +import static org.hamcrest.Matchers.containsString; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class PayPalTest { + + @Before + public void setup() { + clearPreferences(); + launchDemoApp(); + ensureEnvironmentIsSandbox(); + onDevice(withText("PayPal")).waitForEnabled().perform(click()); + } + + @SdkSuppress(minSdkVersion = 21) + @Test(timeout = 60000) + public void browserSwitch_makesASinglePayment() { + uninstallPayPalWallet(); + + onDevice(withText("Single Payment")).waitForEnabled().perform(click()); + onDevice(withContentDescription("Proceed with Sandbox Purchase")).perform(click()); + + onDevice(withTextContaining("Email:")).check(text(containsString("bt_buyer_us@paypal.com"))); + } + + @SdkSuppress(minSdkVersion = 21) + @Test(timeout = 60000) + public void browserSwitch_makesAFuturePayment() { + uninstallPayPalWallet(); + + onDevice(withText("Future Payment")).waitForEnabled().perform(click()); + onDevice(withContentDescription("Email")).perform(click(), setText("test@paypal.com")); + onDevice().pressDPadDown().typeText("password"); + onDevice(withContentDescription("Log In")).perform(click()); + onDevice(withContentDescription("Agree")).perform(click()); + + onDevice(withTextContaining("Email:")).check(text(containsString("jane.doe@example.com"))); + } + + @SdkSuppress(minSdkVersion = 21) + @Test(timeout = 60000) + public void browserSwitch_makesAFuturePaymentWithAddressScope() { + uninstallPayPalWallet(); + + onDevice(withText("Future Payment (Address Scope)")).waitForEnabled().perform(click()); + onDevice(withContentDescription("Email")).perform(click(), setText("test@paypal.com")); + onDevice().pressDPadDown().typeText("password"); + onDevice(withContentDescription("Log In")).perform(click()); + onDevice(withContentDescription("Agree")).perform(click()); + + onDevice(withTextContaining("Email:")).check(text(containsString("jane.doe@example.com"))); + SystemClock.sleep(10000); + } + + @SdkSuppress(minSdkVersion = 21) + @Test(timeout = 60000) + public void browserSwitch_makesABillingAgreement() { + uninstallPayPalWallet(); + + onDevice(withText("Billing Agreement")).waitForEnabled().perform(click()); + onDevice(withContentDescription("Proceed with Sandbox Purchase")).perform(click()); + + onDevice(withTextContaining("Email:")).check(text(containsString("bt_buyer_us@paypal.com"))); + } + + @Test(timeout = 120000) + public void appSwitch_forSinglePayment() { + installPayPalWallet(); + + onDevice(withText("Single Payment")).waitForEnabled().perform(click()); + + onDevice().checkForegroundAppIs("com.paypal.android.p2pmobile"); + } + + @Test(timeout = 120000) + public void appSwitch_forFuturePayment() { + installPayPalWallet(); + + onDevice(withText("Future Payment")).waitForEnabled().perform(click()); + + onDevice().checkForegroundAppIs("com.paypal.android.p2pmobile"); + } + + @Test(timeout = 120000) + public void appSwitch_forFuturePaymentWithAddressScope() { + installPayPalWallet(); + + onDevice(withText("Future Payment (Address Scope)")).waitForEnabled().perform(click()); + + onDevice().checkForegroundAppIs("com.paypal.android.p2pmobile"); + } + + @Test(timeout = 120000) + public void appSwitch_usesBrowserForBillingAgreement() { + installPayPalWallet(); + + onDevice(withText("Billing Agreement")).waitForEnabled().perform(click()); + + if (isAppInstalled("com.android.chrome")) { + onDevice().checkForegroundAppIs("com.android.chrome"); + } else { + onDevice().checkForegroundAppIs("com.android.browser"); + } + } +} diff --git a/Demo/src/androidTest/java/com/braintreepayments/demo/test/PaymentButtonTest.java b/Demo/src/androidTest/java/com/braintreepayments/demo/test/PaymentButtonTest.java new file mode 100644 index 0000000000..5449f092f6 --- /dev/null +++ b/Demo/src/androidTest/java/com/braintreepayments/demo/test/PaymentButtonTest.java @@ -0,0 +1,51 @@ +package com.braintreepayments.demo.test; + +import android.os.SystemClock; +import android.support.test.filters.SdkSuppress; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.LargeTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.braintreepayments.demo.test.utilities.TestHelper.clearPreferences; +import static com.braintreepayments.demo.test.utilities.TestHelper.ensureEnvironmentIsSandbox; +import static com.braintreepayments.demo.test.utilities.TestHelper.launchDemoApp; +import static com.braintreepayments.demo.test.utilities.TestHelper.uninstallPayPalWallet; +import static com.lukekorth.deviceautomator.AutomatorAction.click; +import static com.lukekorth.deviceautomator.AutomatorAction.setText; +import static com.lukekorth.deviceautomator.AutomatorAssertion.text; +import static com.lukekorth.deviceautomator.DeviceAutomator.onDevice; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withContentDescription; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withText; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withTextContaining; +import static org.hamcrest.CoreMatchers.containsString; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class PaymentButtonTest { + + @Before + public void setup() { + clearPreferences(); + launchDemoApp(); + ensureEnvironmentIsSandbox(); + onDevice(withText("Payment Button")).waitForEnabled().perform(click()); + } + + @SdkSuppress(minSdkVersion = 21) + @Test(timeout = 60000) + public void tokenizesPayPal() { + uninstallPayPalWallet(); + + SystemClock.sleep(5000); + onDevice(withContentDescription("Pay with PayPal")).waitForEnabled().perform(click()); + onDevice(withContentDescription("Email")).perform(click(), setText("test@paypal.com")); + onDevice().pressDPadDown().typeText("password"); + onDevice(withContentDescription("Log In")).perform(click()); + onDevice(withContentDescription("Agree")).perform(click()); + + onDevice(withTextContaining("Email:")).check(text(containsString("jane.doe@example.com"))); + } +} diff --git a/Demo/src/androidTest/java/com/braintreepayments/demo/test/utilities/TestHelper.java b/Demo/src/androidTest/java/com/braintreepayments/demo/test/utilities/TestHelper.java new file mode 100644 index 0000000000..6881f589a5 --- /dev/null +++ b/Demo/src/androidTest/java/com/braintreepayments/demo/test/utilities/TestHelper.java @@ -0,0 +1,90 @@ +package com.braintreepayments.demo.test.utilities; + +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.SystemClock; +import android.preference.PreferenceManager; +import android.util.Log; + +import static android.support.test.InstrumentationRegistry.getTargetContext; +import static com.lukekorth.deviceautomator.AutomatorAction.click; +import static com.lukekorth.deviceautomator.AutomatorAssertion.text; +import static com.lukekorth.deviceautomator.DeviceAutomator.onDevice; +import static com.lukekorth.deviceautomator.UiObjectMatcher.withText; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; +import static org.hamcrest.CoreMatchers.equalTo; + +public class TestHelper { + + private static final String PAYPAL_WALLET_PACKAGE_NAME = "com.paypal.android.p2pmobile"; + + public static void clearPreferences() { + PreferenceManager.getDefaultSharedPreferences(getTargetContext()) + .edit() + .clear() + .commit(); + } + + public static void launchDemoApp() { + onDevice().onHomeScreen().launchApp("com.braintreepayments.demo"); + } + + public static void ensureEnvironmentIsSandbox() { + ensureEnvironmentIs("Sandbox"); + } + + public static void ensureEnvironmentIsProduction() { + ensureEnvironmentIs("Production"); + } + + private static void ensureEnvironmentIs(String environment) { + String otherEnvironment; + switch (environment) { + case "Sandbox": + otherEnvironment = "Production"; + break; + case "Production": + otherEnvironment = "Sandbox"; + break; + default: + fail("Environment was invalid"); + return; + } + + try { + onDevice(withText(environment)).check(text(equalTo(environment))); + } catch (RuntimeException e) { + onDevice(withText(otherEnvironment)).perform(click()); + onDevice(withText(environment)).perform(click()); + onDevice(withText(environment)).check(text(equalTo(environment))); + } + } + + public static void installPayPalWallet() { + if (!isAppInstalled(PAYPAL_WALLET_PACKAGE_NAME)) { + Log.d("request_command", "install paypal wallet"); + SystemClock.sleep(45000); + assertTrue(isAppInstalled(PAYPAL_WALLET_PACKAGE_NAME)); + } + } + + public static void uninstallPayPalWallet() { + if (isAppInstalled(PAYPAL_WALLET_PACKAGE_NAME)) { + Log.d("request_command", "uninstall paypal wallet"); + SystemClock.sleep(5000); + assertFalse(isAppInstalled(PAYPAL_WALLET_PACKAGE_NAME)); + } + } + + public static boolean isAppInstalled(String packageName) { + PackageManager pm = getTargetContext().getPackageManager(); + try { + pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES); + return true; + } catch (NameNotFoundException e) { + return false; + } + } +} diff --git a/script/log_listener.rb b/script/log_listener.rb new file mode 100644 index 0000000000..ec787d4b9e --- /dev/null +++ b/script/log_listener.rb @@ -0,0 +1,38 @@ +require 'pty' + +TAGS = ["request_command"] +FILTER = "'#{TAGS.join('|')}'" + +def setup + `adb logcat -c` +end + +def run + begin + PTY.spawn("adb logcat -v tag | grep -E #{FILTER}") do |stdin, stdout, pid| + begin + stdin.each do |line| + if line.include?("request_command") + handle_command_request(line.split(':')[1].strip) + end + end + rescue Errno::EIO + # adb exited, stopping + end + end + rescue PTY::ChildExited + # adb exited, stopping + end +end + +def handle_command_request(command) + if command == 'install paypal wallet' + `adb install -r #{__dir__}/../vendor/com.paypal.android.p2pmobile.apk > /dev/null` + elsif command == 'uninstall paypal wallet' + `adb uninstall com.paypal.android.p2pmobile > /dev/null` + end +end + +setup +run + diff --git a/vendor/com.paypal.android.p2pmobile.apk b/vendor/com.paypal.android.p2pmobile.apk new file mode 100644 index 0000000000..f546a5151c Binary files /dev/null and b/vendor/com.paypal.android.p2pmobile.apk differ