diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0601958f2e8bbfa87f66d5a0b5123251df12f921..a906e2d705b430553529e04790ffc051301348c2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,6 +16,7 @@ build: stage: build script: - ./gradlew build + - ./gradlew assembleAndroidTest artifacts: paths: - app/build/outputs/apk diff --git a/app/build.gradle b/app/build.gradle index fb5da052f89f9f4c4c5475d168e78096f7450936..82218632e31864100c75fe9cb0975d7d71d1db0e 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,8 +19,8 @@ android { targetSdkVersion Versions.target_sdk versionCode versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 versionName "${versionMajor}.${versionMinor}.${versionPatch}" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + testBuildType System.getProperty('testBuildType', 'release') renderscriptTargetApi 28 renderscriptSupportModeEnabled true } @@ -33,7 +33,6 @@ android { applicationIdSuffix '.debug' signingConfig signingConfigs.debug } - applicationVariants.all { variant -> if (variant.buildType.name == "debug") { variant.outputs.all { output -> @@ -44,6 +43,7 @@ android { } } + signingConfigs { debug { storeFile file(getRootDir().path + "/keystore/debug.keystore") @@ -150,6 +150,8 @@ dependencies { androidTestImplementation Libs.AndroidX.Test.runner androidTestImplementation Libs.AndroidX.Test.rules implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0' + androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' + } apply plugin: 'com.getkeepsafe.dexcount' diff --git a/app/src/androidTest/java/foundation/e/blisslauncher/BlissLauncherTestSuite.java b/app/src/androidTest/java/foundation/e/blisslauncher/BlissLauncherTestSuite.java new file mode 100644 index 0000000000000000000000000000000000000000..4abe0f2c6397fa5fd0482a6b47eb0d1ced2de3e1 --- /dev/null +++ b/app/src/androidTest/java/foundation/e/blisslauncher/BlissLauncherTestSuite.java @@ -0,0 +1,21 @@ +package foundation.e.blisslauncher; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + + +import foundation.e.blisslauncher.features.launcher.LauncherActivityUiTest; + +@RunWith(Suite.class) +/* Here list all you tests classes that are part of the suite + * eg: + * mainActivityTest.class, + * secondActivityTest.class, + * serviceTest.class + */ +@Suite.SuiteClasses( + LauncherActivityUiTest.class +) +public class BlissLauncherTestSuite{ + +} diff --git a/app/src/androidTest/java/foundation/e/blisslauncher/ExampleInstrumentedTest.java b/app/src/androidTest/java/foundation/e/blisslauncher/ExampleInstrumentedTest.java deleted file mode 100755 index f0223b542855e3e0a8796aa661923aa7d72ac19b..0000000000000000000000000000000000000000 --- a/app/src/androidTest/java/foundation/e/blisslauncher/ExampleInstrumentedTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2018 /e/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package foundation.e.blisslauncher; - -import static org.junit.Assert.*; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; - -/** - * Instrumentation test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - - assertEquals("org.indin.blisslaunchero", appContext.getPackageName()); - } -} diff --git a/app/src/androidTest/java/foundation/e/blisslauncher/features/launcher/LauncherActivityUiTest.java b/app/src/androidTest/java/foundation/e/blisslauncher/features/launcher/LauncherActivityUiTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a0985bf07cfda699a8b412b7b4a802ce087cf8d0 --- /dev/null +++ b/app/src/androidTest/java/foundation/e/blisslauncher/features/launcher/LauncherActivityUiTest.java @@ -0,0 +1,153 @@ +package foundation.e.blisslauncher.features.launcher; + + +import android.view.View; + +import androidx.test.espresso.ViewInteraction; +import androidx.test.espresso.action.ViewActions; +import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.rule.ActivityTestRule; +import androidx.test.uiautomator.UiDevice; + +import org.hamcrest.Matcher; +import org.hamcrest.core.IsInstanceOf; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import java.io.IOException; +import foundation.e.blisslauncher.R; + +import static androidx.test.espresso.Espresso.closeSoftKeyboard; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.assertion.ViewAssertions.*; +import static androidx.test.espresso.matcher.ViewMatchers.*; +import static androidx.test.espresso.matcher.ViewMatchers.hasChildCount; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withHint; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withParent; +import static androidx.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.not; + + +//instrument --package foundation.e.blisslauncher.features.launcher --class LauncherActivityUiTest --runner + + +@RunWith(AndroidJUnit4ClassRunner.class) +public class LauncherActivityUiTest { + + private UiDevice device; + @Rule + public ActivityTestRule mLauncherActivityTestRule = + new ActivityTestRule(LauncherActivity.class); + + + + @Test + public void displayLeftPanelTest() throws Exception{ + //Swipe on the main view to display the left panel + onView(withId(R.id.appGrid)).perform(ViewActions.swipeRight()); + + //Check every element that should be here are here: Search bar, app suggestion, edit widget buttons and weather widget + + //Check app suggestion is displayed + onView(allOf(withId(R.id.suggestedAppGrid), hasChildCount(4))).check(matches(isDisplayed())); + + //check edit widget button is displayed + onView(withId(R.id.edit_widgets_button)).check(matches(isDisplayed())); + + //check that search_input is displayed + //Note: it was a pain to find the "not(withParent(withParent(withParent(withId(swipe_search_container))))" + //because it told that was more than one match with other trials, but in the "run" window , there was only one + //I had to add breakpoint and analyse Object "editText" to find the other one then to find for difference between both... + final Matcher searchInputMatcher = allOf(withId(R.id.search_input), not( withParent( withParent( withParent( withId(R.id.swipe_search_container ) ) ) ) ) ); + ViewInteraction editText = onView(searchInputMatcher); + + editText.check(matches(withHint("Search"))) + .check(matches( isDisplayed() ) ); + + //check that weather widget is displayed + onView(withId(R.id.weather_info_layout)).check(matches(isDisplayed())); + } + + /** + * This test requires Calendar App to be installed on the device + * @throws Exception + */ + @Test + public void searchCalendarAppTest() throws Exception{ + final String Calendar_app_name = "Calendar"; + + device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + + //Swipe on the main view to display the left panel + onView(withId(R.id.appGrid)).perform(ViewActions.swipeRight()); + final Matcher notChildOfSwipeSearchContainer = not( withParent( withParent( withParent( withId(R.id.swipe_search_container ) ) ) ) ); + final Matcher searchInputMatcher = allOf(withId(R.id.search_input), notChildOfSwipeSearchContainer ); + + + //Check there is 4 app suggested + final ViewInteraction appGrid = onView(allOf(withId(R.id.suggestedAppGrid), withParent(withParent(withId(R.id.used_apps_layout) ) ), isDisplayed() ) ); + appGrid.check(matches(hasChildCount(4))); + + + + //Click on "search input bar" + final ViewInteraction editText = onView(searchInputMatcher); + editText.perform(ViewActions.click()); + + final String checkKeyboardCmd = "dumpsys input_method | grep mInputShown"; + + //check soft keyboard displayed + boolean softKeyboardShown = false; + try { + softKeyboardShown = device.executeShellCommand(checkKeyboardCmd).contains("mInputShown=true"); + } catch ( IOException e) { + System.out.println(e.toString()); + throw new RuntimeException("Keyboard check failed", e); + } + + Assert.assertTrue(softKeyboardShown); + + //Type "Calendar" into the textBox + editText.perform(ViewActions.typeText(Calendar_app_name)); + + //Check the value is set in input + editText.check(matches(withText(Calendar_app_name))); + + + + //check the clear button is present + onView(allOf(withId(R.id.clearSuggestionImageView), notChildOfSwipeSearchContainer) ) + .check(matches( not(withEffectiveVisibility(Visibility.GONE)))); + + + //close soft keyboard + closeSoftKeyboard(); + + Thread.sleep(5000); //required to wait for update of UI + + + + //Check that there is only one app show in grid + final ViewInteraction appGrid2 = onView(allOf(withId(R.id.suggestedAppGrid), withParent(withParent(withId(R.id.used_apps_layout) ) ), isDisplayed() ) ); + appGrid2.check(matches(hasChildCount(1))); //DOESN't WORK + + + // Check that Calendar icon is clickable + final ViewInteraction appLabel = onView( + allOf( + withId( R.id.app_label), + withText(Calendar_app_name), + withParent( + withParent(IsInstanceOf.instanceOf(android.widget.FrameLayout.class) ) + ), isDisplayed() + ) ) ; + + appLabel.check(matches(withParent(withChild(allOf(withId(R.id.app_icon), isClickable()))))); + } + +}