├── .circleci
└── config.yml
├── .gitignore
├── .idea
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
└── dictionaries
│ └── dsvor.xml
├── LICENSE
├── README.md
├── _config.yml
├── build.gradle.kts
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
├── test-app
├── README.md
├── build.gradle.kts
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── avito
│ │ └── android
│ │ └── ui
│ │ └── test
│ │ ├── AppBarScreen.kt
│ │ ├── AppBarTest.kt
│ │ ├── BackgroundDrawableScreen.kt
│ │ ├── BackgroundDrawableTest.kt
│ │ ├── ButtonsOverRecyclerScreen.kt
│ │ ├── ButtonsOverRecyclerTest.kt
│ │ ├── ButtonsOverRecyclerWithCollapsingToolbarTest.kt
│ │ ├── ButtonsScreen.kt
│ │ ├── ButtonsTest.kt
│ │ ├── DisplayedWithTextTest.kt
│ │ ├── DistantViewOnScrollScreen.kt
│ │ ├── EditTextScreen.kt
│ │ ├── EditTextTest.kt
│ │ ├── GodRuleChain.kt
│ │ ├── IdenticalCellsRecyclerScreen.kt
│ │ ├── IdenticalCellsRecyclerTest.kt
│ │ ├── InterceptorTest.kt
│ │ ├── LongRecyclerScreen.kt
│ │ ├── LongRecyclerTest.kt
│ │ ├── MovingButtonScreen.kt
│ │ ├── MovingButtonTest.kt
│ │ ├── OverflowMenuScreen.kt
│ │ ├── OverflowMenuTest.kt
│ │ ├── ReadTextTest.kt
│ │ ├── RecyclerAsLayoutScreen.kt
│ │ ├── RecyclerAsLayoutTest.kt
│ │ ├── RecyclerInRecyclerLayoutScreen.kt
│ │ ├── RecyclerInRecyclerTest.kt
│ │ ├── RecyclerWithSingleLongItemScreen.kt
│ │ ├── RecyclerWithSingleLongItemTest.kt
│ │ ├── Screen.kt
│ │ ├── ScreenRule.kt
│ │ ├── ScrollViewScrollToEndTest.kt
│ │ ├── StatefulRecyclerViewAdapterScreen.kt
│ │ ├── StatefulRecyclerViewAdapterTest.kt
│ │ ├── SwipeRefreshScreen.kt
│ │ ├── SwipeRefreshTest.kt
│ │ ├── TabLayoutScreen.kt
│ │ ├── TabLayoutTest.kt
│ │ ├── TextElementsScreen.kt
│ │ ├── TextElementsTest.kt
│ │ ├── UITestRunner.kt
│ │ ├── ViewPagerScreen.kt
│ │ ├── ViewPagerTest.kt
│ │ ├── VisibilityScreen.kt
│ │ └── VisibilityTest.kt
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── avito
│ │ └── android
│ │ └── ui
│ │ ├── AppBarActivity.kt
│ │ ├── ButtonsActivity.kt
│ │ ├── ButtonsOverRecyclerActivity.kt
│ │ ├── ButtonsOverRecyclerWithCollapsingToolbarActivity.kt
│ │ ├── DistantViewOnScrollActivity.kt
│ │ ├── DrawableActivity.kt
│ │ ├── EditTextActivity.kt
│ │ ├── IdenticalCellsRecyclerActivity.kt
│ │ ├── LongRecyclerActivity.kt
│ │ ├── MovingButtonActivity.kt
│ │ ├── OverflowMenuActivity.kt
│ │ ├── RecyclerAsLayoutActivity.kt
│ │ ├── RecyclerInRecyclerActivity.kt
│ │ ├── RecyclerWithLongItemsActivity.kt
│ │ ├── StatefulRecyclerViewAdapterActivity.kt
│ │ ├── SwipeRefreshActivity.kt
│ │ ├── TabLayoutActivity.kt
│ │ ├── TextElementActivity.kt
│ │ ├── View.kt
│ │ ├── ViewPagerActivity.kt
│ │ └── VisibilityActivity.kt
│ └── res
│ ├── drawable
│ └── ic_check_black_24dp.xml
│ ├── layout
│ ├── activity_app_bar.xml
│ ├── activity_buttons.xml
│ ├── activity_buttons_over_recycler.xml
│ ├── activity_buttons_over_recycler_with_collapsing_toolbar.xml
│ ├── activity_distant_view_on_scroll.xml
│ ├── activity_drawable.xml
│ ├── activity_edittext.xml
│ ├── activity_moving_button.xml
│ ├── activity_overflow.xml
│ ├── activity_recycler.xml
│ ├── activity_swipe_refresh.xml
│ ├── activity_tab_layout.xml
│ ├── activity_text_elements.xml
│ ├── activity_view_pager.xml
│ ├── activity_visibility.xml
│ ├── cell.xml
│ ├── cell_with_edit_text.xml
│ ├── cell_with_inner_recycler.xml
│ ├── cell_with_multiple_text_views.xml
│ ├── cell_with_text_input.xml
│ ├── long_item.xml
│ ├── long_recycler.xml
│ ├── view_pager_even_item.xml
│ └── view_pager_odd_item.xml
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ └── values
│ └── color.xml
├── ui-testing-core
├── build.gradle.kts
├── lint.xml
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ ├── androidx
│ │ └── test
│ │ │ └── espresso
│ │ │ ├── action
│ │ │ └── SwipeDirection.kt
│ │ │ └── assertion
│ │ │ ├── HumanReadables.kt
│ │ │ └── isDoesntExistAssertion.kt
│ │ └── com
│ │ └── avito
│ │ └── android
│ │ └── test
│ │ ├── Device.kt
│ │ ├── Intents.kt
│ │ ├── InteractionContext.kt
│ │ ├── UITestConfig.kt
│ │ ├── Waiter.kt
│ │ ├── action
│ │ ├── Actions.kt
│ │ ├── ActionsDriver.kt
│ │ ├── ActionsImpl.kt
│ │ ├── InteractionContextMatcherActions.kt
│ │ ├── InteractionContextPositionActions.kt
│ │ ├── OnDescendantMatcherListItemActions.kt
│ │ ├── OnDescendantPositionListItemActions.kt
│ │ ├── OnViewActionsDriver.kt
│ │ └── WebElementActions.kt
│ │ ├── checks
│ │ ├── Checks.kt
│ │ ├── ChecksDriver.kt
│ │ ├── ChecksImpl.kt
│ │ ├── InteractionContextMatcherChecksDriver.kt
│ │ ├── InteractionContextPositionChecksDriver.kt
│ │ ├── LabelChecks.kt
│ │ ├── LabelChecksImpl.kt
│ │ ├── OnDescendantMatcherListItemChecksDriver.kt
│ │ ├── OnDescendantPositionListItemChecksDriver.kt
│ │ ├── OnViewChecksDriver.kt
│ │ ├── PasswordFieldChecks.kt
│ │ ├── TextFieldErrorChecks.kt
│ │ ├── TextFieldHintChecks.kt
│ │ └── WebElementChecks.kt
│ │ ├── element
│ │ └── field
│ │ │ ├── TextFieldAction.kt
│ │ │ ├── TextFieldChecks.kt
│ │ │ ├── TextFieldElement.kt
│ │ │ └── actions
│ │ │ └── TypeText.kt
│ │ ├── espresso
│ │ ├── EspressoActions.kt
│ │ ├── action
│ │ │ ├── ActionOnClickableElement.kt
│ │ │ ├── ActionOnEnabledElement.kt
│ │ │ ├── ActionOnLongClickableElement.kt
│ │ │ ├── CollapseAppBarAction.kt
│ │ │ ├── GroupedViewAction.kt
│ │ │ ├── OrientationChangeAction.kt
│ │ │ ├── RecyclerSpanCountAction.kt
│ │ │ ├── RecyclerViewHorizontalOffsetAction.kt
│ │ │ ├── RecyclerViewItemsCountAction.kt
│ │ │ ├── RecyclerViewVerticalOffsetAction.kt
│ │ │ ├── TextViewReadAction.kt
│ │ │ ├── ToolbarReadMenuItemsAction.kt
│ │ │ ├── ViewGetHeightAction.kt
│ │ │ ├── ViewGetTranslationYAction.kt
│ │ │ ├── ViewPagersFlipAction.kt
│ │ │ ├── ViewPagersSelectAction.kt
│ │ │ ├── WaitForIdleAction.kt
│ │ │ ├── click
│ │ │ │ ├── ClickAction.kt
│ │ │ │ └── Event.kt
│ │ │ ├── recycler
│ │ │ │ ├── RecyclerViewActions.kt
│ │ │ │ ├── RecyclerViewScroll.kt
│ │ │ │ └── ViewHolderItemMatching.kt
│ │ │ └── scroll
│ │ │ │ ├── Scroll.kt
│ │ │ │ └── ScrollToIfPossibleAction.kt
│ │ └── assertion
│ │ │ └── ViewExistsAssertion.kt
│ │ ├── interceptor
│ │ ├── HumanReadableInterceptor.kt
│ │ └── Interceptor.kt
│ │ ├── internal
│ │ ├── Cache.kt
│ │ ├── SQLiteDB.kt
│ │ └── SharedPreferences.kt
│ │ ├── matcher
│ │ ├── AlphaMatcher.kt
│ │ ├── AvitoPositionAssertions.kt
│ │ ├── CanBeClickedMatcher.kt
│ │ ├── CanBeLongClickedMatcher.kt
│ │ ├── CollapsingToolbarTitleMatcher.kt
│ │ ├── CompoundDrawableMatcher.kt
│ │ ├── DrawableBackgroundMatcher.kt
│ │ ├── DrawableMatcher.kt
│ │ ├── DrawableMatcherActionIcon.kt
│ │ ├── DrawableMatcherCheckableImageView.kt
│ │ ├── DrawableMatcherImageButton.kt
│ │ ├── FocusableInTouchModeMatcher.kt
│ │ ├── HintMatcher.kt
│ │ ├── ImageShownMatcher.kt
│ │ ├── IsAssignableFromMatcher.kt
│ │ ├── IsRefreshingMatcher.kt
│ │ ├── NoViewMatcher.kt
│ │ ├── RecyclerViewMatcher.kt
│ │ ├── StringPatternMatcher.kt
│ │ ├── TabLayoutSelectMatcher.kt
│ │ ├── TabLayoutTabsCountMatcher.kt
│ │ ├── TextInputLayoutErrorMatcher.kt
│ │ ├── TextInputLayoutHintMatcher.kt
│ │ ├── TextInputPasswordVisibilityMatcher.kt
│ │ ├── TextViewLinesMatcher.kt
│ │ ├── ToolbarSubTitleResMatcher.kt
│ │ ├── ToolbarSubtitleMatcher.kt
│ │ ├── ToolbarTitleMatcher.kt
│ │ ├── ToolbarTitleResMatcher.kt
│ │ ├── UniversalCheckedMatcher.kt
│ │ ├── ViewGroupMatcher.kt
│ │ ├── ViewMatchers.kt
│ │ ├── ViewPagersSelectMatcher.kt
│ │ ├── ViewPagersTabsCountMatcher.kt
│ │ └── WithHintEndingMatcher.kt
│ │ ├── page_object
│ │ ├── Alert.kt
│ │ ├── AppBarElement.kt
│ │ ├── FloatingViewElement.kt
│ │ ├── ImageViewElement.kt
│ │ ├── KeyboardElement.kt
│ │ ├── ListElement.kt
│ │ ├── PageObjectElement.kt
│ │ ├── ProgressBarElement.kt
│ │ ├── RatingBarElement.kt
│ │ ├── SnackbarElement.kt
│ │ ├── SwipeRefreshElement.kt
│ │ ├── SwitchElement.kt
│ │ ├── TabLayoutElement.kt
│ │ ├── TextElement.kt
│ │ ├── TextInputElement.kt
│ │ ├── ToolbarElement.kt
│ │ ├── ToolbarMenuElement.kt
│ │ ├── ViewPagerElement.kt
│ │ └── WebView.kt
│ │ ├── screenshot
│ │ ├── ScreenshotConsumer.kt
│ │ ├── ScreenshotProvider.kt
│ │ ├── ScreenshotRule.kt
│ │ └── SuppressScreenshot.kt
│ │ └── util
│ │ ├── AppendableDescription.kt
│ │ ├── ClickTypeRule.kt
│ │ ├── Context.kt
│ │ ├── Drawables.kt
│ │ ├── HumanReadables.kt
│ │ ├── Instrumentations.kt
│ │ ├── Reflection.kt
│ │ └── View.kt
│ └── test
│ └── java
│ └── com
│ └── avito
│ └── android
│ └── test
│ └── util
│ └── ReflectionTests.kt
└── ui-testing-maps
├── build.gradle.kts
├── lint.xml
└── src
└── main
├── AndroidManifest.xml
└── java
└── com.avito.android.test.maps
├── Exception.kt
├── GoogleMapActions.kt
├── GoogleMapChecks.kt
├── GoogleMapFragmentElement.kt
├── GoogleMapMatchers.kt
└── provider
├── FragmentGoogleMapProvider.kt
└── GoogleMapProvider.kt
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle/
3 | *build/
4 | local.properties
5 | **/.idea/*
6 | !.idea/codeStyles
7 | !.idea/inspectionProfiles
8 | !.idea/dictionaries
9 | **/gen/*
10 | captures/*
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/dictionaries/dsvor.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | avito
5 |
6 |
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Dmitriy Voronin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [ARCHIVED] Avito Android UI testing library
2 |
3 | See https://github.com/avito-tech/avito-android for this library as part of a bigger project.
4 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-minimal
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | android.useAndroidX=true
2 | android.enableJetifier=false
3 | minSdk=18
4 | targetSdk=28
5 | # versions
6 | androidGradlePluginVersion=3.5.0
7 | kotlinVersion=1.3.50
8 | playServicesVersion=17.0.0
9 | materialVersion=1.0.0
10 | junitVersion=4.12
11 | # jetpack
12 | appcompatVersion=1.0.2
13 | recyclerViewVersion=1.0.0
14 | # test versions
15 | androidXTestVersion=1.2.0
16 | espressoVersion=3.1.0
17 | uiAutomatorVersion=2.2.0
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/avito-tech/android-ui-testing/3fa67bd425cb7ae38b2c4687e8e8ee9e6104ff2e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | val kotlinVersion: String by settings
2 | val androidGradlePluginVersion: String by settings
3 |
4 | pluginManagement {
5 | repositories {
6 | gradlePluginPortal()
7 | google()
8 | }
9 | resolutionStrategy {
10 | eachPlugin {
11 | val pluginId = requested.id.id
12 | when {
13 | pluginId.startsWith("com.android.") ->
14 | useModule("com.android.tools.build:gradle:$androidGradlePluginVersion")
15 |
16 | pluginId.startsWith("org.jetbrains.kotlin.") ->
17 | useVersion(kotlinVersion)
18 | }
19 | }
20 | }
21 | }
22 |
23 | rootProject.buildFileName = "build.gradle.kts"
24 |
25 | include(":ui-testing-core")
26 | include(":ui-testing-maps")
27 | include(":test-app")
28 |
--------------------------------------------------------------------------------
/test-app/README.md:
--------------------------------------------------------------------------------
1 | Tests for test-ui library
--------------------------------------------------------------------------------
/test-app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | val targetSdk: String by project
2 | val minSdk: String by project
3 |
4 | val kotlinVersion: String by project
5 | val playServicesVersion: String by project
6 | val appcompatVersion: String by project
7 | val recyclerViewVersion: String by project
8 | val materialVersion: String by project
9 |
10 | plugins {
11 | id("com.android.application")
12 | kotlin("android")
13 | }
14 |
15 | android {
16 | compileSdkVersion(targetSdk.toInt())
17 |
18 | defaultConfig {
19 | minSdkVersion(minSdk)
20 | targetSdkVersion(targetSdk.toInt())
21 | testInstrumentationRunner = "com.avito.android.ui.test.UITestRunner"
22 | }
23 |
24 | buildTypes {
25 | getByName("debug") {
26 | matchingFallbacks = listOf("release")
27 | }
28 | }
29 |
30 | variantFilter {
31 | if (name == "release") {
32 | setIgnore(true)
33 | }
34 | }
35 |
36 | packagingOptions {
37 | pickFirst("protobuf.meta")
38 | }
39 | }
40 |
41 | dependencies {
42 | implementation(kotlin("stdlib", kotlinVersion))
43 | implementation("com.google.android.gms:play-services-maps:$playServicesVersion")
44 |
45 | api("androidx.appcompat:appcompat:$appcompatVersion")
46 | api("androidx.recyclerview:recyclerview:$recyclerViewVersion")
47 | api("com.google.android.material:material:$materialVersion")
48 |
49 | androidTestImplementation(project(":ui-testing-core"))
50 | }
51 |
52 | tasks.getByName("build").dependsOn("$path:assembleAndroidTest")
53 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/AppBarScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.page_object.AppBarElement
5 | import com.avito.android.test.page_object.PageObject
6 | import com.avito.android.test.page_object.ViewElement
7 | import com.avito.android.ui.R
8 |
9 | class AppBarScreen : PageObject() {
10 | val appBar: AppBarElement = element(withId(R.id.appbar))
11 | val testView: ViewElement = element(withId(R.id.view_in_collapsing_toolbar))
12 | }
13 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/AppBarTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.AppBarActivity
4 | import org.junit.Rule
5 | import org.junit.Test
6 |
7 | class AppBarTest {
8 |
9 | @get:Rule
10 | val rule = screenRule()
11 |
12 | @Test
13 | fun collapse_collapsesViews() {
14 | rule.launchActivity(null)
15 |
16 | rule.activity.setExpanded(true)
17 |
18 | Screen.appBarScreen.appBar.actions.collapse()
19 | Screen.appBarScreen.testView.checks.isNotCompletelyDisplayed()
20 | }
21 |
22 | @Test
23 | fun expand_showsViews() {
24 | rule.launchActivity(null)
25 |
26 | rule.activity.setExpanded(false)
27 |
28 | Screen.appBarScreen.appBar.actions.expand()
29 | Screen.appBarScreen.testView.checks.isCompletelyDisplayed()
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/BackgroundDrawableScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.page_object.PageObject
5 | import com.avito.android.test.page_object.ViewElement
6 | import com.avito.android.ui.R
7 |
8 | class BackgroundDrawableScreen : PageObject() {
9 | val viewWithBackgroundRedColor: ViewElement = element(withId(R.id.background_view_color))
10 | val viewWithBackgroundCheckIcon: ViewElement = element(withId(R.id.background_view_image))
11 | }
12 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/BackgroundDrawableTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.DrawableActivity
4 | import com.avito.android.ui.R
5 | import org.junit.Rule
6 | import org.junit.Test
7 |
8 | class BackgroundDrawableTest {
9 |
10 | @get:Rule
11 | val rule = screenRule(launchActivity = true)
12 |
13 | @Test
14 | fun backgroundDrawable_matches_whenBackgroundIsColorResource() {
15 | Screen.backgroundDrawableScreen.viewWithBackgroundRedColor.checks.hasBackground(R.color.red)
16 | }
17 |
18 | @Test
19 | fun backgroundDrawable_matches_whenBackgroundIsIconResource() {
20 | Screen.backgroundDrawableScreen.viewWithBackgroundCheckIcon.checks
21 | .hasBackground(R.drawable.ic_check_black_24dp)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/ButtonsOverRecyclerScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import android.widget.FrameLayout
4 | import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
5 | import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
6 | import androidx.test.espresso.matcher.ViewMatchers.withId
7 | import androidx.test.espresso.matcher.ViewMatchers.withText
8 | import com.avito.android.test.InteractionContext
9 | import com.avito.android.test.page_object.ListElement
10 | import com.avito.android.test.page_object.PageObject
11 | import com.avito.android.test.page_object.ViewElement
12 | import com.avito.android.ui.R
13 |
14 | class ButtonsOverRecyclerScreen : PageObject() {
15 |
16 | val list: List = element(withId(R.id.recycler))
17 |
18 | class List(interactionContext: InteractionContext) : ListElement(interactionContext) {
19 |
20 | fun cellWithTitle(title: String): Cell = listElement(hasDescendant(withText(title)))
21 | fun cellAt(position: Int): Cell =
22 | listElement(isAssignableFrom(FrameLayout::class.java), position)
23 |
24 | class Cell(interactionContext: InteractionContext) : ViewElement(interactionContext) {
25 | val title: ViewElement = element(withId(R.id.title))
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/ButtonsOverRecyclerTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.action.SwipeDirections
4 | import com.avito.android.ui.ButtonsOverRecyclerActivity
5 | import org.hamcrest.Matchers.equalTo
6 | import org.hamcrest.Matchers.greaterThan
7 | import org.junit.Rule
8 | import org.junit.Test
9 |
10 | class ButtonsOverRecyclerTest {
11 |
12 | @get:Rule
13 | val rule = screenRule(launchActivity = true)
14 |
15 | @Test
16 | fun listElement_swipe_RecyclerViewBehindButtons() {
17 | with(Screen.buttonsOverRecycler.list) {
18 | actions.swipe(SwipeDirections.BOTTOM_TO_TOP)
19 | checks.firstVisiblePosition(greaterThan(0))
20 | // on some devices swipe to top may end on half way
21 | repeat(3) { actions.swipe(SwipeDirections.TOP_TO_BOTTOM) }
22 | checks.firstVisiblePosition(equalTo(0))
23 | }
24 | }
25 |
26 | @Test
27 | fun listElement_elementClicked_whenThereIsOverlappedButton() {
28 | Screen.buttonsOverRecycler.list.cellAt(60).click()
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/ButtonsOverRecyclerWithCollapsingToolbarTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.ButtonsOverRecyclerWithCollapsingToolbarActivity
4 | import org.junit.Rule
5 | import org.junit.Test
6 |
7 | class ButtonsOverRecyclerWithCollapsingToolbarTest {
8 |
9 | @get:Rule
10 | val rule = screenRule(launchActivity = true)
11 |
12 | @Test
13 | fun listElement_elementClicked_whenThereIsOverlappedButtonInScreenWithCollapsingToolbar() {
14 | Screen.buttonsOverRecycler.list.cellAt(90).click()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/ButtonsScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import androidx.test.espresso.matcher.ViewMatchers.withText
5 | import com.avito.android.test.page_object.PageObject
6 | import com.avito.android.test.page_object.ViewElement
7 | import com.avito.android.ui.R
8 |
9 | class ButtonsScreen : PageObject() {
10 | val enabledButton: ViewElement = element(withId(R.id.button_enabled))
11 | val enabledButtonClickIndicatorView: ViewElement = element(
12 | withId(R.id.button_enabled_clicked_text_view)
13 | )
14 | val enabledButtonLongClickIndicatorView: ViewElement = element(
15 | withId(R.id.button_enabled_long_clicked_text_view)
16 | )
17 | val disabledButton: ViewElement = element(withId(R.id.button_disabled))
18 | val nonClickableButton: ViewElement = element(withId(R.id.button_non_clickable))
19 |
20 | val clickableContainerInnerButton: ViewElement = element(withText("Non clickable inside clickable"))
21 | val clickableContainerIndicator: ViewElement = element(withId(R.id.clickable_container_indicator))
22 |
23 | val nonLongClickableButton: ViewElement = element(withId(R.id.button_non_long_clickable))
24 | val nonLongClickableButtonIndicator: ViewElement = element(
25 | withId(R.id.button_non_long_clickable_clicked_text_view)
26 | )
27 |
28 | val longClickableContainerInnerButton: ViewElement = element(withText("Non long-clickable inside long-clickable"))
29 | val longClickableContainerIndicator: ViewElement = element(withId(R.id.long_clickable_container_indicator))
30 | }
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/DisplayedWithTextTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.IdenticalCellsRecyclerActivity
4 | import org.hamcrest.Matchers
5 | import org.junit.Rule
6 | import org.junit.Test
7 |
8 | class DisplayedWithTextTest {
9 |
10 | @get:Rule
11 | val rule = screenRule()
12 |
13 | @Test
14 | fun canAssertText_onFoundItem() {
15 | rule.launchActivity(IdenticalCellsRecyclerActivity.intent(arrayListOf("test string")))
16 |
17 | Screen.identicalCellsRecycler.list.cellAt(position = 0)
18 | .title.checks.displayedWithText("test string")
19 | }
20 |
21 | @Test
22 | fun canAssertTextWithMatcher_onFoundItem() {
23 | rule.launchActivity(IdenticalCellsRecyclerActivity.intent(arrayListOf("test string")))
24 |
25 | Screen.identicalCellsRecycler.list.cellAt(position = 0)
26 | .title.checks.displayedWithText(Matchers.startsWith("test"))
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/DistantViewOnScrollScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.page_object.PageObject
5 | import com.avito.android.test.page_object.ViewElement
6 | import com.avito.android.ui.R
7 |
8 | class DistantViewOnScrollScreen : PageObject() {
9 | val scroll: ViewElement = ViewElement(withId(R.id.scroll))
10 | val view: ViewElement = element(withId(R.id.view))
11 | }
12 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/EditTextScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.element.field.TextFieldElement
5 | import com.avito.android.test.page_object.PageObject
6 | import com.avito.android.ui.R
7 |
8 | class EditTextScreen : PageObject() {
9 | val editText: TextFieldElement = element(withId(R.id.edit_text))
10 | val editText1: TextFieldElement = element(withId(R.id.edit_text1))
11 | val phoneNumberText: TextFieldElement = element(withId(R.id.phone_number_edit_text1))
12 | }
13 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/EditTextTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.test.Device
4 | import com.avito.android.ui.EditTextActivity
5 | import org.junit.Rule
6 | import org.junit.Test
7 |
8 | class EditTextTest {
9 |
10 | @get:Rule
11 | val rule = screenRule()
12 |
13 | @Test
14 | fun findsKeyboard_whenKeyboardIsOpenedByActivityManifest() = with(rule) {
15 | launchActivity(null)
16 |
17 | Device.keyboard.checks.isDisplayed(activity)
18 | }
19 |
20 | @Test
21 | fun writesToInputWithFormatting() = with(rule) {
22 | launchActivity(null)
23 |
24 | Screen.editTextScreen.phoneNumberText.write("9261418698")
25 | Screen.editTextScreen.phoneNumberText.checks.displayedWithText("(926) 141-8698")
26 | }
27 |
28 | @Test
29 | fun writesCyrillicText() = with(rule) {
30 | launchActivity(null)
31 |
32 | Screen.editTextScreen.editText1.write("Кирилл и Мефодий не изобретали кириллицу")
33 | Screen.editTextScreen.editText1.checks.displayedWithText("Кирилл и Мефодий не изобретали кириллицу")
34 | }
35 |
36 | @Test
37 | fun writesLongText() = with(rule) {
38 | launchActivity(null)
39 |
40 | val superLongText = StringBuilder()
41 | .apply {
42 | (0..100000)
43 | .forEach { _ ->
44 | append("a")
45 | }
46 | }
47 | .toString()
48 |
49 | Screen.editTextScreen.editText.write(superLongText)
50 | Screen.editTextScreen.editText.checks.displayedWithText(superLongText)
51 | }
52 |
53 | @Test
54 | fun writesEmptyText() = with(rule) {
55 | launchActivity(null)
56 |
57 | Screen.editTextScreen.editText.write("")
58 | Screen.editTextScreen.editText.checks.displayedWithText("")
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/GodRuleChain.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import android.app.Activity
4 | import android.app.Instrumentation
5 | import android.content.Intent
6 | import androidx.test.rule.ActivityTestRule
7 | import org.junit.rules.RuleChain
8 | import org.junit.rules.TestRule
9 | import org.junit.runner.Description
10 | import org.junit.runners.model.Statement
11 |
12 | /**
13 | * RuleChain with exposed methods and fields from it's rules
14 | */
15 | class GodRuleChain(private val chain: RuleChain) :
16 | TestRule {
17 |
18 | @Suppress("UNCHECKED_CAST")
19 | private val rules = chain.javaClass.getDeclaredField("rulesStartingWithInnerMost")
20 | .apply { isAccessible = true }.get(chain) as List
21 |
22 | private val activityTestRule = rules.filterIsInstance>().first()
23 |
24 | val activity: T
25 | get() = activityTestRule.activity
26 |
27 | val activityResult: Instrumentation.ActivityResult
28 | get() = activityTestRule.activityResult
29 |
30 | fun runOnUiThread(runnable: () -> Unit) = activityTestRule.runOnUiThread(runnable)
31 |
32 | fun launchActivity(intent: Intent?): T = activityTestRule.launchActivity(intent)
33 |
34 | fun launchActivity(func: (Intent) -> Intent): T =
35 | activityTestRule.launchActivity(func(Intent(Intent.ACTION_MAIN)))
36 |
37 | override fun apply(base: Statement?, description: Description?): Statement {
38 | return chain.apply(base, description)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/IdenticalCellsRecyclerScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import android.widget.FrameLayout
4 | import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
5 | import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
6 | import androidx.test.espresso.matcher.ViewMatchers.withId
7 | import androidx.test.espresso.matcher.ViewMatchers.withText
8 | import com.avito.android.test.InteractionContext
9 | import com.avito.android.test.page_object.ListElement
10 | import com.avito.android.test.page_object.PageObject
11 | import com.avito.android.test.page_object.ViewElement
12 | import com.avito.android.ui.R
13 |
14 | class IdenticalCellsRecyclerScreen : PageObject() {
15 |
16 | val list: List = element(withId(R.id.recycler))
17 |
18 | class List(interactionContext: InteractionContext) : ListElement(interactionContext) {
19 |
20 | fun cellWithTitle(title: String): Cell = listElement(hasDescendant(withText(title)))
21 | fun cellAt(position: Int): Cell =
22 | listElement(isAssignableFrom(FrameLayout::class.java), position)
23 |
24 | class Cell(interactionContext: InteractionContext) : ViewElement(interactionContext) {
25 | val title: ViewElement = element(withId(R.id.title))
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/IdenticalCellsRecyclerTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.IdenticalCellsRecyclerActivity
4 | import org.junit.Rule
5 | import org.junit.Test
6 |
7 | class IdenticalCellsRecyclerTest {
8 |
9 | @get:Rule
10 | val rule = screenRule()
11 |
12 | @Test
13 | fun typedItemWithMatcher_foundSecondItem_withAllDifferentValues() {
14 | rule.launchActivity(IdenticalCellsRecyclerActivity.intent(arrayListOf("1", "2", "3")))
15 |
16 | Screen.identicalCellsRecycler.list.cellWithTitle("2").title.checks.displayedWithText("2")
17 | }
18 |
19 | @Test
20 | fun typedItemWithMatcher_failedToFailValues_withIdenticalValues() {
21 | rule.launchActivity(IdenticalCellsRecyclerActivity.intent(arrayListOf("2", "2", "2")))
22 |
23 | Screen.identicalCellsRecycler.list.cellWithTitle("2").title.checks.displayedWithText("2")
24 | }
25 |
26 | @Test
27 | fun typedItemAtPosition_foundSecondItem_withAllDifferentValues() {
28 | rule.launchActivity(IdenticalCellsRecyclerActivity.intent(arrayListOf("1", "2", "3")))
29 |
30 | Screen.identicalCellsRecycler.list.cellAt(position = 1).title.checks.displayedWithText("2")
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/InterceptorTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.test.UITestConfig
4 | import com.avito.android.test.interceptor.HumanReadableActionInterceptor
5 | import com.avito.android.test.interceptor.HumanReadableAssertionInterceptor
6 | import com.avito.android.ui.VisibilityActivity
7 | import org.junit.Assert
8 | import org.junit.Rule
9 | import org.junit.Test
10 |
11 | class InterceptorTest {
12 |
13 | @get:Rule
14 | val rule = screenRule(true)
15 |
16 | @Test
17 | fun actionInterceptor_intercepts_clickAction() {
18 | var intercepted = ""
19 |
20 | UITestConfig.actionInterceptors += HumanReadableActionInterceptor { intercepted = it }
21 | Screen.visibility.label.click()
22 |
23 | Assert.assertEquals("single click on clickable element on enabled element on AppCompatTextView(id=text;text=Test)", intercepted)
24 | }
25 |
26 | @Test
27 | fun assertionInterceptor_intercepts_visibleCheck() {
28 | var intercepted = ""
29 |
30 | UITestConfig.assertionInterceptors += HumanReadableAssertionInterceptor { intercepted = it }
31 |
32 | Screen.visibility.label.checks.isVisible()
33 |
34 | Assert.assertEquals(
35 | "Check view has effective visibility=VISIBLE on AppCompatTextView(id=text;text=Test)",
36 | intercepted
37 | )
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/LongRecyclerScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.page_object.ListElement
5 | import com.avito.android.test.page_object.PageObject
6 | import com.avito.android.ui.R
7 |
8 | class LongRecyclerScreen : PageObject() {
9 | val list: ListElement = element(withId(R.id.recycler))
10 | }
11 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/LongRecyclerTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.LongRecyclerActivity
4 | import com.avito.android.ui.RecyclerAsLayoutActivity
5 | import org.hamcrest.Matchers.greaterThan
6 | import org.junit.Rule
7 | import org.junit.Test
8 |
9 | class LongRecyclerTest {
10 |
11 | @get:Rule
12 | val rule = screenRule()
13 |
14 | private fun givenItemsList(n: Int) = (0..n).asSequence().map { "label_$it" }.toList()
15 |
16 | @Test
17 | fun textInput_isAccessible() {
18 |
19 | val itemsCount = 500
20 |
21 | rule.launchActivity(
22 | RecyclerAsLayoutActivity.intent(
23 | arrayListOf().apply { addAll(givenItemsList(itemsCount)) }
24 | )
25 | )
26 |
27 | Screen.longRecycler.list.actions.smoothScrollToPosition(itemsCount)
28 | Thread.sleep(1000L)
29 |
30 | Screen.longRecycler.list.checks.firstVisiblePosition(greaterThan(400))
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/MovingButtonScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers
4 | import com.avito.android.test.page_object.PageObject
5 | import com.avito.android.test.page_object.ViewElement
6 | import com.avito.android.ui.R
7 |
8 | class MovingButtonScreen : PageObject() {
9 | val movedButton: ViewElement = element(ViewMatchers.withId(R.id.moving_button))
10 | val movedButtonClickIndicatorView: ViewElement =
11 | element(ViewMatchers.withId(R.id.moving_button_clicked_text_view))
12 | }
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/MovingButtonTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.MovingButtonActivity
4 | import org.junit.Rule
5 | import org.junit.Test
6 |
7 | class MovingButtonTest {
8 |
9 | @get:Rule
10 | val rule = screenRule(launchActivity = true)
11 |
12 | @Test
13 | fun movingButton_clicked() {
14 | Screen.movingButton.movedButton.click()
15 | Screen.movingButton.movedButtonClickIndicatorView.checks.isDisplayed()
16 | }
17 | }
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/OverflowMenuScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.page_object.PageObject
5 | import com.avito.android.test.page_object.ToolbarElement
6 | import com.avito.android.test.page_object.ViewElement
7 | import com.avito.android.ui.R
8 |
9 | class OverflowMenuScreen : PageObject() {
10 |
11 | val toolbar: Toolbar = element()
12 | val label: ViewElement = element(withId(R.id.text))
13 |
14 | class Toolbar : ToolbarElement() {
15 | val menuItem = actionMenuItem("check")
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/OverflowMenuTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import android.view.MenuItem
4 | import androidx.test.espresso.NoMatchingViewException
5 | import com.avito.android.ui.OverflowMenuActivity
6 | import org.junit.Rule
7 | import org.junit.Test
8 | import org.junit.rules.ExpectedException
9 |
10 | class OverflowMenuTest {
11 |
12 | @get:Rule
13 | val rule = screenRule()
14 |
15 | @get:Rule
16 | val exception: ExpectedException = ExpectedException.none()
17 |
18 | @Test
19 | fun menuItem_isClickable_inActionMenu() {
20 | val label = "ACTION CLICKED"
21 | rule.launchActivity(OverflowMenuActivity.intent(MenuItem.SHOW_AS_ACTION_ALWAYS, label))
22 |
23 | Screen.overflow.toolbar.menuItem.actions.click()
24 | Screen.overflow.label.checks.displayedWithText(label)
25 | }
26 |
27 | @Test
28 | fun menuItem_isClickable_inOverflowMenu() {
29 | val label = "OVERFLOW CLICKED"
30 | rule.launchActivity(OverflowMenuActivity.intent(MenuItem.SHOW_AS_ACTION_NEVER, label))
31 |
32 | Screen.overflow.toolbar.menuItem.actions.click()
33 | Screen.overflow.label.checks.displayedWithText(label)
34 | }
35 |
36 | @Test
37 | fun menuItem_notFound_inOverflowMenuWithNoAutoClick() {
38 | rule.launchActivity(
39 | OverflowMenuActivity.intent(
40 | MenuItem.SHOW_AS_ACTION_NEVER,
41 | "doesn't matter"
42 | )
43 | )
44 |
45 | exception.expect(NoMatchingViewException::class.java)
46 | exception.expectMessage("No views in hierarchy found matching: with text")
47 | Screen.overflow.toolbar.menuItem.disableOverflowMenuAutoOpen().actions.click()
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/RecyclerAsLayoutScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.InteractionContext
5 | import com.avito.android.test.element.field.TextFieldElement
6 | import com.avito.android.test.page_object.ListElement
7 | import com.avito.android.test.page_object.PageObject
8 | import com.avito.android.test.page_object.TextInputElement
9 | import com.avito.android.test.page_object.ViewElement
10 | import com.avito.android.ui.R
11 |
12 | class RecyclerAsLayoutScreen : PageObject() {
13 |
14 | val list: List = element(withId(R.id.recycler))
15 |
16 | class List(interactionContext: InteractionContext) : ListElement(interactionContext) {
17 | val inputField: TextInputElement = listElement(withId(R.id.input_layout))
18 | val editText: TextFieldElement = listElement(withId(R.id.edit_text))
19 | val label: ViewElement = listElement(withId(R.id.title))
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/RecyclerAsLayoutTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.RecyclerAsLayoutActivity
4 | import org.junit.Rule
5 | import org.junit.Test
6 |
7 | class RecyclerAsLayoutTest {
8 |
9 | @get:Rule
10 | val rule = screenRule()
11 |
12 | @Test
13 | fun label_isAccessible() {
14 | rule.launchActivity(
15 | RecyclerAsLayoutActivity.intent(
16 | arrayListOf(
17 | "input",
18 | "editText",
19 | "label"
20 | )
21 | )
22 | )
23 |
24 | Screen.recyclerAsLayout.list.label.checks.withText("label")
25 | }
26 |
27 | @Test
28 | fun editText_isAccessible() {
29 | rule.launchActivity(
30 | RecyclerAsLayoutActivity.intent(
31 | arrayListOf(
32 | "input",
33 | "editText",
34 | "label"
35 | )
36 | )
37 | )
38 |
39 | Screen.recyclerAsLayout.list.editText.checks.withHintText("editText")
40 | }
41 |
42 | @Test
43 | fun textInput_isAccessible() {
44 | rule.launchActivity(
45 | RecyclerAsLayoutActivity.intent(
46 | arrayListOf(
47 | "input",
48 | "editText",
49 | "label"
50 | )
51 | )
52 | )
53 |
54 | Screen.recyclerAsLayout.list.inputField.checks.withHintText("input")
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/RecyclerInRecyclerLayoutScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import android.widget.FrameLayout
4 | import androidx.test.espresso.matcher.ViewMatchers
5 | import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
6 | import androidx.test.espresso.matcher.ViewMatchers.withId
7 | import androidx.test.espresso.matcher.ViewMatchers.withText
8 | import com.avito.android.test.InteractionContext
9 | import com.avito.android.test.page_object.ListElement
10 | import com.avito.android.test.page_object.PageObject
11 | import com.avito.android.test.page_object.ViewElement
12 | import com.avito.android.ui.R
13 |
14 | class RecyclerInRecyclerLayoutScreen : PageObject() {
15 |
16 | val list: List = element(withId(R.id.recycler))
17 |
18 | class List(interactionContext: InteractionContext) : ListElement(interactionContext) {
19 |
20 | val horizontalList: InnerList = listElement(withId(R.id.inner_recycler))
21 |
22 | class InnerList(interactionContext: InteractionContext) : ListElement(interactionContext) {
23 |
24 | fun cellWithTitle(title: String): Cell = listElement(hasDescendant(withText(title)))
25 |
26 | fun cellAt(position: Int): Cell = listElement(
27 | ViewMatchers.isAssignableFrom(FrameLayout::class.java),
28 | position
29 | )
30 |
31 | class Cell(interactionContext: InteractionContext) : ViewElement(interactionContext) {
32 | val title: ViewElement = element(withId(R.id.title))
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/RecyclerInRecyclerTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.RecyclerInRecyclerActivity
4 | import org.junit.Rule
5 | import org.junit.Test
6 |
7 | class RecyclerInRecyclerTest {
8 |
9 | @get:Rule
10 | val rule = screenRule()
11 |
12 | @Test
13 | fun typedItemAtPosition_foundFirstValue() {
14 | rule.launchActivity(RecyclerInRecyclerActivity.intent(arrayListOf("0", "1", "2")))
15 |
16 | Screen.recyclerInRecycler.list.horizontalList.cellAt(position = 0)
17 | .title.checks.displayedWithText("0")
18 | }
19 |
20 | @Test
21 | fun typedItemWithMatcher_foundFirstValue() {
22 | rule.launchActivity(RecyclerInRecyclerActivity.intent(arrayListOf("0", "1", "2")))
23 |
24 | Screen.recyclerInRecycler.list.horizontalList.cellWithTitle("0")
25 | .title.checks.displayedWithText("0")
26 | }
27 |
28 | @Test
29 | fun typedItemAtPosition_foundThirdValue() {
30 | rule.launchActivity(RecyclerInRecyclerActivity.intent(arrayListOf("0", "1", "2")))
31 |
32 | Screen.recyclerInRecycler.list.horizontalList.cellAt(position = 2)
33 | .title.checks.displayedWithText("2")
34 | }
35 |
36 | @Test
37 | fun typedItemWithMatcher_foundThirdValue() {
38 | rule.launchActivity(RecyclerInRecyclerActivity.intent(arrayListOf("0", "1", "2")))
39 |
40 | Screen.recyclerInRecycler.list.horizontalList.cellWithTitle("2")
41 | .title.checks.displayedWithText("2")
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/RecyclerWithSingleLongItemScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.page_object.ListElement
5 | import com.avito.android.test.page_object.PageObject
6 | import com.avito.android.ui.R
7 |
8 | class RecyclerWithSingleLongItemScreen : PageObject() {
9 | val list: ListElement = element(withId(R.id.recycler))
10 | }
11 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/Screen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | object Screen {
4 |
5 | val distantViewOnScroll: DistantViewOnScrollScreen
6 | get() = DistantViewOnScrollScreen()
7 |
8 | val visibility: VisibilityScreen
9 | get() = VisibilityScreen()
10 |
11 | val overflow: OverflowMenuScreen
12 | get() = OverflowMenuScreen()
13 |
14 | val swipeRefresh: SwipeRefreshScreen
15 | get() = SwipeRefreshScreen()
16 |
17 | val textsElements: TextElementsScreen
18 | get() = TextElementsScreen()
19 |
20 | val buttons: ButtonsScreen
21 | get() = ButtonsScreen()
22 |
23 | val movingButton: MovingButtonScreen
24 | get() = MovingButtonScreen()
25 |
26 | val appBarScreen: AppBarScreen
27 | get() = AppBarScreen()
28 |
29 | val identicalCellsRecycler: IdenticalCellsRecyclerScreen
30 | get() = IdenticalCellsRecyclerScreen()
31 |
32 | val buttonsOverRecycler: ButtonsOverRecyclerScreen
33 | get() = ButtonsOverRecyclerScreen()
34 |
35 | val statefulRecyclerViewAdapterScreen: StatefulRecyclerViewAdapterScreen
36 | get() = StatefulRecyclerViewAdapterScreen()
37 |
38 | val recyclerAsLayout: RecyclerAsLayoutScreen
39 | get() = RecyclerAsLayoutScreen()
40 |
41 | val viewPagerScreen: ViewPagerScreen
42 | get() = ViewPagerScreen()
43 |
44 | val longRecycler: LongRecyclerScreen
45 | get() = LongRecyclerScreen()
46 |
47 | val recyclerInRecycler: RecyclerInRecyclerLayoutScreen
48 | get() = RecyclerInRecyclerLayoutScreen()
49 |
50 | val editTextScreen: EditTextScreen
51 | get() = EditTextScreen()
52 |
53 | val tabLayoutScreen: TabLayoutScreen
54 | get() = TabLayoutScreen()
55 |
56 | val backgroundDrawableScreen: BackgroundDrawableScreen
57 | get() = BackgroundDrawableScreen()
58 |
59 | val recyclerWithSingleLongItemScreen: RecyclerWithSingleLongItemScreen
60 | get() = RecyclerWithSingleLongItemScreen()
61 | }
62 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/ScreenRule.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import android.app.Activity
4 | import androidx.test.rule.ActivityTestRule
5 | import org.junit.rules.RuleChain
6 |
7 | inline fun screenRule(launchActivity: Boolean = false): GodRuleChain =
8 | GodRuleChain(
9 | RuleChain.emptyRuleChain()
10 | .around(ActivityTestRule(T::class.java, true, launchActivity))
11 | )
12 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/ScrollViewScrollToEndTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.DistantViewOnScrollActivity
4 | import org.junit.Rule
5 | import org.junit.Test
6 |
7 | class ScrollViewScrollToEndTest {
8 |
9 | @get:Rule
10 | val rule = screenRule(launchActivity = true)
11 |
12 | @Test
13 | fun isVisible_viewIsNotDisplayed() {
14 | Screen.distantViewOnScroll.view.checks.isNotDisplayed()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/StatefulRecyclerViewAdapterScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
4 | import androidx.test.espresso.matcher.ViewMatchers.withId
5 | import androidx.test.espresso.matcher.ViewMatchers.withText
6 | import com.avito.android.test.InteractionContext
7 | import com.avito.android.test.page_object.ListElement
8 | import com.avito.android.test.page_object.PageObject
9 | import com.avito.android.test.page_object.ViewElement
10 | import com.avito.android.ui.R
11 |
12 | class StatefulRecyclerViewAdapterScreen : PageObject() {
13 |
14 | val list: List = element(withId(R.id.recycler))
15 |
16 | class List(override val interactionContext: InteractionContext) : ListElement(interactionContext) {
17 |
18 | fun cellWithTitle(title: String): Cell = listElement(hasDescendant(withText(title)))
19 |
20 | fun cellWithTitleCreatedByRecyclerViewInteractionContext(title: String): ViewElement =
21 | listElement(
22 | hasDescendant(withText(title))
23 | )
24 |
25 | class Cell(interactionContext: InteractionContext) : ViewElement(interactionContext) {
26 | val title: ViewElement = element(withId(R.id.title))
27 | val title2: ViewElement = element(withId(R.id.title2))
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/SwipeRefreshScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.page_object.ListElement
5 | import com.avito.android.test.page_object.PageObject
6 | import com.avito.android.test.page_object.SwipeRefreshElement
7 | import com.avito.android.ui.R
8 |
9 | class SwipeRefreshScreen : PageObject() {
10 | val list: ListElement = element(withId(R.id.swipe_refresh))
11 | val swipeRefreshElement: SwipeRefreshElement = element(withId(R.id.swipe_refresh))
12 | }
13 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/SwipeRefreshTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.SwipeRefreshActivity
4 | import org.hamcrest.CoreMatchers.equalTo
5 | import org.hamcrest.MatcherAssert.assertThat
6 | import org.junit.Rule
7 | import org.junit.Test
8 |
9 | class SwipeRefreshTest {
10 |
11 | @get:Rule
12 | val rule = screenRule()
13 |
14 | @Test
15 | fun refresh_onPullToRefresh_listAction() {
16 | rule.launchActivity(null)
17 |
18 | Screen.swipeRefresh.list.actions.pullToRefresh()
19 |
20 | Screen.swipeRefresh.swipeRefreshElement.checks.isRefreshing()
21 | assertThat(rule.activity.refreshedTimes, equalTo(1))
22 | }
23 |
24 | @Test
25 | fun refresh_onPullToRefresh_swipeRefreshAction() {
26 | rule.launchActivity(null)
27 |
28 | Screen.swipeRefresh.swipeRefreshElement.actions.pullToRefresh()
29 |
30 | assertThat(rule.activity.refreshedTimes, equalTo(1))
31 | }
32 |
33 | @Test
34 | fun stop_refreshing_by_intention() {
35 | rule.launchActivity(null)
36 |
37 | Screen.swipeRefresh.swipeRefreshElement.actions.pullToRefresh()
38 |
39 | rule.activity.postAndStopRefreshing()
40 |
41 | Screen.swipeRefresh.swipeRefreshElement.checks.isNotRefreshing()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/TabLayoutScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.page_object.PageObject
5 | import com.avito.android.test.page_object.TabLayoutElement
6 | import com.avito.android.ui.R
7 |
8 | class TabLayoutScreen : PageObject() {
9 | val tabs: TabLayoutElement = element(withId(R.id.tabs))
10 | }
11 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/TabLayoutTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import com.avito.android.ui.TabLayoutActivity
4 | import org.junit.Rule
5 | import org.junit.Test
6 |
7 | class TabLayoutTest {
8 |
9 | @get:Rule
10 | val rule = screenRule(launchActivity = true)
11 |
12 | @Test
13 | fun tabsCountIs1000() {
14 | Screen.tabLayoutScreen.tabs.checks.withTabsCount(1000)
15 | }
16 |
17 | @Test
18 | fun selectTab500_tabIsDisplayed() {
19 | Screen.tabLayoutScreen.tabs.select(500)
20 | Screen.tabLayoutScreen.tabs.checks.withSelectedPosition(500)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/TextElementsScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.page_object.TextElement
5 | import com.avito.android.test.page_object.PageObject
6 | import com.avito.android.ui.R
7 |
8 | class TextElementsScreen : PageObject() {
9 | val textView: TextElement = element(withId(R.id.text_view))
10 | val textViewLong: TextElement = element(withId(R.id.text_view_long))
11 | }
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/UITestRunner.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import android.content.Intent
4 | import androidx.test.runner.AndroidJUnitRunner
5 |
6 | class UITestRunner : AndroidJUnitRunner() {
7 |
8 | override fun onStart() {
9 | super.onStart()
10 | targetContext.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/ViewPagerScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers.withId
4 | import com.avito.android.test.InteractionContext
5 | import com.avito.android.test.page_object.PageObject
6 | import com.avito.android.test.page_object.ViewElement
7 | import com.avito.android.test.page_object.ViewPagerElement
8 | import com.avito.android.ui.R
9 |
10 | class ViewPagerScreen : PageObject() {
11 |
12 | val pager: Pager = element(withId(R.id.view_pager))
13 |
14 | class Pager(interactionContext: InteractionContext) : ViewPagerElement(interactionContext) {
15 | val currentEvenPage: EvenPage = currentPageElement(withId(R.id.even_page_root))
16 | val currentOddPage: OddPage = currentPageElement(withId(R.id.odd_page_root))
17 | }
18 |
19 | class EvenPage(interactionContext: InteractionContext) : ViewElement(interactionContext) {
20 | val label: ViewElement = element(withId(R.id.view_pager_even_label))
21 | }
22 |
23 | class OddPage(interactionContext: InteractionContext) : ViewElement(interactionContext) {
24 | val label: ViewElement = element(withId(R.id.view_pager_odd_label))
25 | }
26 | }
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/VisibilityScreen.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import androidx.test.espresso.matcher.ViewMatchers
4 | import com.avito.android.test.page_object.PageObject
5 | import com.avito.android.test.page_object.ViewElement
6 | import com.avito.android.ui.R
7 |
8 | class VisibilityScreen : PageObject() {
9 | val label: ViewElement = element(ViewMatchers.withId(R.id.text))
10 | }
11 |
--------------------------------------------------------------------------------
/test-app/src/androidTest/java/com/avito/android/ui/test/VisibilityTest.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui.test
2 |
3 | import android.view.View
4 | import com.avito.android.ui.R
5 | import com.avito.android.ui.VisibilityActivity
6 | import junit.framework.AssertionFailedError
7 | import org.junit.Rule
8 | import org.junit.Test
9 | import org.junit.rules.ExpectedException
10 |
11 | class VisibilityTest {
12 |
13 | @get:Rule
14 | val rule = screenRule()
15 |
16 | @get:Rule
17 | val exception: ExpectedException = ExpectedException.none()
18 |
19 | @Test
20 | fun isVisible_success_forVisibleElement() {
21 | rule.launchActivity(null)
22 |
23 | Screen.visibility.label.checks.isVisible()
24 | }
25 |
26 | @Test
27 | fun isVisible_fail_forInVisibleElement() {
28 | rule.launchActivity(null)
29 |
30 | rule.runOnUiThread {
31 | rule.activity.findViewById(R.id.text).visibility = View.INVISIBLE
32 | }
33 | exception.expect(AssertionFailedError::class.java)
34 | exception.expectMessage(
35 | "'view has effective visibility=VISIBLE' " +
36 | "doesn't match the selected view."
37 | )
38 | Screen.visibility.label.checks.isVisible()
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/test-app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/test-app/src/main/java/com/avito/android/ui/AppBarActivity.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.appcompat.widget.Toolbar
6 | import com.google.android.material.appbar.AppBarLayout
7 |
8 | class AppBarActivity : AppCompatActivity() {
9 |
10 | private lateinit var appBarLayout: AppBarLayout
11 |
12 | override fun onCreate(savedInstanceState: Bundle?) {
13 | super.onCreate(savedInstanceState)
14 | setContentView(R.layout.activity_app_bar)
15 | appBarLayout = findViewById(R.id.appbar)
16 | val toolbar = findViewById(R.id.toolbar)
17 | setSupportActionBar(toolbar)
18 | }
19 |
20 | fun setExpanded(isExpanded: Boolean) {
21 | appBarLayout.handler.post {
22 | appBarLayout.setExpanded(isExpanded)
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/test-app/src/main/java/com/avito/android/ui/ButtonsOverRecyclerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.avito.android.ui
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.Button
8 | import android.widget.TextView
9 | import androidx.appcompat.app.AppCompatActivity
10 | import androidx.recyclerview.widget.LinearLayoutManager
11 | import androidx.recyclerview.widget.RecyclerView
12 |
13 | class ButtonsOverRecyclerActivity : AppCompatActivity() {
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | setContentView(R.layout.activity_buttons_over_recycler)
18 |
19 | val data = (1..99).map { it.toString() }.toList()
20 |
21 | findViewById(R.id.recycler).apply {
22 | layoutManager = LinearLayoutManager(this@ButtonsOverRecyclerActivity)
23 | adapter = Adapter(data)
24 | }
25 |
26 | findViewById