diff --git a/.gitignore b/.gitignore index 39fb081..25bf2ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.iml .gradle +.idea /local.properties /.idea/workspace.xml /.idea/libraries diff --git a/README.md b/README.md index 3a96074..f645362 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,27 @@ ## Setup -* Clone the repo -* Build the app & test application -* Use BrowserStack app-automate endpoints to run the test-suite +* Clone the Repository +* Download JDK8 from [here](https://www.oracle.com/in/java/technologies/javase/javase-jdk8-downloads.html) +* Update your JDK location via Project Structure (Android Studio) + * Go to File > Project Structure. + * Select the SDK Location section in the list of the left. + * Enter the absolute path of your installed JDK in the text box. +* Build the main application: `./gradlew assemble` (apk will be generated in the `app/build/outputs/apk/debug/` directory) +* Build the test application: `./gradlew assembleAndroidTest` (apk will be generated in the `app/build/outputs/apk/androidTest/debug/` directory) +* Upload both the apk files to BrowserStack and start a session. Refer our documentation for details: [Using Espresso with BrowserStack](https://www.browserstack.com/app-automate/espresso/get-started) ## Notes -* You can check app-automate Espresso related endpoints on [BrowserStack app-automate Espresso](https://www.browserstack.com/app-automate/espresso/get-started) * You can view your test results on the [BrowserStack app-automate dashboard](https://www.browserstack.com/app-automate) ## Additional Resources * [Customizing your tests on BrowserStack](https://www.browserstack.com/app-automate/capabilities) * [Browsers & mobile devices for app-automate testing on BrowserStack](https://www.browserstack.com/list-of-browsers-and-platforms?product=app_automate) * [Using REST API to access information about your builds via the command-line interface](https://www.browserstack.com/app-automate/rest-api) +* [Using Espresso with BrowserStack](https://www.browserstack.com/app-automate/espresso/get-started) +* [Generating JUnit XML report or Test coverage report using Espresso with BrowserStack](https://www.browserstack.com/docs/app-automate/espresso/view-test-reports). + example: + curl -u "< username >:< password >" \ + -X POST "https://api-cloud.browserstack.com/app-automate/espresso/v2/build" \ + -d '{"app": "bs://", "testSuite": "bs://", "devices": ["Google Pixel-8.0"], "coverage": true, "enableSpoonFramework": true }' \ + -H "Content-Type: application/json" diff --git a/app/build-with-flavours.gradle b/app/build-with-flavours.gradle new file mode 100644 index 0000000..74af810 --- /dev/null +++ b/app/build-with-flavours.gradle @@ -0,0 +1,81 @@ +apply plugin: 'com.android.application' +apply plugin: 'spoon' +apply plugin: 'jacoco' +apply plugin: "com.browserstack.gradle" + +buildscript { + repositories { +// maven { +// url "https://plugins.gradle.org/m2/" +// } + mavenLocal() + mavenCentral() + } + + dependencies { + classpath 'com.stanfy.spoon:spoon-gradle-plugin:1.2.2' + // classpath "gradle.plugin.com.browserstack.gradle:browserstack-gradle-plugin:3.0.3" + classpath "com.browserstack:gradle:3.1.3" + } +} + +android { + compileSdkVersion 30 + dataBinding.enabled = true + + defaultConfig { + applicationId "com.sample.browserstack.samplecalculator" + minSdkVersion 15 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + multiDexEnabled true + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + flavorDimensions "devices" + productFlavors { + tablet { + applicationId + "com.sample.browserstack.samplecalculator.app.tablet" + versionName "1.0-tablet" + dimension "devices" + } + phone { + applicationId + "com.sample.browserstack.samplecalculator.app.phone" + versionName "1.0-phone" + dimension "devices" + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' + androidTestImplementation 'com.squareup.spoon:spoon-client:1.7.1' + androidTestImplementation 'androidx.test:rules:1.1.1' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + testImplementation 'junit:junit:4.12' +} + +spoon { + debug = true + adbTimeout = 30 +} + +browserStackConfig { + username = "$System.env.BROWSERSTACK_USERNAME" + accessKey = "$System.env.BROWSERSTACK_ACCESS_KEY" + customId = "AndroidTestAPK" + debug = true + configFilePath = "${rootDir}/config-browserstack.json" +} diff --git a/app/build.gradle b/app/build.gradle index 4edff7c..2253132 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,30 +1,74 @@ apply plugin: 'com.android.application' +apply plugin: 'spoon' +apply plugin: 'jacoco' +apply plugin: "com.browserstack.gradle" + +jacoco { + toolVersion='0.7.5.201505241946' +} +buildscript { + repositories { +// maven { +// url "https://plugins.gradle.org/m2/" +// } + mavenLocal() + mavenCentral() + } + + dependencies { + classpath 'com.stanfy.spoon:spoon-gradle-plugin:1.2.2' + // classpath "gradle.plugin.com.browserstack.gradle:browserstack-gradle-plugin:3.1.0" + classpath "com.browserstack:gradle:3.1.3" + } +} android { - compileSdkVersion 26 + compileSdkVersion 30 dataBinding.enabled = true defaultConfig { applicationId "com.sample.browserstack.samplecalculator" minSdkVersion 15 - targetSdkVersion 26 + targetSdkVersion 30 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + debug { + testCoverageEnabled true + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:appcompat-v7:26.1.0' - implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' + androidTestImplementation 'com.squareup.spoon:spoon-client:1.7.1' + androidTestImplementation 'androidx.test:rules:1.1.1' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.1' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' +} + +spoon { + debug = true + adbTimeout = 30 +} + +browserStackConfig { + username = "$System.env.BROWSERSTACK_USERNAME" + accessKey = "$System.env.BROWSERSTACK_ACCESS_KEY" + customId = "AndroidTestAPK" + debug = true + configFilePath = "${rootDir}/config-browserstack.json" } diff --git a/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureInputTests.java b/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureInputTests.java index 636c1e8..1ca87fb 100644 --- a/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureInputTests.java +++ b/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureInputTests.java @@ -1,18 +1,21 @@ package com.sample.browserstack.samplecalculator; -import android.support.test.filters.SmallTest; -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.filters.SmallTest; +import androidx.test.rule.ActivityTestRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.squareup.spoon.Spoon; + +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; /** * Espresso tests to ensure that editText box is updated appropriately @@ -27,16 +30,27 @@ public class EnsureInputTests { public ActivityTestRule activityRule = new ActivityTestRule(MainActivity.class); + private MainActivity mainActivity; + + @Before + public void setUp() { + mainActivity = activityRule.getActivity(); + } + @Test public void ensureSingleInputIsHandled() { + Spoon.screenshot(mainActivity, "initial_state"); onView(withId(R.id.buttonOne)).perform(click()); onView(withId(R.id.editText)).check(matches(withText("1"))); + Spoon.screenshot(mainActivity, "post_multiple_btn_click"); } @Test public void ensureMultipleInputIsHandled() { + Spoon.screenshot(mainActivity, "initial_state"); onView(withId(R.id.buttonOne)).perform(click()); onView(withId(R.id.buttonTwo)).perform(click()); onView(withId(R.id.editText)).check(matches(withText("12"))); + Spoon.screenshot(mainActivity, "post_multiple_btn_click"); } } diff --git a/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureOperationTests.java b/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureOperationTests.java index 999d7eb..4f2d0ef 100644 --- a/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureOperationTests.java +++ b/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureOperationTests.java @@ -1,18 +1,21 @@ package com.sample.browserstack.samplecalculator; -import android.support.test.filters.MediumTest; -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.filters.MediumTest; +import androidx.test.rule.ActivityTestRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.squareup.spoon.Spoon; + +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; /** * Espresso tests to ensure that simple operations result in @@ -27,6 +30,14 @@ public class EnsureOperationTests { public ActivityTestRule activityRule = new ActivityTestRule(MainActivity.class); + private MainActivity mainActivity; + + @Before + public void setUp() { + mainActivity = activityRule.getActivity(); + } + + @Test public void ensureAdditionWorks() { onView(withId(R.id.buttonOne)).perform(click()); @@ -36,6 +47,7 @@ public void ensureAdditionWorks() { onView(withId(R.id.buttonOne)).perform(click()); onView(withId(R.id.buttonEqual)).perform(click()); onView(withId(R.id.editText)).check(matches(withText("33"))); + Spoon.screenshot(mainActivity, "post_addition"); } @Test @@ -47,6 +59,7 @@ public void ensureSubtractionWorks() { onView(withId(R.id.buttonOne)).perform(click()); onView(withId(R.id.buttonEqual)).perform(click()); onView(withId(R.id.editText)).check(matches(withText("11"))); + Spoon.screenshot(mainActivity, "post_subtraction"); } @Test @@ -57,6 +70,7 @@ public void ensureMultiplicationWorks() { onView(withId(R.id.buttonFive)).perform(click()); onView(withId(R.id.buttonEqual)).perform(click()); onView(withId(R.id.editText)).check(matches(withText("60"))); + Spoon.screenshot(mainActivity, "post_multiplication"); } @Test @@ -67,5 +81,6 @@ public void ensureDivisionWorks() { onView(withId(R.id.buttonThree)).perform(click()); onView(withId(R.id.buttonEqual)).perform(click()); onView(withId(R.id.editText)).check(matches(withText("4"))); + Spoon.screenshot(mainActivity, "post_division"); } } diff --git a/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureRandomTests.java b/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureRandomTests.java index 4413e01..9524c6c 100644 --- a/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureRandomTests.java +++ b/app/src/androidTest/java/com/sample/browserstack/samplecalculator/EnsureRandomTests.java @@ -1,18 +1,18 @@ package com.sample.browserstack.samplecalculator; -import android.support.test.filters.MediumTest; -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.filters.MediumTest; +import androidx.test.rule.ActivityTestRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; /** * Espresso tests to ensure that random operation result are diff --git a/app/src/androidTest/java/com/sample/browserstack/samplecalculator/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/sample/browserstack/samplecalculator/ExampleInstrumentedTest.java index 64821b8..2e25e20 100644 --- a/app/src/androidTest/java/com/sample/browserstack/samplecalculator/ExampleInstrumentedTest.java +++ b/app/src/androidTest/java/com/sample/browserstack/samplecalculator/ExampleInstrumentedTest.java @@ -1,8 +1,8 @@ package com.sample.browserstack.samplecalculator; import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; @@ -17,10 +17,9 @@ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test - public void useAppContext() throws Exception { + public void useAppContext() { // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); assertEquals("com.sample.browserstack.samplecalculator", appContext.getPackageName()); } } diff --git a/app/src/androidTestPhone/java/com/sample/browserstack/sampleCalculator/EnsureLabelTests.java b/app/src/androidTestPhone/java/com/sample/browserstack/sampleCalculator/EnsureLabelTests.java new file mode 100644 index 0000000..6f65442 --- /dev/null +++ b/app/src/androidTestPhone/java/com/sample/browserstack/sampleCalculator/EnsureLabelTests.java @@ -0,0 +1,37 @@ +package com.sample.browserstack.sampleCalculator; + +import androidx.test.filters.SmallTest; +import androidx.test.rule.ActivityTestRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.sample.browserstack.samplecalculator.MainActivity; +import com.sample.browserstack.samplecalculator.R; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; + +/** + * Espresso tests to ensure that editText box is updated appropriately + * whenever buttons are clicked + */ + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class EnsureLabelTests { + + @Rule + public ActivityTestRule activityRule = + new ActivityTestRule(MainActivity.class); + + @Test + public void ensureLabelIsCorrect() { + onView(withId(R.id.infoTextView)).check(matches(withText("Phone"))); + } + +} diff --git a/app/src/androidTestTablet/java/com/sample/browserstack/sampleCalculator/EnsureLabelTests.java b/app/src/androidTestTablet/java/com/sample/browserstack/sampleCalculator/EnsureLabelTests.java new file mode 100644 index 0000000..bee05b7 --- /dev/null +++ b/app/src/androidTestTablet/java/com/sample/browserstack/sampleCalculator/EnsureLabelTests.java @@ -0,0 +1,39 @@ +package com.sample.browserstack.sampleCalculator; + +import androidx.test.filters.SmallTest; +import androidx.test.rule.ActivityTestRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.sample.browserstack.samplecalculator.MainActivity; +import com.sample.browserstack.samplecalculator.R; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; + +/** + * Espresso tests to ensure that editText box is updated appropriately + * whenever buttons are clicked + */ + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class EnsureLablelTests { + + @Rule + public ActivityTestRule activityRule = + new ActivityTestRule(MainActivity.class); + + @Test + public void ensureLabelIsCorrect() { + onView(withId(R.id.infoTextView)).check(matches(withText("Tablet"))); + } + + +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9e0d2a8..69a6e9f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ + + + + + + + + + + +