A fork of Simple Time Tracker with WearOS support. (Now integrated upstream)
0

Configure Feed

Select the types of activity you want to include in your feed.

add more ui tests

razeeman (Nov 20, 2022, 7:01 PM +0300) 01126d80 19278281

+796 -23
+522
app/src/androidTest/java/com/example/util/simpletimetracker/ActivityFilterTest.kt
··· 1 + package com.example.util.simpletimetracker 2 + 3 + import android.view.View 4 + import androidx.test.espresso.Espresso.closeSoftKeyboard 5 + import androidx.test.espresso.Espresso.onView 6 + import androidx.test.espresso.assertion.PositionAssertions.isCompletelyAbove 7 + import androidx.test.espresso.assertion.PositionAssertions.isCompletelyBelow 8 + import androidx.test.espresso.matcher.ViewMatchers.hasDescendant 9 + import androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA 10 + import androidx.test.espresso.matcher.ViewMatchers.withId 11 + import androidx.test.espresso.matcher.ViewMatchers.withParent 12 + import androidx.test.espresso.matcher.ViewMatchers.withText 13 + import androidx.test.ext.junit.runners.AndroidJUnit4 14 + import com.example.util.simpletimetracker.core.mapper.ColorMapper 15 + import com.example.util.simpletimetracker.domain.model.ActivityFilter 16 + import com.example.util.simpletimetracker.utils.BaseUiTest 17 + import com.example.util.simpletimetracker.utils.NavUtils 18 + import com.example.util.simpletimetracker.utils.checkViewDoesNotExist 19 + import com.example.util.simpletimetracker.utils.checkViewIsDisplayed 20 + import com.example.util.simpletimetracker.utils.checkViewIsNotDisplayed 21 + import com.example.util.simpletimetracker.utils.clickOnRecyclerItem 22 + import com.example.util.simpletimetracker.utils.clickOnView 23 + import com.example.util.simpletimetracker.utils.clickOnViewWithText 24 + import com.example.util.simpletimetracker.utils.longClickOnView 25 + import com.example.util.simpletimetracker.utils.nestedScrollTo 26 + import com.example.util.simpletimetracker.utils.scrollRecyclerToPosition 27 + import com.example.util.simpletimetracker.utils.scrollRecyclerToView 28 + import com.example.util.simpletimetracker.utils.tryAction 29 + import com.example.util.simpletimetracker.utils.typeTextIntoView 30 + import com.example.util.simpletimetracker.utils.unconstrainedClickOnView 31 + import com.example.util.simpletimetracker.utils.withCardColor 32 + import dagger.hilt.android.testing.HiltAndroidTest 33 + import kotlinx.coroutines.runBlocking 34 + import org.hamcrest.CoreMatchers.allOf 35 + import org.hamcrest.Matcher 36 + import org.junit.Test 37 + import org.junit.runner.RunWith 38 + 39 + @HiltAndroidTest 40 + @RunWith(AndroidJUnit4::class) 41 + class ActivityFilterTest : BaseUiTest() { 42 + 43 + @Test 44 + fun addActivityFilter() { 45 + showActivityFilters() 46 + 47 + val name = "TestFilter" 48 + val typeName1 = "Type1" 49 + val typeName2 = "Type2" 50 + val categoryName1 = "Category1" 51 + val categoryName2 = "Category2" 52 + val lastColorPosition = ColorMapper.getAvailableColors().size - 1 53 + 54 + // Add activities 55 + testUtils.addActivity(typeName1) 56 + testUtils.addActivity(typeName2) 57 + testUtils.addCategory(categoryName1) 58 + testUtils.addCategory(categoryName2) 59 + 60 + tryAction { clickOnViewWithText(R.string.running_records_add_filter) } 61 + closeSoftKeyboard() 62 + 63 + // View is set up 64 + checkViewIsNotDisplayed(withId(R.id.btnChangeActivityFilterDelete)) 65 + checkViewIsNotDisplayed(withId(R.id.rvChangeActivityFilterColor)) 66 + checkViewIsNotDisplayed(withId(R.id.rvChangeActivityFilterType)) 67 + 68 + // Name is not selected 69 + clickOnViewWithText(R.string.change_category_save) 70 + 71 + // Typing name 72 + typeTextIntoView(R.id.etChangeActivityFilterName, name) 73 + checkPreviewUpdated(hasDescendant(withText(name))) 74 + 75 + // Open color chooser 76 + clickOnViewWithText(R.string.change_category_color_hint) 77 + checkViewIsDisplayed(withId(R.id.rvChangeActivityFilterColor)) 78 + checkViewIsNotDisplayed(withId(R.id.rvChangeActivityFilterType)) 79 + 80 + // Selecting color 81 + clickOnRecyclerItem(R.id.rvChangeActivityFilterColor, withCardColor(firstColor)) 82 + checkPreviewUpdated(withCardColor(firstColor)) 83 + checkViewIsDisplayed(allOf(withId(R.id.viewColorItemSelected), withParent(withCardColor(firstColor)))) 84 + 85 + // Selecting color 86 + scrollRecyclerToPosition(R.id.rvChangeActivityFilterColor, lastColorPosition) 87 + clickOnRecyclerItem(R.id.rvChangeActivityFilterColor, withCardColor(lastColor)) 88 + checkPreviewUpdated(withCardColor(lastColor)) 89 + checkViewIsDisplayed(allOf(withId(R.id.viewColorItemSelected), withParent(withCardColor(lastColor)))) 90 + 91 + // Open activity chooser 92 + clickOnViewWithText(R.string.activity_hint) 93 + checkViewIsNotDisplayed(withId(R.id.rvChangeActivityFilterColor)) 94 + checkViewIsDisplayed(withId(R.id.rvChangeActivityFilterType)) 95 + checkViewIsDisplayed(withText(typeName1)) 96 + checkViewIsDisplayed(withText(typeName2)) 97 + checkViewIsDisplayed(withText(R.string.nothing_selected)) 98 + checkViewIsDisplayed(withId(R.id.viewDividerItem)) 99 + onView(withText(typeName1)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 100 + onView(withText(typeName2)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 101 + 102 + // Selecting activity 103 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(typeName1)) 104 + checkViewIsDisplayed(withText(R.string.something_selected)) 105 + checkViewIsDisplayed(withId(R.id.viewDividerItem)) 106 + onView(withText(typeName1)).check(isCompletelyAbove(withId(R.id.viewDividerItem))) 107 + onView(withText(typeName2)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 108 + 109 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(typeName2)) 110 + checkViewIsDisplayed(withText(R.string.something_selected)) 111 + checkViewDoesNotExist(withId(R.id.viewDividerItem)) 112 + checkViewIsDisplayed(withText(typeName1)) 113 + checkViewIsDisplayed(withText(typeName2)) 114 + 115 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(typeName1)) 116 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(typeName2)) 117 + checkViewIsDisplayed(withText(R.string.nothing_selected)) 118 + checkViewIsDisplayed(withId(R.id.viewDividerItem)) 119 + onView(withText(typeName1)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 120 + onView(withText(typeName2)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 121 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(typeName1)) 122 + 123 + // Open category chooser 124 + clickOnViewWithText(R.string.category_hint) 125 + checkViewIsNotDisplayed(withId(R.id.rvChangeActivityFilterColor)) 126 + checkViewIsDisplayed(withId(R.id.rvChangeActivityFilterType)) 127 + checkViewIsDisplayed(withText(categoryName1)) 128 + checkViewIsDisplayed(withText(categoryName2)) 129 + checkViewIsDisplayed(withText(R.string.nothing_selected)) 130 + checkViewIsDisplayed(withId(R.id.viewDividerItem)) 131 + onView(withText(categoryName1)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 132 + onView(withText(categoryName2)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 133 + 134 + // Selecting category 135 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(categoryName1)) 136 + checkViewIsDisplayed(withText(R.string.something_selected)) 137 + checkViewIsDisplayed(withId(R.id.viewDividerItem)) 138 + onView(withText(categoryName1)).check(isCompletelyAbove(withId(R.id.viewDividerItem))) 139 + onView(withText(categoryName2)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 140 + 141 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(categoryName2)) 142 + checkViewIsDisplayed(withText(R.string.something_selected)) 143 + checkViewDoesNotExist(withId(R.id.viewDividerItem)) 144 + checkViewIsDisplayed(withText(categoryName1)) 145 + checkViewIsDisplayed(withText(categoryName2)) 146 + 147 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(categoryName1)) 148 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(categoryName2)) 149 + checkViewIsDisplayed(withText(R.string.nothing_selected)) 150 + checkViewIsDisplayed(withId(R.id.viewDividerItem)) 151 + onView(withText(categoryName1)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 152 + onView(withText(categoryName2)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 153 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(categoryName1)) 154 + 155 + // Types are preserved when switching filter type 156 + clickOnView( 157 + allOf(isDescendantOfA(withId(R.id.buttonsChangeActivityFilterType)), withText(R.string.activity_hint)) 158 + ) 159 + onView(withText(typeName1)).check(isCompletelyAbove(withId(R.id.viewDividerItem))) 160 + onView(withText(typeName2)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 161 + clickOnView( 162 + allOf(isDescendantOfA(withId(R.id.buttonsChangeActivityFilterType)), withText(R.string.category_hint)) 163 + ) 164 + onView(withText(categoryName1)).check(isCompletelyAbove(withId(R.id.viewDividerItem))) 165 + onView(withText(categoryName2)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 166 + 167 + // Save 168 + clickOnView( 169 + allOf(isDescendantOfA(withId(R.id.buttonsChangeActivityFilterType)), withText(R.string.activity_hint)) 170 + ) 171 + clickOnViewWithText(R.string.change_activity_filter_save) 172 + 173 + // Filter added 174 + checkViewIsDisplayed(withText(name)) 175 + checkViewIsDisplayed(withCardColor(lastColor)) 176 + 177 + // Check types saved 178 + longClickOnView(withText(name)) 179 + clickOnViewWithText(R.string.activity_hint) 180 + checkViewIsDisplayed(withText(R.string.something_selected)) 181 + checkViewIsDisplayed(withId(R.id.viewDividerItem)) 182 + onView(withText(typeName1)).check(isCompletelyAbove(withId(R.id.viewDividerItem))) 183 + onView(withText(typeName2)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 184 + } 185 + 186 + @Test 187 + fun changeActivityFilter() { 188 + showActivityFilters() 189 + 190 + val name = "TestFilter" 191 + val newName = "UpdatedFilter" 192 + val typeName1 = "Type1" 193 + val typeName2 = "Type2" 194 + val categoryName1 = "Category1" 195 + val categoryName2 = "Category2" 196 + 197 + // Add activities 198 + testUtils.addActivity(typeName1) 199 + testUtils.addActivity(typeName2) 200 + testUtils.addCategory(categoryName1) 201 + testUtils.addCategory(categoryName2) 202 + 203 + // Add category 204 + NavUtils.addActivityFilter(name = name, color = firstColor, activities = listOf(typeName1)) 205 + 206 + longClickOnView(withText(name)) 207 + 208 + // View is set up 209 + checkViewIsDisplayed(withId(R.id.btnChangeActivityFilterDelete)) 210 + checkViewIsNotDisplayed(withId(R.id.rvChangeActivityFilterColor)) 211 + checkViewIsNotDisplayed(withId(R.id.rvChangeActivityFilterType)) 212 + checkViewIsDisplayed(allOf(withId(R.id.etChangeActivityFilterName), withText(name))) 213 + 214 + // Preview is updated 215 + checkPreviewUpdated(hasDescendant(withText(name))) 216 + checkPreviewUpdated(withCardColor(firstColor)) 217 + 218 + // Change name 219 + typeTextIntoView(R.id.etChangeActivityFilterName, newName) 220 + checkPreviewUpdated(hasDescendant(withText(newName))) 221 + 222 + // Change color 223 + clickOnViewWithText(R.string.change_category_color_hint) 224 + checkViewIsDisplayed(allOf(withId(R.id.viewColorItemSelected), withParent(withCardColor(firstColor)))) 225 + scrollRecyclerToView(R.id.rvChangeActivityFilterColor, withCardColor(lastColor)) 226 + clickOnRecyclerItem(R.id.rvChangeActivityFilterColor, withCardColor(lastColor)) 227 + checkPreviewUpdated(withCardColor(lastColor)) 228 + checkViewIsDisplayed(allOf(withId(R.id.viewColorItemSelected), withParent(withCardColor(lastColor)))) 229 + 230 + // Change types 231 + clickOnViewWithText(R.string.activity_hint) 232 + onView(withText(typeName1)).check(isCompletelyAbove(withId(R.id.viewDividerItem))) 233 + onView(withText(typeName2)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 234 + clickOnView( 235 + allOf(isDescendantOfA(withId(R.id.buttonsChangeActivityFilterType)), withText(R.string.category_hint)) 236 + ) 237 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(categoryName2)) 238 + onView(withText(categoryName1)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 239 + onView(withText(categoryName2)).check(isCompletelyAbove(withId(R.id.viewDividerItem))) 240 + 241 + // Save 242 + clickOnViewWithText(R.string.change_activity_filter_save) 243 + 244 + // Filter updated 245 + checkViewIsDisplayed(withText(newName)) 246 + checkViewIsDisplayed(withCardColor(lastColor)) 247 + longClickOnView(withText(newName)) 248 + clickOnViewWithText(R.string.activity_hint) 249 + onView(withText(categoryName1)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 250 + onView(withText(categoryName2)).check(isCompletelyAbove(withId(R.id.viewDividerItem))) 251 + } 252 + 253 + @Test 254 + fun addActivityFilterEmpty() { 255 + showActivityFilters() 256 + 257 + tryAction { clickOnViewWithText(R.string.running_records_add_filter) } 258 + clickOnView(withText(R.string.activity_hint)) 259 + 260 + // Activities empty 261 + clickOnView( 262 + allOf( 263 + isDescendantOfA(withId(R.id.buttonsChangeActivityFilterType)), 264 + withText(R.string.activity_hint) 265 + ) 266 + ) 267 + checkViewIsDisplayed(withText(R.string.record_types_empty)) 268 + 269 + // Categories empty 270 + clickOnView( 271 + allOf( 272 + isDescendantOfA(withId(R.id.buttonsChangeActivityFilterType)), 273 + withText(R.string.category_hint) 274 + ) 275 + ) 276 + checkViewIsDisplayed(withText(R.string.change_record_type_categories_empty)) 277 + } 278 + 279 + @Test 280 + fun filtering() { 281 + showActivityFilters() 282 + 283 + val filterByActivity1 = "filterByActivity1" 284 + val filterByActivity2 = "filterByActivity2" 285 + val filterByCategory1 = "filterByCategory1" 286 + val filterByCategory2 = "filterByCategory2" 287 + val filterByCategoryAll = "filterByCategoryAll" 288 + val filterEmpty = "filterEmpty" 289 + val typeName1 = "Type1" 290 + val typeName2 = "Type2" 291 + val typeName3 = "Type3" 292 + val typeName4 = "Type4" 293 + val typeName5 = "Type5" 294 + val categoryName1 = "Category1" 295 + val categoryName2 = "Category2" 296 + 297 + val availableTypes = listOf(typeName1, typeName2, typeName3, typeName4, typeName5) 298 + 299 + // Add data 300 + testUtils.addCategory(categoryName1) 301 + testUtils.addCategory(categoryName2) 302 + testUtils.addActivity(name = typeName1, categories = listOf(categoryName1)) 303 + testUtils.addActivity(name = typeName2, categories = listOf(categoryName1)) 304 + testUtils.addActivity(name = typeName3, categories = listOf(categoryName2)) 305 + testUtils.addActivity(name = typeName4, categories = listOf(categoryName2)) 306 + testUtils.addActivity(name = typeName5) 307 + 308 + // Add empty filter 309 + testUtils.addActivityFilter( 310 + name = filterEmpty, 311 + type = ActivityFilter.Type.Activity, 312 + color = firstColor, 313 + ) 314 + 315 + // Add activity filters 316 + testUtils.addActivityFilter( 317 + name = filterByActivity1, 318 + type = ActivityFilter.Type.Activity, 319 + color = firstColor, 320 + names = listOf(typeName1, typeName3) 321 + ) 322 + testUtils.addActivityFilter( 323 + name = filterByActivity2, 324 + type = ActivityFilter.Type.Activity, 325 + color = firstColor, 326 + names = listOf(typeName5) 327 + ) 328 + 329 + // Add category filters 330 + testUtils.addActivityFilter( 331 + name = filterByCategory1, 332 + type = ActivityFilter.Type.Category, 333 + color = firstColor, 334 + names = listOf(categoryName1) 335 + ) 336 + testUtils.addActivityFilter( 337 + name = filterByCategory2, 338 + type = ActivityFilter.Type.Category, 339 + color = firstColor, 340 + names = listOf(categoryName2) 341 + ) 342 + testUtils.addActivityFilter( 343 + name = filterByCategoryAll, 344 + type = ActivityFilter.Type.Category, 345 + color = firstColor, 346 + names = listOf(categoryName1, categoryName2) 347 + ) 348 + 349 + // Check filtering 350 + tryAction { 351 + checkFilter(filterByActivity1, R.color.colorInactive) 352 + checkFilter(filterByActivity2, R.color.colorInactive) 353 + checkFilter(filterByCategory1, R.color.colorInactive) 354 + checkFilter(filterByCategory2, R.color.colorInactive) 355 + checkFilter(filterByCategoryAll, R.color.colorInactive) 356 + checkFilter(filterEmpty, R.color.colorInactive) 357 + checkTypes(displayed = availableTypes, available = availableTypes) 358 + } 359 + 360 + clickOnViewWithText(filterByActivity1) 361 + checkFilter(filterByActivity1, firstColor) 362 + checkTypes( 363 + displayed = listOf(typeName1, typeName3), 364 + available = availableTypes 365 + ) 366 + clickOnViewWithText(filterByActivity1) 367 + checkTypes(displayed = availableTypes, available = availableTypes) 368 + 369 + clickOnViewWithText(filterByActivity2) 370 + checkFilter(filterByActivity2, firstColor) 371 + checkTypes( 372 + displayed = listOf(typeName5), 373 + available = availableTypes, 374 + ) 375 + clickOnViewWithText(filterByActivity2) 376 + checkTypes(displayed = availableTypes, available = availableTypes) 377 + 378 + clickOnViewWithText(filterByCategory1) 379 + checkFilter(filterByCategory1, firstColor) 380 + checkTypes( 381 + displayed = listOf(typeName1, typeName2), 382 + available = availableTypes, 383 + ) 384 + clickOnViewWithText(filterByCategory1) 385 + checkTypes(displayed = availableTypes, available = availableTypes) 386 + 387 + clickOnViewWithText(filterByCategory2) 388 + checkFilter(filterByCategory2, firstColor) 389 + checkTypes( 390 + displayed = listOf(typeName3, typeName4), 391 + available = availableTypes, 392 + ) 393 + clickOnViewWithText(filterByCategory2) 394 + checkTypes(displayed = availableTypes, available = availableTypes) 395 + 396 + clickOnViewWithText(filterByCategoryAll) 397 + checkFilter(filterByCategoryAll, firstColor) 398 + checkTypes( 399 + displayed = listOf(typeName1, typeName2, typeName3, typeName4), 400 + available = availableTypes, 401 + ) 402 + clickOnViewWithText(filterByCategoryAll) 403 + checkTypes(displayed = availableTypes, available = availableTypes) 404 + 405 + clickOnViewWithText(filterEmpty) 406 + checkFilter(filterEmpty, firstColor) 407 + checkTypes( 408 + displayed = listOf(), 409 + available = availableTypes, 410 + ) 411 + clickOnViewWithText(filterEmpty) 412 + checkTypes(displayed = availableTypes, available = availableTypes) 413 + 414 + clickOnViewWithText(filterByActivity1) 415 + clickOnViewWithText(filterByCategory1) 416 + checkFilter(filterByActivity1, firstColor) 417 + checkFilter(filterByCategory1, firstColor) 418 + checkTypes( 419 + displayed = listOf(typeName1, typeName2, typeName3), 420 + available = availableTypes, 421 + ) 422 + clickOnViewWithText(filterByActivity1) 423 + clickOnViewWithText(filterByCategory1) 424 + checkTypes(displayed = availableTypes, available = availableTypes) 425 + 426 + clickOnViewWithText(filterByActivity2) 427 + clickOnViewWithText(filterByCategory2) 428 + checkFilter(filterByActivity2, firstColor) 429 + checkFilter(filterByCategory2, firstColor) 430 + checkTypes( 431 + displayed = listOf(typeName3, typeName4, typeName5), 432 + available = availableTypes, 433 + ) 434 + clickOnViewWithText(filterByActivity2) 435 + clickOnViewWithText(filterByCategory2) 436 + checkTypes(displayed = availableTypes, available = availableTypes) 437 + 438 + // All filters 439 + clickOnViewWithText(filterByActivity1) 440 + clickOnViewWithText(filterByActivity2) 441 + clickOnViewWithText(filterByCategory1) 442 + clickOnViewWithText(filterByCategory2) 443 + clickOnViewWithText(filterByCategoryAll) 444 + clickOnViewWithText(filterEmpty) 445 + checkFilter(filterByActivity1, firstColor) 446 + checkFilter(filterByActivity2, firstColor) 447 + checkFilter(filterByCategory1, firstColor) 448 + checkFilter(filterByCategory2, firstColor) 449 + checkFilter(filterEmpty, firstColor) 450 + checkTypes( 451 + displayed = availableTypes, 452 + available = availableTypes, 453 + ) 454 + } 455 + 456 + @Test 457 + fun filteringDisabledIfFiltersNotShown() { 458 + val filterName = "Filter" 459 + val typeName1 = "Type1" 460 + val typeName2 = "Type2" 461 + 462 + // Add data 463 + testUtils.addActivity(typeName1) 464 + testUtils.addActivity(typeName2) 465 + testUtils.addActivityFilter( 466 + name = filterName, 467 + type = ActivityFilter.Type.Activity, 468 + names = listOf(typeName1), 469 + selected = true, 470 + ) 471 + 472 + // No filtering 473 + tryAction { 474 + checkViewIsDisplayed(withText(typeName1)) 475 + checkViewIsDisplayed(withText(typeName2)) 476 + } 477 + 478 + // Change setting 479 + NavUtils.openSettingsScreen() 480 + NavUtils.openSettingsDisplay() 481 + onView(withId(R.id.checkboxSettingsShowActivityFilters)).perform(nestedScrollTo()) 482 + unconstrainedClickOnView(withId(R.id.checkboxSettingsShowActivityFilters)) 483 + 484 + // Filtering appears 485 + NavUtils.openRunningRecordsScreen() 486 + checkViewIsDisplayed(withText(typeName1)) 487 + checkViewDoesNotExist(withText(typeName2)) 488 + 489 + // Change setting 490 + NavUtils.openSettingsScreen() 491 + onView(withId(R.id.checkboxSettingsShowActivityFilters)).perform(nestedScrollTo()) 492 + unconstrainedClickOnView(withId(R.id.checkboxSettingsShowActivityFilters)) 493 + 494 + // No filtering 495 + NavUtils.openRunningRecordsScreen() 496 + checkViewIsDisplayed(withText(typeName1)) 497 + checkViewIsDisplayed(withText(typeName2)) 498 + } 499 + 500 + private fun checkFilter( 501 + name: String, 502 + color: Int, 503 + ) { 504 + checkViewIsDisplayed(allOf(withCardColor(color), hasDescendant(withText(name)))) 505 + } 506 + 507 + @Suppress("ConvertArgumentToSet") 508 + private fun checkTypes( 509 + displayed: List<String>, 510 + available: List<String>, 511 + ) { 512 + displayed.forEach { checkViewIsDisplayed(withText(it)) } 513 + (available - displayed).forEach { checkViewDoesNotExist(withText(it)) } 514 + } 515 + 516 + private fun showActivityFilters() = runBlocking { 517 + prefsInteractor.setShowActivityFilters(true) 518 + } 519 + 520 + private fun checkPreviewUpdated(matcher: Matcher<View>) = 521 + checkViewIsDisplayed(allOf(withId(R.id.previewChangeActivityFilter), matcher)) 522 + }
+13 -4
app/src/androidTest/java/com/example/util/simpletimetracker/AddCategoryTest.kt
··· 140 140 fun addCategoryFromChangeActivity() { 141 141 val categoryName1 = "Category1" 142 142 val categoryName2 = "Category2" 143 - val typeName = "Type" 143 + val typeName1 = "Type1" 144 + val typeName2 = "Type2" 144 145 145 146 // Add activity 146 - testUtils.addActivity(typeName) 147 - tryAction { longClickOnView(withText(typeName)) } 147 + testUtils.addActivity(typeName1) 148 + testUtils.addActivity(typeName2) 149 + tryAction { longClickOnView(withText(typeName1)) } 148 150 149 151 // Add category 150 152 clickOnViewWithText(R.string.category_hint) 151 153 clickOnViewWithText(R.string.categories_add_category) 152 154 typeTextIntoView(R.id.etChangeCategoryName, categoryName1) 153 155 closeSoftKeyboard() 154 - clickOnViewWithText(R.string.change_category_save) 156 + 157 + // Activity already selected 158 + clickOnViewWithText(R.string.change_category_types_hint) 159 + checkViewIsDisplayed(withText(R.string.something_selected)) 160 + checkViewIsDisplayed(withId(R.id.viewDividerItem)) 161 + onView(withText(typeName1)).check(isCompletelyAbove(withId(R.id.viewDividerItem))) 162 + onView(withText(typeName2)).check(isCompletelyBelow(withId(R.id.viewDividerItem))) 155 163 156 164 // Category added 165 + clickOnViewWithText(R.string.change_category_save) 157 166 checkViewIsDisplayed(withText(categoryName1)) 158 167 159 168 // Change category
+12 -7
app/src/androidTest/java/com/example/util/simpletimetracker/AddRecordTagTest.kt
··· 212 212 213 213 @Test 214 214 fun addRecordTagFromChangeRecord() { 215 - val tagName1 = "Category1" 216 - val tagName2 = "Category2" 215 + val tagName1 = "Tag1" 216 + val tagName2 = "Tag2" 217 217 val typeName = "Type" 218 218 219 219 // Add data 220 - testUtils.addActivity(typeName) 220 + testUtils.addActivity(name = typeName, color = lastColor, icon = lastIcon) 221 221 testUtils.addRecord(typeName) 222 222 223 - // Add category 223 + // Add tag 224 224 NavUtils.openRecordsScreen() 225 225 clickOnView(allOf(withText(typeName), isCompletelyDisplayed())) 226 226 clickOnViewWithId(R.id.fieldChangeRecordCategory) 227 227 clickOnViewWithText(R.string.categories_add_record_tag) 228 + 229 + // Activity already selected 230 + checkPreviewUpdated(withCardColor(lastColor)) 231 + checkPreviewUpdated(hasDescendant(withTag(lastIcon))) 232 + 228 233 typeTextIntoView(R.id.etChangeRecordTagName, tagName1) 229 234 closeSoftKeyboard() 230 235 clickOnViewWithText(R.string.change_category_save) 231 236 232 - // Category added 237 + // Tag added 233 238 checkViewIsDisplayed(withText(tagName1)) 234 239 235 - // Change category 240 + // Change tag 236 241 longClickOnView(withText(tagName1)) 237 242 typeTextIntoView(R.id.etChangeRecordTagName, tagName2) 238 243 closeSoftKeyboard() 239 244 clickOnViewWithText(R.string.change_category_save) 240 245 241 - // Category changed 246 + // Tag changed 242 247 checkViewDoesNotExist(withText(tagName1)) 243 248 checkViewIsDisplayed(withText(tagName2)) 244 249 }
+116 -8
app/src/androidTest/java/com/example/util/simpletimetracker/IconTest.kt
··· 33 33 class IconTest : BaseUiTest() { 34 34 35 35 @Test 36 - fun emojiTest() { 36 + fun iconEmojiTest() { 37 37 val firstName = "first" 38 - val lastName = "last" 38 + val secondName = "last" 39 39 40 40 // Add activity 41 - testUtils.addActivity(name = lastName, text = lastEmoji) 41 + testUtils.addActivity(name = secondName, text = lastEmoji) 42 42 43 43 // Open change record type screen 44 44 tryAction { clickOnViewWithText(R.string.running_records_add_type) } ··· 88 88 longClickOnView(allOf(isDescendantOfA(withId(R.id.viewRunningRecordItem)), withText(firstName))) 89 89 checkViewIsDisplayed(allOf(withId(R.id.previewChangeRunningRecord), hasDescendant(withText(firstEmoji)))) 90 90 clickOnViewWithText(R.string.change_record_type_field) 91 - clickOnRecyclerItem(R.id.rvChangeRunningRecordType, withText(lastName)) 91 + clickOnRecyclerItem(R.id.rvChangeRunningRecordType, withText(secondName)) 92 92 checkViewIsDisplayed(allOf(withId(R.id.previewChangeRunningRecord), hasDescendant(withText(lastEmoji)))) 93 93 clickOnViewWithText(R.string.change_record_save) 94 94 ··· 97 97 checkViewIsDisplayed( 98 98 allOf( 99 99 withId(R.id.viewRunningRecordItem), 100 - hasDescendant(withText(lastName)), 100 + hasDescendant(withText(secondName)), 101 101 hasDescendant(withText(lastEmoji)) 102 102 ) 103 103 ) 104 104 } 105 105 106 106 // Stop timer 107 - clickOnView(allOf(isDescendantOfA(withId(R.id.viewRunningRecordItem)), withText(lastName))) 107 + clickOnView(allOf(isDescendantOfA(withId(R.id.viewRunningRecordItem)), withText(secondName))) 108 108 109 109 // Record is added 110 110 NavUtils.openRecordsScreen() 111 111 checkViewIsDisplayed( 112 112 allOf( 113 113 withId(R.id.viewRecordItem), 114 - hasDescendant(withText(lastName)), 114 + hasDescendant(withText(secondName)), 115 115 hasDescendant(withText(lastEmoji)), 116 116 isCompletelyDisplayed() 117 117 ) 118 118 ) 119 119 120 120 // Change record 121 - clickOnView(allOf(withText(lastName), isCompletelyDisplayed())) 121 + clickOnView(allOf(withText(secondName), isCompletelyDisplayed())) 122 122 checkViewIsDisplayed(allOf(withId(R.id.previewChangeRecord), hasDescendant(withText(lastEmoji)))) 123 123 clickOnViewWithText(R.string.change_record_type_field) 124 124 clickOnRecyclerItem(R.id.rvChangeRecordType, withText(firstName)) ··· 132 132 withId(R.id.viewRecordItem), 133 133 hasDescendant(withText(firstName)), 134 134 hasDescendant(withText(firstEmoji)), 135 + isCompletelyDisplayed() 136 + ) 137 + ) 138 + } 139 + } 140 + 141 + @Test 142 + fun iconTextTest() { 143 + val firstName = "firstName" 144 + val firstIconText = "firstIconText" 145 + val secondName = "secondName" 146 + val secondIconText = "secondIconText" 147 + 148 + // Add activity 149 + testUtils.addActivity(name = secondName, text = secondIconText) 150 + 151 + // Open change record type screen 152 + tryAction { clickOnViewWithText(R.string.running_records_add_type) } 153 + 154 + // Select emoji 155 + clickOnViewWithText(R.string.change_record_type_icon_image_hint) 156 + clickOnView( 157 + allOf( 158 + isDescendantOfA(withId(R.id.btnChangeRecordTypeIconSwitch)), 159 + withText(R.string.change_record_type_icon_text_hint) 160 + ) 161 + ) 162 + tryAction { typeTextIntoView(R.id.etChangeRecordTypeIconText, firstIconText) } 163 + 164 + // Preview is updated 165 + checkViewIsDisplayed(allOf(withId(R.id.previewChangeRecordType), hasDescendant(withText(firstIconText)))) 166 + 167 + // Save 168 + clickOnViewWithId(R.id.fieldChangeRecordTypeIcon) 169 + typeTextIntoView(R.id.etChangeRecordTypeName, firstName) 170 + clickOnViewWithText(R.string.change_record_type_save) 171 + 172 + // Record type is created 173 + tryAction { 174 + checkViewIsDisplayed( 175 + allOf( 176 + withId(R.id.viewRecordTypeItem), 177 + hasDescendant(withText(firstName)), 178 + hasDescendant(withText(firstIconText)) 179 + ) 180 + ) 181 + } 182 + 183 + // Start timer 184 + clickOnViewWithText(firstName) 185 + 186 + // Check running record 187 + checkViewIsDisplayed( 188 + allOf( 189 + withId(R.id.viewRunningRecordItem), 190 + hasDescendant(withText(firstName)), 191 + hasDescendant(withText(firstIconText)) 192 + ) 193 + ) 194 + 195 + // Change running record 196 + longClickOnView(allOf(isDescendantOfA(withId(R.id.viewRunningRecordItem)), withText(firstName))) 197 + checkViewIsDisplayed(allOf(withId(R.id.previewChangeRunningRecord), hasDescendant(withText(firstIconText)))) 198 + clickOnViewWithText(R.string.change_record_type_field) 199 + clickOnRecyclerItem(R.id.rvChangeRunningRecordType, withText(secondName)) 200 + checkViewIsDisplayed(allOf(withId(R.id.previewChangeRunningRecord), hasDescendant(withText(secondIconText)))) 201 + clickOnViewWithText(R.string.change_record_save) 202 + 203 + // Check running record 204 + tryAction { 205 + checkViewIsDisplayed( 206 + allOf( 207 + withId(R.id.viewRunningRecordItem), 208 + hasDescendant(withText(secondName)), 209 + hasDescendant(withText(secondIconText)) 210 + ) 211 + ) 212 + } 213 + 214 + // Stop timer 215 + clickOnView(allOf(isDescendantOfA(withId(R.id.viewRunningRecordItem)), withText(secondName))) 216 + 217 + // Record is added 218 + NavUtils.openRecordsScreen() 219 + checkViewIsDisplayed( 220 + allOf( 221 + withId(R.id.viewRecordItem), 222 + hasDescendant(withText(secondName)), 223 + hasDescendant(withText(secondIconText)), 224 + isCompletelyDisplayed() 225 + ) 226 + ) 227 + 228 + // Change record 229 + clickOnView(allOf(withText(secondName), isCompletelyDisplayed())) 230 + checkViewIsDisplayed(allOf(withId(R.id.previewChangeRecord), hasDescendant(withText(secondIconText)))) 231 + clickOnViewWithText(R.string.change_record_type_field) 232 + clickOnRecyclerItem(R.id.rvChangeRecordType, withText(firstName)) 233 + checkViewIsDisplayed(allOf(withId(R.id.previewChangeRecord), hasDescendant(withText(firstIconText)))) 234 + clickOnViewWithText(R.string.change_record_type_save) 235 + 236 + // Check record 237 + tryAction { 238 + checkViewIsDisplayed( 239 + allOf( 240 + withId(R.id.viewRecordItem), 241 + hasDescendant(withText(firstName)), 242 + hasDescendant(withText(firstIconText)), 135 243 isCompletelyDisplayed() 136 244 ) 137 245 )
+41
app/src/androidTest/java/com/example/util/simpletimetracker/SettingsTest.kt
··· 31 31 import com.example.util.simpletimetracker.core.extension.setToStartOfDay 32 32 import com.example.util.simpletimetracker.core.extension.setWeekToFirstDay 33 33 import com.example.util.simpletimetracker.core.mapper.ColorMapper 34 + import com.example.util.simpletimetracker.domain.model.ActivityFilter 34 35 import com.example.util.simpletimetracker.domain.model.DayOfWeek 35 36 import com.example.util.simpletimetracker.utils.BaseUiTest 36 37 import com.example.util.simpletimetracker.utils.Direction ··· 1374 1375 clickOnView(allOf(withText(name), isCompletelyDisplayed())) 1375 1376 checkViewIsDisplayed(allOf(withText(R.string.title_this_week), isCompletelyDisplayed())) 1376 1377 pressBack() 1378 + } 1379 + 1380 + @Test 1381 + fun automatedTracking() { 1382 + NavUtils.openSettingsScreen() 1383 + NavUtils.openSettingsAdditional() 1384 + onView(withId(R.id.btnSettingsAutomatedTracking)).perform(nestedScrollTo(), click()) 1385 + checkViewIsDisplayed( 1386 + allOf(withId(R.id.tvHelpDialogTitle), withText(R.string.settings_automated_tracking)) 1387 + ) 1388 + } 1389 + 1390 + @Test 1391 + fun showFiltersOnMain() { 1392 + val name = "ActivityFilter" 1393 + 1394 + // Add filter 1395 + testUtils.addActivityFilter(name, ActivityFilter.Type.Activity) 1396 + 1397 + // Filters not shown 1398 + tryAction { 1399 + checkViewIsDisplayed(withText(R.string.running_records_add_type)) 1400 + checkViewDoesNotExist(withText(R.string.running_records_add_filter)) 1401 + checkViewDoesNotExist(withText(name)) 1402 + } 1403 + 1404 + // Check settings 1405 + NavUtils.openSettingsScreen() 1406 + NavUtils.openSettingsDisplay() 1407 + onView(withId(R.id.checkboxSettingsShowActivityFilters)).perform(nestedScrollTo()) 1408 + onView(withId(R.id.checkboxSettingsShowActivityFilters)).check(matches(isNotChecked())) 1409 + 1410 + // Change setting 1411 + unconstrainedClickOnView(withId(R.id.checkboxSettingsShowActivityFilters)) 1412 + onView(withId(R.id.checkboxSettingsShowActivityFilters)).check(matches(isChecked())) 1413 + 1414 + // Filters shown 1415 + NavUtils.openRunningRecordsScreen() 1416 + checkViewIsDisplayed(withText(R.string.running_records_add_filter)) 1417 + checkViewIsDisplayed(withText(name)) 1377 1418 } 1378 1419 1379 1420 private fun clearDuration() {
+53
app/src/androidTest/java/com/example/util/simpletimetracker/utils/NavUtils.kt
··· 236 236 clickOnViewWithText(R.string.change_record_save) 237 237 } 238 238 239 + fun addActivityFilter( 240 + name: String, 241 + color: Int? = null, 242 + activities: List<String> = emptyList(), 243 + categories: List<String> = emptyList(), 244 + ) { 245 + tryAction { clickOnViewWithText(R.string.running_records_add_filter) } 246 + 247 + // Name 248 + typeTextIntoView(R.id.etChangeActivityFilterName, name) 249 + 250 + // Color 251 + if (color != null) { 252 + clickOnViewWithText(R.string.change_category_color_hint) 253 + scrollRecyclerToView(R.id.rvChangeActivityFilterColor, withCardColor(color)) 254 + clickOnRecyclerItem(R.id.rvChangeActivityFilterColor, withCardColor(color)) 255 + } 256 + 257 + // Activity 258 + if (activities.isNotEmpty()) { 259 + clickOnViewWithId(R.id.fieldChangeActivityFilterType) 260 + clickOnView( 261 + allOf( 262 + isDescendantOfA(withId(R.id.buttonsChangeActivityFilterType)), 263 + withText(R.string.activity_hint) 264 + ) 265 + ) 266 + activities.forEach { 267 + scrollRecyclerToView(R.id.rvChangeActivityFilterType, hasDescendant(withText(it))) 268 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(it)) 269 + } 270 + clickOnViewWithId(R.id.fieldChangeActivityFilterType) 271 + } 272 + 273 + // Category 274 + if (categories.isNotEmpty()) { 275 + clickOnViewWithId(R.id.fieldChangeActivityFilterType) 276 + clickOnView( 277 + allOf( 278 + isDescendantOfA(withId(R.id.buttonsChangeActivityFilterType)), 279 + withText(R.string.category_hint) 280 + ) 281 + ) 282 + categories.forEach { 283 + scrollRecyclerToView(R.id.rvChangeActivityFilterType, hasDescendant(withText(it))) 284 + clickOnRecyclerItem(R.id.rvChangeActivityFilterType, withText(it)) 285 + } 286 + clickOnViewWithId(R.id.fieldChangeActivityFilterType) 287 + } 288 + 289 + clickOnViewWithText(R.string.change_activity_filter_save) 290 + } 291 + 239 292 fun setCustomRange( 240 293 yearStarted: Int, 241 294 monthStarted: Int,
+39 -4
core/src/main/java/com/example/util/simpletimetracker/core/utils/TestUtils.kt
··· 12 12 import com.example.util.simpletimetracker.domain.interactor.RecordTypeCategoryInteractor 13 13 import com.example.util.simpletimetracker.domain.interactor.RecordTypeInteractor 14 14 import com.example.util.simpletimetracker.domain.interactor.RunningRecordInteractor 15 + import com.example.util.simpletimetracker.domain.model.ActivityFilter 15 16 import com.example.util.simpletimetracker.domain.model.AppColor 16 17 import com.example.util.simpletimetracker.domain.model.Category 17 18 import com.example.util.simpletimetracker.domain.model.DayOfWeek ··· 154 155 recordTagInteractor.add(data) 155 156 } 156 157 157 - fun getTypeId(typeName: String): Long = runBlocking { 158 - recordTypeInteractor.getAll() 159 - .firstOrNull { it.name == typeName } 160 - ?.id.orZero() 158 + fun addActivityFilter( 159 + name: String, 160 + type: ActivityFilter.Type, 161 + color: Int? = null, 162 + colorInt: Int? = null, 163 + names: List<String> = emptyList(), 164 + selected: Boolean = false, 165 + ) = runBlocking { 166 + val colors = ColorMapper.getAvailableColors() 167 + val colorId = colors.indexOf(color).takeUnless { it == -1 } 168 + ?: (0..colors.size).random() 169 + val availableCategories = categoryInteractor.getAll() 170 + val availableTypes = recordTypeInteractor.getAll() 171 + val selectedIds = names 172 + .mapNotNull { name -> 173 + when (type) { 174 + is ActivityFilter.Type.Activity -> { 175 + availableTypes.firstOrNull { it.name == name }?.id 176 + } 177 + is ActivityFilter.Type.Category -> { 178 + availableCategories.firstOrNull { it.name == name }?.id 179 + } 180 + } 181 + } 182 + .takeUnless { 183 + it.isEmpty() 184 + } 185 + .orEmpty() 186 + 187 + val data = ActivityFilter( 188 + selectedIds = selectedIds, 189 + type = type, 190 + name = name, 191 + color = AppColor(colorId = colorId, colorInt = colorInt?.toString().orEmpty()), 192 + selected = selected, 193 + ) 194 + 195 + activityFilterInteractor.add(data) 161 196 } 162 197 }