diff --git a/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/bottomnav/UiBottomNavigationView.kt b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/bottomnav/UiBottomNavigationView.kt new file mode 100644 index 000000000..4f6a73cb8 --- /dev/null +++ b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/bottomnav/UiBottomNavigationView.kt @@ -0,0 +1,17 @@ +@file:Suppress("unused") +package com.kaspersky.components.kautomator.dsl.bottomnav + +import com.kaspersky.components.kautomator.dsl.common.builders.UiViewBuilder +import com.kaspersky.components.kautomator.dsl.common.builders.UiViewSelector +import com.kaspersky.components.kautomator.dsl.common.views.UiBaseView + +/** + * View for acting and asserting on BottomNavigationView + * + * @see UiBottomNavigationViewActions + * @see UiBottomNavigationViewAssertions + */ +class UiBottomNavigationView : UiBaseView, UiBottomNavigationViewActions, UiBottomNavigationViewAssertions { + constructor(selector: UiViewSelector) : super(selector) + constructor(builder: UiViewBuilder.() -> Unit) : super(builder) +} \ No newline at end of file diff --git a/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/bottomnav/UiBottomNavigationViewActions.kt b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/bottomnav/UiBottomNavigationViewActions.kt new file mode 100644 index 000000000..2e7b1dd9e --- /dev/null +++ b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/bottomnav/UiBottomNavigationViewActions.kt @@ -0,0 +1,53 @@ +@file:Suppress("unused") +package com.kaspersky.components.kautomator.dsl.bottomnav + +import androidx.test.uiautomator.By +import com.kaspersky.components.kautomator.dsl.common.actions.UiBaseActions +import com.kaspersky.components.kautomator.intercepting.operation.UiOperationType + +/** + * Provides actions for BottomNavigationView + */ +interface UiBottomNavigationViewActions : UiBaseActions { + + /** + * Selects menu item with given id + * + * @param id Menu item id + */ + fun setSelectedItemWithId(id: String) { + view.perform(UiBottomNavigationViewActionType.SELECT_WITH_ID) { + findObject(By.res(applicationPackage, id)).click() + } + } + + /** + * Selects menu item with given index. Note that this method uses view hierarchy which could be changed at any time. + * + * @param index Menu item index + */ + fun setSelectedItemWithIndex(index: Int) { + view.perform(UiBottomNavigationViewActionType.SELECT_WITH_INDEX) { + children[0] // ViewGroup with menu items + .children[index] // Menu item with index + .click() + } + } + + /** + * Selects menu item with given title. Note that this method uses view hierarchy which could be changed at any time. + * + * @param title Menu item title + */ + fun setSelectedItemWithTitle(title: String) { + view.perform(UiBottomNavigationViewActionType.SELECT_WITH_TITLE) { + findObject(By.text(title)).click() + } + } + + enum class UiBottomNavigationViewActionType : UiOperationType { + SELECT_WITH_ID, + SELECT_WITH_INDEX, + SELECT_WITH_TITLE + } +} \ No newline at end of file diff --git a/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/bottomnav/UiBottomNavigationViewAssertions.kt b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/bottomnav/UiBottomNavigationViewAssertions.kt new file mode 100644 index 000000000..0aae92ca9 --- /dev/null +++ b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/bottomnav/UiBottomNavigationViewAssertions.kt @@ -0,0 +1,104 @@ +@file:Suppress("unused") +package com.kaspersky.components.kautomator.dsl.bottomnav + +import androidx.test.uiautomator.By +import com.google.common.truth.Truth.assertThat +import com.kaspersky.components.kautomator.dsl.common.assertions.UiBaseAssertions +import com.kaspersky.components.kautomator.intercepting.operation.UiOperationType + +/** + * Provides assertions for BottomNavigationview + */ +interface UiBottomNavigationViewAssertions : UiBaseAssertions { + + /** + * Checks if the view's selected menu item id matches given one + * + * @param id Menu item id + */ + fun hasSelectedItemWithId(id: String) { + view.check(UiBottomNavigationViewAssertionType.IS_SELECTED_ITEM_WITH_ID) { + val item = findObject(By.res(applicationPackage, id)) + assertThat(item.isSelected).isTrue() + } + } + + /** + * Checks if the view's selected menu item id does not match given one. + * + * @param id Menu item id + */ + fun hasNotSelectedItemWithId(id: String) { + view.check(UiBottomNavigationViewAssertionType.IS_NOT_SELECTED_ITEM_WITH_ID) { + val item = findObject(By.res(applicationPackage, id)) + assertThat(item.isSelected).isFalse() + } + } + + /** + * Checks if the view's selected menu item index matches given one. + * Note that this method uses view hierarchy which could be changed at any time. + * + * @param index Menu item index + */ + fun hasSelectedItemWithIndex(index: Int) { + view.check(UiBottomNavigationViewAssertionType.IS_SELECTED_ITEM_WITH_INDEX) { + val item = children[0] // ViewGroup with menu items + .children[index] // Menu item with index + assertThat(item.isSelected).isTrue() + } + } + + /** + * Checks if the view's selected menu item index does not match given one. + * Note that this method uses view hierarchy which could be changed at any time. + * + * @param index Menu item index + */ + fun hasNotSelectedItemWithIndex(index: Int) { + view.check(UiBottomNavigationViewAssertionType.IS_NOT_SELECTED_ITEM_WITH_INDEX) { + val item = children[0] // ViewGroup with menu items + .children[index] // Menu item with index + assertThat(item.isSelected).isFalse() + } + } + + /** + * Checks if the view's selected menu item title matches given one. + * Note that this method uses view hierarchy which could be changed at any time. + * + * @param title Menu item title + */ + fun hasSelectedItemWithTitle(title: String) { + view.check(UiBottomNavigationViewAssertionType.IS_SELECTED_ITEM_WITH_TITLE) { + val item = findObject(By.text(title)) + .parent // BaselineLayout + .parent // Menu item + assertThat(item.isSelected).isTrue() + } + } + + /** + * Checks if the view's selected menu item title does not match given one. + * Note that this method uses view hierarchy which could be changed at any time. + * + * @param title Menu item title + */ + fun hasNotSelectedItemWithTitle(title: String) { + view.check(UiBottomNavigationViewAssertionType.IS_NOT_SELECTED_ITEM_WITH_TITLE) { + val item = findObject(By.text(title)) + .parent // BaselineLayout + .parent // Menu item + assertThat(item.isSelected).isFalse() + } + } + + enum class UiBottomNavigationViewAssertionType : UiOperationType { + IS_SELECTED_ITEM_WITH_ID, + IS_NOT_SELECTED_ITEM_WITH_ID, + IS_SELECTED_ITEM_WITH_INDEX, + IS_NOT_SELECTED_ITEM_WITH_INDEX, + IS_SELECTED_ITEM_WITH_TITLE, + IS_NOT_SELECTED_ITEM_WITH_TITLE + } +} \ No newline at end of file diff --git a/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckBox.kt b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckBox.kt index 8ca35ce6d..5d141a475 100644 --- a/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckBox.kt +++ b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckBox.kt @@ -1,3 +1,4 @@ +@file:Suppress("unused") package com.kaspersky.components.kautomator.dsl.check import com.kaspersky.components.kautomator.dsl.common.builders.UiViewBuilder diff --git a/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckableActions.kt b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckableActions.kt index ab99acfff..851059536 100644 --- a/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckableActions.kt +++ b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckableActions.kt @@ -1,8 +1,13 @@ +@file:Suppress("unused") package com.kaspersky.components.kautomator.dsl.check + import com.kaspersky.components.kautomator.dsl.check.UiCheckableActions.CheckableActionType.SET_CHECKED import com.kaspersky.components.kautomator.dsl.common.actions.UiBaseActions import com.kaspersky.components.kautomator.intercepting.operation.UiOperationType +/** + * Provides actions for checkable views + */ interface UiCheckableActions : UiBaseActions { /** diff --git a/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckableAssertions.kt b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckableAssertions.kt index 3477cfaa3..eb2f3e0df 100644 --- a/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckableAssertions.kt +++ b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/dsl/check/UiCheckableAssertions.kt @@ -1,3 +1,4 @@ +@file:Suppress("unused") package com.kaspersky.components.kautomator.dsl.check import com.google.common.truth.Truth.assertThat @@ -5,7 +6,7 @@ import com.kaspersky.components.kautomator.dsl.common.assertions.UiBaseAssertion import com.kaspersky.components.kautomator.intercepting.operation.UiOperationType /** - * Provides assertions for UiCheckBox + * Provides assertions for checkable views */ interface UiCheckableAssertions : UiBaseAssertions { @@ -23,24 +24,8 @@ interface UiCheckableAssertions : UiBaseAssertions { view.check(CheckableAssertionType.IS_NOT_CHECKED) { assertThat(isChecked).isFalse() } } - /** - * Checks if the view is checkable - */ - fun isCheckable() { - view.check(CheckableAssertionType.IS_CHECKABLE) { assertThat(isCheckable).isTrue() } - } - - /** - * Checks if the view is not checkable - */ - fun isNotCheckable() { - view.check(CheckableAssertionType.IS_NOT_CHECKABLE) { assertThat(isCheckable).isFalse() } - } - enum class CheckableAssertionType : UiOperationType { IS_CHECKED, - IS_NOT_CHECKED, - IS_CHECKABLE, - IS_NOT_CHECKABLE + IS_NOT_CHECKED } } \ No newline at end of file diff --git a/sample_kautomator/build.gradle b/sample_kautomator/build.gradle index 8eca18276..361ae181b 100644 --- a/sample_kautomator/build.gradle +++ b/sample_kautomator/build.gradle @@ -8,7 +8,7 @@ android { buildToolsVersion versions.buildTools defaultConfig { - applicationId "com.kaspersky.kaspresso.sample_uiautomator_dsl" + applicationId "com.kaspersky.kaspresso.sample_kautomator" minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk versionCode 1 @@ -28,6 +28,7 @@ android { dependencies { implementation "androidx.appcompat:appcompat:$versions.androidSupport" + implementation 'com.google.android.material:material:1.0.0' implementation "androidx.constraintlayout:constraintlayout:$versions.constraint" testImplementation "junit:junit:$versions.junit" diff --git a/sample_kautomator/src/androidTest/java/com/kaspersky/kaspresso/sample_kautomator/screen/ComponentsScreen.kt b/sample_kautomator/src/androidTest/java/com/kaspersky/kaspresso/sample_kautomator/screen/ComponentsScreen.kt new file mode 100644 index 000000000..ee9c9b248 --- /dev/null +++ b/sample_kautomator/src/androidTest/java/com/kaspersky/kaspresso/sample_kautomator/screen/ComponentsScreen.kt @@ -0,0 +1,13 @@ +package com.kaspersky.kaspresso.sample_kautomator.screen + +import com.kaspersky.components.kautomator.dsl.bottomnav.UiBottomNavigationView +import com.kaspersky.components.kautomator.dsl.check.UiCheckBox +import com.kaspersky.components.kautomator.dsl.screen.UiScreen + +object ComponentsScreen : UiScreen() { + + private const val MAIN_APP_PACKAGE_ID = "com.kaspersky.kaspresso.sample_kautomator" + + val bottomNav = UiBottomNavigationView { withId(this@ComponentsScreen.MAIN_APP_PACKAGE_ID, "bottomNav") } + val checkbox = UiCheckBox { withId(this@ComponentsScreen.MAIN_APP_PACKAGE_ID, "checkBox") } +} \ No newline at end of file diff --git a/sample_kautomator/src/androidTest/java/com/kaspersky/kaspresso/sample_kautomator/test/components/BottomNavigationViewTest.kt b/sample_kautomator/src/androidTest/java/com/kaspersky/kaspresso/sample_kautomator/test/components/BottomNavigationViewTest.kt new file mode 100644 index 000000000..c9db826a5 --- /dev/null +++ b/sample_kautomator/src/androidTest/java/com/kaspersky/kaspresso/sample_kautomator/test/components/BottomNavigationViewTest.kt @@ -0,0 +1,58 @@ +package com.kaspersky.kaspresso.sample_kautomator.test.components + +import androidx.test.rule.ActivityTestRule +import com.kaspersky.kaspresso.sample_kautomator.ComponentsActivity +import com.kaspersky.kaspresso.sample_kautomator.screen.ComponentsScreen +import com.kaspersky.kaspresso.testcases.api.testcase.TestCase +import org.junit.Rule +import org.junit.Test + +class BottomNavigationViewTest : TestCase() { + + companion object { + private const val ITEM_0_TEXT = "Menu Item 1" + private const val ITEM_1_TEXT = "Menu Item 2" + + private const val ITEM_0_ID = "menu_item_1" + private const val ITEM_1_ID = "menu_item_2" + } + + @get:Rule + val rule = ActivityTestRule(ComponentsActivity::class.java, true, true) + + @Test + fun test() { + run { + + step("Select item by id") { + ComponentsScreen { + bottomNav { + setSelectedItemWithId(ITEM_1_ID) + hasSelectedItemWithId(ITEM_1_ID) + hasNotSelectedItemWithId(ITEM_0_ID) + } + } + } + + step("Select item by index") { + ComponentsScreen { + bottomNav { + setSelectedItemWithIndex(0) + hasSelectedItemWithIndex(0) + hasNotSelectedItemWithIndex(1) + } + } + } + + step("Select item by label") { + ComponentsScreen { + bottomNav { + setSelectedItemWithTitle(ITEM_1_TEXT) + hasSelectedItemWithTitle(ITEM_1_TEXT) + hasNotSelectedItemWithTitle(ITEM_0_TEXT) + } + } + } + } + } +} \ No newline at end of file diff --git a/sample_kautomator/src/androidTest/java/com/kaspersky/kaspresso/sample_kautomator/test/components/CheckboxTest.kt b/sample_kautomator/src/androidTest/java/com/kaspersky/kaspresso/sample_kautomator/test/components/CheckboxTest.kt new file mode 100644 index 000000000..fe124bb29 --- /dev/null +++ b/sample_kautomator/src/androidTest/java/com/kaspersky/kaspresso/sample_kautomator/test/components/CheckboxTest.kt @@ -0,0 +1,37 @@ +package com.kaspersky.kaspresso.sample_kautomator.test.components + +import androidx.test.rule.ActivityTestRule +import com.kaspersky.kaspresso.sample_kautomator.ComponentsActivity +import com.kaspersky.kaspresso.sample_kautomator.screen.ComponentsScreen +import com.kaspersky.kaspresso.testcases.api.testcase.TestCase +import org.junit.Rule +import org.junit.Test + +class CheckboxTest : TestCase() { + + @get:Rule + val rule = ActivityTestRule(ComponentsActivity::class.java, true, true) + + @Test + fun test() { + run { + step("Set checked") { + ComponentsScreen { + checkbox { + setChecked(true) + isChecked() + } + } + } + + step("Set not checked") { + ComponentsScreen { + checkbox { + setChecked(false) + isNotChecked() + } + } + } + } + } +} \ No newline at end of file diff --git a/sample_kautomator/src/main/AndroidManifest.xml b/sample_kautomator/src/main/AndroidManifest.xml index 7a8ce59a2..901d7284b 100644 --- a/sample_kautomator/src/main/AndroidManifest.xml +++ b/sample_kautomator/src/main/AndroidManifest.xml @@ -22,6 +22,8 @@ + + \ No newline at end of file diff --git a/sample_kautomator/src/main/java/com/kaspersky/kaspresso/sample_kautomator/ComponentsActivity.kt b/sample_kautomator/src/main/java/com/kaspersky/kaspresso/sample_kautomator/ComponentsActivity.kt new file mode 100644 index 000000000..9d4a65699 --- /dev/null +++ b/sample_kautomator/src/main/java/com/kaspersky/kaspresso/sample_kautomator/ComponentsActivity.kt @@ -0,0 +1,12 @@ +package com.kaspersky.kaspresso.sample_kautomator + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity + +class ComponentsActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_ui_components) + } +} \ No newline at end of file diff --git a/sample_kautomator/src/main/res/layout/activity_ui_components.xml b/sample_kautomator/src/main/res/layout/activity_ui_components.xml new file mode 100644 index 000000000..ae6308858 --- /dev/null +++ b/sample_kautomator/src/main/res/layout/activity_ui_components.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/sample_kautomator/src/main/res/menu/bottom_nav_menu.xml b/sample_kautomator/src/main/res/menu/bottom_nav_menu.xml new file mode 100644 index 000000000..bbc80fa66 --- /dev/null +++ b/sample_kautomator/src/main/res/menu/bottom_nav_menu.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/sample_kautomator/src/main/res/values/strings.xml b/sample_kautomator/src/main/res/values/strings.xml index 3b28135a2..55d620992 100644 --- a/sample_kautomator/src/main/res/values/strings.xml +++ b/sample_kautomator/src/main/res/values/strings.xml @@ -3,4 +3,7 @@ Sample of UiAutomator dsl Button CheckBox + + Menu Item 1 + Menu Item 2