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 new tests

razeeman (May 6, 2023, 8:00 PM +0300) 8df075cf 61cb4e8c

+584 -6
+284
app/src/androidTest/java/com/example/util/simpletimetracker/RecordActionsDuplicateTest.kt
··· 1 + package com.example.util.simpletimetracker 2 + 3 + import androidx.test.espresso.Espresso.closeSoftKeyboard 4 + import androidx.test.espresso.Espresso.onView 5 + import androidx.test.espresso.Espresso.pressBack 6 + import androidx.test.espresso.action.ViewActions.click 7 + import androidx.test.espresso.matcher.ViewMatchers.hasDescendant 8 + import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed 9 + import androidx.test.espresso.matcher.ViewMatchers.withId 10 + import androidx.test.espresso.matcher.ViewMatchers.withText 11 + import androidx.test.ext.junit.runners.AndroidJUnit4 12 + import com.example.util.simpletimetracker.utils.BaseUiTest 13 + import com.example.util.simpletimetracker.utils.NavUtils 14 + import com.example.util.simpletimetracker.utils.checkViewIsDisplayed 15 + import com.example.util.simpletimetracker.utils.checkViewIsNotDisplayed 16 + import com.example.util.simpletimetracker.utils.clickOnRecyclerItem 17 + import com.example.util.simpletimetracker.utils.clickOnView 18 + import com.example.util.simpletimetracker.utils.clickOnViewWithId 19 + import com.example.util.simpletimetracker.utils.clickOnViewWithText 20 + import com.example.util.simpletimetracker.utils.getMillis 21 + import com.example.util.simpletimetracker.utils.longClickOnView 22 + import com.example.util.simpletimetracker.utils.nestedScrollTo 23 + import com.example.util.simpletimetracker.utils.nthChildOf 24 + import com.example.util.simpletimetracker.utils.recyclerItemCount 25 + import com.example.util.simpletimetracker.utils.tryAction 26 + import com.example.util.simpletimetracker.utils.typeTextIntoView 27 + import com.example.util.simpletimetracker.utils.withCardColor 28 + import com.example.util.simpletimetracker.utils.withTag 29 + import dagger.hilt.android.testing.HiltAndroidTest 30 + import java.util.Calendar 31 + import java.util.concurrent.TimeUnit 32 + import kotlinx.coroutines.runBlocking 33 + import org.hamcrest.CoreMatchers.allOf 34 + import org.junit.Test 35 + import org.junit.runner.RunWith 36 + import com.example.util.simpletimetracker.core.R as coreR 37 + import com.example.util.simpletimetracker.feature_base_adapter.R as baseR 38 + import com.example.util.simpletimetracker.feature_change_record.R as changeRecordR 39 + import com.example.util.simpletimetracker.feature_records.R as recordsR 40 + 41 + @HiltAndroidTest 42 + @RunWith(AndroidJUnit4::class) 43 + class RecordActionsDuplicateTest : BaseUiTest() { 44 + 45 + @Test 46 + fun duplicateVisibility() { 47 + val name = "Name" 48 + 49 + // Setup 50 + testUtils.addActivity(name) 51 + testUtils.addRecord(name) 52 + testUtils.addRunningRecord(name) 53 + Thread.sleep(1000) 54 + 55 + // Running record - not shown 56 + tryAction { 57 + longClickOnView( 58 + allOf(withId(baseR.id.viewRunningRecordItem), hasDescendant(withText(name)), isCompletelyDisplayed()) 59 + ) 60 + } 61 + clickOnViewWithText(coreR.string.change_record_actions_hint) 62 + checkViewIsNotDisplayed(withText(coreR.string.change_record_duplicate)) 63 + pressBack() 64 + 65 + // Record - shown 66 + NavUtils.openRecordsScreen() 67 + clickOnView( 68 + allOf(withId(baseR.id.viewRecordItem), hasDescendant(withText(name)), isCompletelyDisplayed()) 69 + ) 70 + clickOnViewWithText(coreR.string.change_record_actions_hint) 71 + onView(withText(coreR.string.change_record_duplicate)).perform(nestedScrollTo()) 72 + checkViewIsDisplayed(withText(coreR.string.change_record_duplicate)) 73 + } 74 + 75 + @Test 76 + fun duplicateRecord() { 77 + val name = "Name" 78 + val color = firstColor 79 + val icon = firstIcon 80 + val comment = "Some_comment" 81 + val tag = "Tag" 82 + val fullName = "$name - $tag" 83 + val calendar = Calendar.getInstance() 84 + 85 + // Setup 86 + val current = calendar.timeInMillis 87 + val difference = TimeUnit.MINUTES.toMillis(30) 88 + val timeStartedTimestamp = current - difference 89 + val timeStartedPreview = timeStartedTimestamp.formatTime() 90 + val timeEndedPreview = current.formatTime() 91 + val timeRangePreview = difference.formatInterval() 92 + 93 + testUtils.addActivity(name = name, color = color, icon = icon) 94 + testUtils.addRecordTag(tag) 95 + testUtils.addRecord( 96 + typeName = name, 97 + timeStarted = timeStartedTimestamp, 98 + timeEnded = current, 99 + tagNames = listOf(tag), 100 + comment = comment 101 + ) 102 + 103 + // Check record 104 + NavUtils.openRecordsScreen() 105 + onView(allOf(withId(recordsR.id.rvRecordsList), isCompletelyDisplayed())) 106 + .check(recyclerItemCount(2)) 107 + checkRecord( 108 + recordsR.id.rvRecordsList, 109 + listOf(0), 110 + fullName, 111 + timeStartedPreview, 112 + timeEndedPreview, 113 + timeRangePreview, 114 + comment 115 + ) 116 + 117 + // Continue 118 + clickOnViewWithText(fullName) 119 + clickOnViewWithText(coreR.string.change_record_actions_hint) 120 + onView(withText(coreR.string.change_record_duplicate)).perform(nestedScrollTo(), click()) 121 + 122 + tryAction { 123 + onView(allOf(withId(recordsR.id.rvRecordsList), isCompletelyDisplayed())) 124 + .check(recyclerItemCount(3)) 125 + } 126 + checkRecord( 127 + recordsR.id.rvRecordsList, 128 + listOf(0, 1), 129 + fullName, 130 + timeStartedPreview, 131 + timeEndedPreview, 132 + timeRangePreview, 133 + comment 134 + ) 135 + } 136 + 137 + @Test 138 + fun duplicateUntrackedRecord() { 139 + val name = "Name" 140 + val comment = "Some_comment" 141 + val calendar = Calendar.getInstance() 142 + 143 + // Setup 144 + val current = calendar.timeInMillis 145 + val startOfDay = calendar.getMillis(0, 0) 146 + val timeStartedPreview = startOfDay.formatTime() 147 + val timeEndedPreview = current.formatTime() 148 + val timeRangePreview = (current - startOfDay).formatInterval() 149 + 150 + testUtils.addActivity(name) 151 + runBlocking { prefsInteractor.setShowUntrackedInRecords(true) } 152 + NavUtils.openRecordsScreen() 153 + 154 + // Open untracked time 155 + checkViewIsDisplayed( 156 + allOf( 157 + withId(baseR.id.viewRecordItem), 158 + hasDescendant(withText(coreR.string.untracked_time_name)), 159 + hasDescendant(withText(timeStartedPreview)), 160 + hasDescendant(withText(timeEndedPreview)), 161 + hasDescendant(withText(timeRangePreview)), 162 + isCompletelyDisplayed() 163 + ) 164 + ) 165 + onView(allOf(withId(recordsR.id.rvRecordsList), isCompletelyDisplayed())) 166 + .check(recyclerItemCount(2)) 167 + clickOnViewWithText(coreR.string.untracked_time_name) 168 + 169 + // Duplicate untracked doesn't work 170 + clickOnViewWithText(coreR.string.change_record_actions_hint) 171 + onView(withText(coreR.string.change_record_duplicate)).perform(nestedScrollTo(), click()) 172 + clickOnViewWithId(com.google.android.material.R.id.snackbar_text) 173 + clickOnViewWithText(coreR.string.change_record_actions_hint) 174 + 175 + // Select activity 176 + clickOnViewWithText(coreR.string.change_record_type_field) 177 + clickOnRecyclerItem(changeRecordR.id.rvChangeRecordType, withText(name)) 178 + clickOnViewWithText(coreR.string.change_record_comment_field) 179 + typeTextIntoView(changeRecordR.id.etChangeRecordComment, comment) 180 + closeSoftKeyboard() 181 + clickOnViewWithText(coreR.string.change_record_comment_field) 182 + 183 + // Duplicate 184 + clickOnViewWithText(coreR.string.change_record_actions_hint) 185 + onView(withText(coreR.string.change_record_duplicate)).perform(nestedScrollTo(), click()) 186 + 187 + tryAction { 188 + onView(allOf(withId(recordsR.id.rvRecordsList), isCompletelyDisplayed())) 189 + .check(recyclerItemCount(3)) 190 + } 191 + checkRecord( 192 + recordsR.id.rvRecordsList, 193 + listOf(0, 1), 194 + name, 195 + timeStartedPreview, 196 + timeEndedPreview, 197 + timeRangePreview, 198 + comment 199 + ) 200 + } 201 + 202 + @Test 203 + fun duplicateNewRecord() { 204 + val name = "Name" 205 + val comment = "Some_comment" 206 + val calendar = Calendar.getInstance() 207 + 208 + // Setup 209 + val current = calendar.timeInMillis 210 + val difference = TimeUnit.HOURS.toMillis(1) 211 + val timeStartedTimestamp = current - difference 212 + val timeStartedPreview = timeStartedTimestamp.formatTime() 213 + val timeEndedPreview = current.formatTime() 214 + val timeRangePreview = difference.formatInterval() 215 + 216 + testUtils.addActivity(name) 217 + NavUtils.openRecordsScreen() 218 + 219 + // Open add new record 220 + onView(allOf(withId(recordsR.id.rvRecordsList), isCompletelyDisplayed())) 221 + .check(recyclerItemCount(1)) 222 + clickOnViewWithId(recordsR.id.btnRecordAdd) 223 + 224 + // Duplicate untracked doesn't work 225 + clickOnViewWithText(coreR.string.change_record_actions_hint) 226 + onView(withText(coreR.string.change_record_duplicate)).perform(nestedScrollTo(), click()) 227 + clickOnViewWithId(com.google.android.material.R.id.snackbar_text) 228 + clickOnViewWithText(coreR.string.change_record_actions_hint) 229 + 230 + // Select activity 231 + clickOnViewWithText(coreR.string.change_record_type_field) 232 + clickOnRecyclerItem(changeRecordR.id.rvChangeRecordType, withText(name)) 233 + clickOnViewWithText(coreR.string.change_record_comment_field) 234 + typeTextIntoView(changeRecordR.id.etChangeRecordComment, comment) 235 + closeSoftKeyboard() 236 + clickOnViewWithText(coreR.string.change_record_comment_field) 237 + 238 + // Duplicate 239 + clickOnViewWithText(coreR.string.change_record_actions_hint) 240 + onView(withText(coreR.string.change_record_duplicate)).perform(nestedScrollTo(), click()) 241 + 242 + tryAction { 243 + onView(allOf(withId(recordsR.id.rvRecordsList), isCompletelyDisplayed())) 244 + .check(recyclerItemCount(3)) 245 + } 246 + checkRecord( 247 + recordsR.id.rvRecordsList, 248 + listOf(0, 1), 249 + name, 250 + timeStartedPreview, 251 + timeEndedPreview, 252 + timeRangePreview, 253 + comment 254 + ) 255 + } 256 + 257 + @Suppress("SameParameterValue") 258 + private fun checkRecord( 259 + parentId: Int, 260 + indexes: List<Int>, 261 + name: String, 262 + timeStartedPreview: String, 263 + timeEndedPreview: String, 264 + timeRangePreview: String, 265 + comment: String, 266 + ) { 267 + indexes.forEach { index -> 268 + checkViewIsDisplayed( 269 + allOf( 270 + nthChildOf(withId(parentId), index), 271 + withId(baseR.id.viewRecordItem), 272 + withCardColor(firstColor), 273 + hasDescendant(withText(name)), 274 + hasDescendant(withTag(firstIcon)), 275 + hasDescendant(withText(timeStartedPreview)), 276 + hasDescendant(withText(timeEndedPreview)), 277 + hasDescendant(withText(timeRangePreview)), 278 + hasDescendant(withText(comment)), 279 + isCompletelyDisplayed() 280 + ) 281 + ) 282 + } 283 + } 284 + }
+26
app/src/androidTest/java/com/example/util/simpletimetracker/SettingsTest.kt
··· 255 255 } 256 256 257 257 @Test 258 + fun showNotificationsControls() { 259 + NavUtils.openSettingsScreen() 260 + NavUtils.openSettingsNotifications() 261 + 262 + // Check settings 263 + onView(withId(settingsR.id.checkboxSettingsShowNotifications)).perform(nestedScrollTo()) 264 + checkViewIsNotDisplayed(withText(coreR.string.settings_show_notifications_controls)) 265 + checkViewIsNotDisplayed(withId(settingsR.id.checkboxSettingsShowNotificationsControls)) 266 + 267 + unconstrainedClickOnView(withId(settingsR.id.checkboxSettingsShowNotifications)) 268 + onView(withId(settingsR.id.checkboxSettingsShowNotificationsControls)).perform(nestedScrollTo()) 269 + checkViewIsDisplayed(withText(coreR.string.settings_show_notifications_controls)) 270 + onView(withId(settingsR.id.checkboxSettingsShowNotificationsControls)).check(matches(isChecked())) 271 + unconstrainedClickOnView(withId(settingsR.id.checkboxSettingsShowNotificationsControls)) 272 + onView(withId(settingsR.id.checkboxSettingsShowNotificationsControls)).check(matches(isNotChecked())) 273 + unconstrainedClickOnView(withId(settingsR.id.checkboxSettingsShowNotificationsControls)) 274 + onView(withId(settingsR.id.checkboxSettingsShowNotificationsControls)).check(matches(isChecked())) 275 + 276 + // Change settings 277 + onView(withId(settingsR.id.checkboxSettingsShowNotifications)).perform(nestedScrollTo()) 278 + unconstrainedClickOnView(withId(settingsR.id.checkboxSettingsShowNotifications)) 279 + checkViewIsNotDisplayed(withText(coreR.string.settings_show_notifications_controls)) 280 + checkViewIsNotDisplayed(withId(settingsR.id.checkboxSettingsShowNotificationsControls)) 281 + } 282 + 283 + @Test 258 284 fun enableEnableDarkMode() { 259 285 val name1 = "Test1" 260 286 val name2 = "Test2"
+254 -4
app/src/androidTest/java/com/example/util/simpletimetracker/StatisticsTest.kt
··· 97 97 ) 98 98 checkViewIsDisplayed( 99 99 allOf( 100 + withId(baseR.id.viewStatisticsItem), 101 + hasDescendant(withText(coreR.string.untracked_time_name)), 102 + hasDescendant(withSubstring("<1%")), 103 + isCompletelyDisplayed() 104 + ) 105 + ) 106 + checkViewIsDisplayed( 107 + allOf( 100 108 withId(statisticsR.id.tvStatisticsInfoText), 101 109 withText("2$hourString 0$minuteString") 102 110 ) ··· 115 123 val typeName2 = "Type2" 116 124 val typeName3 = "Type3" 117 125 val typeName4 = "Type4" 126 + val typeName5 = "Type5" 118 127 val categoryName1 = "Category1" 119 128 val categoryName2 = "Category2" 120 129 val categoryName3 = "Category3" ··· 133 142 testUtils.addActivity(name = typeName2, categories = listOf(categoryName1)) 134 143 testUtils.addActivity(name = typeName3, categories = listOf(categoryName2)) 135 144 testUtils.addActivity(name = typeName4, categories = listOf(categoryName1, categoryName2)) 145 + testUtils.addActivity(name = typeName5) 136 146 137 147 // Add records 138 148 NavUtils.openRecordsScreen() ··· 140 150 testUtils.addRecord(typeName2) 141 151 testUtils.addRecord(typeName3) 142 152 testUtils.addRecord(typeName4) 153 + testUtils.addRecord(typeName5) 143 154 144 155 NavUtils.openStatisticsScreen() 145 156 clickOnViewWithIdOnPager(statisticsR.id.btnStatisticsChartFilter) ··· 182 193 withId(baseR.id.viewStatisticsItem), 183 194 withCardColor(firstColor), 184 195 hasDescendant(withText(categoryName1)), 185 - hasDescendant(withSubstring("60%")), 196 + hasDescendant(withSubstring("50%")), 186 197 isCompletelyDisplayed() 187 198 ) 188 199 ) ··· 191 202 withId(baseR.id.viewStatisticsItem), 192 203 withCardColor(lastColor), 193 204 hasDescendant(withText(categoryName2)), 194 - hasDescendant(withSubstring("40%")), 205 + hasDescendant(withSubstring("33%")), 206 + isCompletelyDisplayed() 207 + ) 208 + ) 209 + checkViewIsDisplayed( 210 + allOf( 211 + withId(baseR.id.viewStatisticsItem), 212 + hasDescendant(withText(coreR.string.uncategorized_time_name)), 213 + hasDescendant(withSubstring("17%")), 214 + isCompletelyDisplayed() 215 + ) 216 + ) 217 + checkViewIsDisplayed( 218 + allOf( 219 + withId(baseR.id.viewStatisticsItem), 220 + hasDescendant(withText(coreR.string.untracked_time_name)), 221 + hasDescendant(withSubstring("<1%")), 195 222 isCompletelyDisplayed() 196 223 ) 197 224 ) 198 225 checkViewIsDisplayed( 199 226 allOf( 200 227 withId(statisticsR.id.tvStatisticsInfoText), 201 - withText("5$hourString 0$minuteString") 228 + withText("6$hourString 0$minuteString") 202 229 ) 203 230 ) 204 231 checkViewIsDisplayed( ··· 211 238 allOf( 212 239 withId(baseR.id.viewStatisticsItem), 213 240 hasDescendant(withText(categoryName3)) 241 + ) 242 + ) 243 + } 244 + 245 + @Test 246 + fun statisticsTags() { 247 + val typeName1 = "Type1" 248 + val typeName2 = "Type2" 249 + val typeName3 = "Type3" 250 + val typeName4 = "Type4" 251 + val tagName1 = "Tag1" 252 + val tagName2 = "Tag2" 253 + val tagName3 = "Tag3" 254 + 255 + // Add activities 256 + NavUtils.openRunningRecordsScreen() 257 + testUtils.addActivity(name = typeName1, color = firstColor) 258 + testUtils.addActivity(name = typeName2) 259 + testUtils.addActivity(name = typeName3) 260 + testUtils.addActivity(name = typeName4) 261 + 262 + // Add tags 263 + NavUtils.openSettingsScreen() 264 + NavUtils.openCategoriesScreen() 265 + NavUtils.addRecordTag(tagName1, typeName1) 266 + NavUtils.addRecordTag(tagName2, null, lastColor) 267 + NavUtils.addRecordTag(tagName3) 268 + pressBack() 269 + 270 + // Add records 271 + NavUtils.openRecordsScreen() 272 + testUtils.addRecord(typeName1, tagNames = listOf(tagName1)) 273 + testUtils.addRecord(typeName2, tagNames = listOf(tagName2)) 274 + testUtils.addRecord(typeName3, tagNames = listOf(tagName2)) 275 + testUtils.addRecord(typeName1, tagNames = listOf(tagName1, tagName2)) 276 + testUtils.addRecord(typeName4) 277 + 278 + NavUtils.openStatisticsScreen() 279 + clickOnViewWithIdOnPager(statisticsR.id.btnStatisticsChartFilter) 280 + clickOnViewWithText(coreR.string.record_tag_hint_short) 281 + pressBack() 282 + 283 + // Check day range 284 + clickOnViewWithId(statisticsR.id.btnStatisticsContainerToday) 285 + clickOnViewWithText(coreR.string.range_day) 286 + checkTagRange(firstColor, lastColor, tagName1, tagName2, tagName3) 287 + 288 + // Switch to week range 289 + clickOnView(allOf(withText(coreR.string.title_today), isCompletelyDisplayed())) 290 + clickOnViewWithText(coreR.string.range_week) 291 + checkTagRange(firstColor, lastColor, tagName1, tagName2, tagName3) 292 + 293 + // Switch to month range 294 + clickOnView(allOf(withText(coreR.string.title_this_week), isCompletelyDisplayed())) 295 + clickOnViewWithText(coreR.string.range_month) 296 + checkTagRange(firstColor, lastColor, tagName1, tagName2, tagName3) 297 + 298 + // Switch to year range 299 + clickOnView(allOf(withText(coreR.string.title_this_month), isCompletelyDisplayed())) 300 + clickOnViewWithText(coreR.string.range_year) 301 + checkTagRange(firstColor, lastColor, tagName1, tagName2, tagName3) 302 + 303 + // Switch to last days range 304 + clickOnView(allOf(withText(coreR.string.title_this_year), isCompletelyDisplayed())) 305 + clickOnViewWithText(coreR.string.range_last) 306 + checkTagRange(firstColor, lastColor, tagName1, tagName2, tagName3, checkPrevious = false) 307 + 308 + // Switch to overall range 309 + clickOnView(allOf(withText(coreR.string.range_last), isCompletelyDisplayed())) 310 + clickOnViewWithText(coreR.string.range_overall) 311 + Thread.sleep(1000) 312 + 313 + checkViewDoesNotExist(allOf(withText("3$hourString 0$minuteString"), isCompletelyDisplayed())) 314 + checkViewIsDisplayed( 315 + allOf( 316 + withId(baseR.id.viewStatisticsItem), 317 + withCardColor(firstColor), 318 + hasDescendant(withText(tagName1)), 319 + hasDescendant(withSubstring("33%")), 320 + isCompletelyDisplayed() 321 + ) 322 + ) 323 + checkViewIsDisplayed( 324 + allOf( 325 + withId(baseR.id.viewStatisticsItem), 326 + withCardColor(lastColor), 327 + hasDescendant(withText(tagName2)), 328 + hasDescendant(withSubstring("50%")), 329 + isCompletelyDisplayed() 330 + ) 331 + ) 332 + checkViewIsDisplayed( 333 + allOf( 334 + withId(baseR.id.viewStatisticsItem), 335 + hasDescendant(withText(coreR.string.change_record_untagged)), 336 + hasDescendant(withSubstring("17%")), 337 + isCompletelyDisplayed() 338 + ) 339 + ) 340 + checkViewIsDisplayed( 341 + allOf( 342 + withId(baseR.id.viewStatisticsItem), 343 + hasDescendant(withText(coreR.string.untracked_time_name)), 344 + hasDescendant(withSubstring("<1%")), 345 + isCompletelyDisplayed() 346 + ) 347 + ) 348 + checkViewIsDisplayed( 349 + allOf( 350 + withId(statisticsR.id.tvStatisticsInfoText), 351 + withText("6$hourString 0$minuteString") 352 + ) 353 + ) 354 + checkViewIsDisplayed( 355 + allOf( 356 + withText(coreR.string.statistics_hint), 357 + isCompletelyDisplayed() 358 + ) 359 + ) 360 + checkViewDoesNotExist( 361 + allOf( 362 + withId(baseR.id.viewStatisticsItem), 363 + hasDescendant(withText(tagName3)) 214 364 ) 215 365 ) 216 366 } ··· 334 484 ) 335 485 checkViewIsDisplayed( 336 486 allOf( 487 + withId(baseR.id.viewStatisticsItem), 488 + hasDescendant(withText(coreR.string.uncategorized_time_name)), 489 + hasDescendant(withText("1$hourString 0$minuteString")), 490 + hasDescendant(withSubstring("%")), 491 + isCompletelyDisplayed() 492 + ) 493 + ) 494 + checkViewIsDisplayed( 495 + allOf( 337 496 withId(statisticsR.id.tvStatisticsInfoText), 338 - withText("5$hourString 0$minuteString") 497 + withText("6$hourString 0$minuteString") 339 498 ) 340 499 ) 341 500 checkViewDoesNotExist( 342 501 allOf( 343 502 withId(baseR.id.viewStatisticsItem), 344 503 hasDescendant(withText(categoryName3)) 504 + ) 505 + ) 506 + checkViewIsDisplayed( 507 + allOf( 508 + withText(coreR.string.statistics_hint), 509 + isCompletelyDisplayed() 510 + ) 511 + ) 512 + if (!checkPrevious) return 513 + clickOnViewWithId(statisticsR.id.btnStatisticsContainerPrevious) 514 + checkViewIsDisplayed( 515 + allOf( 516 + withId(baseR.id.viewStatisticsItem), 517 + hasDescendant(withText(coreR.string.untracked_time_name)), 518 + hasDescendant(withText("100%")), 519 + hasDescendant(withSubstring("$hourString 0$minuteString")), 520 + isCompletelyDisplayed() 521 + ) 522 + ) 523 + checkViewIsDisplayed( 524 + allOf( 525 + withId(statisticsR.id.layoutStatisticsInfoItem), 526 + hasDescendant(withText(coreR.string.statistics_total_tracked)), 527 + hasDescendant(withText("0$secondString")), 528 + isCompletelyDisplayed() 529 + ) 530 + ) 531 + checkViewDoesNotExist( 532 + allOf( 533 + withText(coreR.string.statistics_hint), 534 + isCompletelyDisplayed() 535 + ) 536 + ) 537 + clickOnViewWithId(statisticsR.id.btnStatisticsContainerNext) 538 + } 539 + 540 + private fun checkTagRange( 541 + firstColor: Int, 542 + lastColor: Int, 543 + tagName1: String, 544 + tagName2: String, 545 + tagName3: String, 546 + checkPrevious: Boolean = true, 547 + ) { 548 + checkViewIsDisplayed( 549 + allOf( 550 + withId(baseR.id.viewStatisticsItem), 551 + hasDescendant(withText(coreR.string.untracked_time_name)), 552 + hasDescendant(withSubstring("%")), 553 + isCompletelyDisplayed() 554 + ) 555 + ) 556 + checkViewIsDisplayed( 557 + allOf( 558 + withId(baseR.id.viewStatisticsItem), 559 + withCardColor(firstColor), 560 + hasDescendant(withText(tagName1)), 561 + hasDescendant(withText("2$hourString 0$minuteString")), 562 + hasDescendant(withSubstring("%")), 563 + isCompletelyDisplayed() 564 + ) 565 + ) 566 + checkViewIsDisplayed( 567 + allOf( 568 + withId(baseR.id.viewStatisticsItem), 569 + withCardColor(lastColor), 570 + hasDescendant(withText(tagName2)), 571 + hasDescendant(withText("3$hourString 0$minuteString")), 572 + hasDescendant(withSubstring("%")), 573 + isCompletelyDisplayed() 574 + ) 575 + ) 576 + checkViewIsDisplayed( 577 + allOf( 578 + withId(baseR.id.viewStatisticsItem), 579 + hasDescendant(withText(coreR.string.change_record_untagged)), 580 + hasDescendant(withText("1$hourString 0$minuteString")), 581 + hasDescendant(withSubstring("%")), 582 + isCompletelyDisplayed() 583 + ) 584 + ) 585 + checkViewIsDisplayed( 586 + allOf( 587 + withId(statisticsR.id.tvStatisticsInfoText), 588 + withText("6$hourString 0$minuteString") 589 + ) 590 + ) 591 + checkViewDoesNotExist( 592 + allOf( 593 + withId(baseR.id.viewStatisticsItem), 594 + hasDescendant(withText(tagName3)) 345 595 ) 346 596 ) 347 597 checkViewIsDisplayed(
+19 -2
app/src/androidTest/java/com/example/util/simpletimetracker/utils/Matchers.kt
··· 1 1 package com.example.util.simpletimetracker.utils 2 2 3 3 import android.view.View 4 + import android.view.ViewGroup 4 5 import android.view.WindowManager 5 6 import android.widget.TextView 6 7 import androidx.annotation.ColorInt ··· 11 12 import androidx.test.espresso.matcher.BoundedMatcher 12 13 import androidx.test.espresso.matcher.ViewMatchers.withTagValue 13 14 import com.google.android.material.slider.Slider 15 + import kotlin.math.roundToInt 14 16 import org.hamcrest.CoreMatchers.equalTo 15 17 import org.hamcrest.Description 16 18 import org.hamcrest.Matcher 17 19 import org.hamcrest.TypeSafeMatcher 18 - import kotlin.math.roundToInt 19 20 20 21 fun withCardColor(expectedId: Int): Matcher<View> = 21 22 object : BoundedMatcher<View, CardView>(CardView::class.java) { ··· 82 83 override fun describeTo(description: Description) { 83 84 description.appendText("expected: $expectedValue") 84 85 } 85 - } 86 + } 87 + 88 + fun nthChildOf(parentMatcher: Matcher<View?>, childPosition: Int): Matcher<View> { 89 + return object : TypeSafeMatcher<View>() { 90 + override fun describeTo(description: Description) { 91 + description.appendText("with $childPosition child view of type parentMatcher") 92 + } 93 + 94 + override fun matchesSafely(view: View): Boolean { 95 + if (view.parent !is ViewGroup) { 96 + return parentMatcher.matches(view.parent) 97 + } 98 + val group: ViewGroup = view.parent as ViewGroup 99 + return parentMatcher.matches(view.parent) && group.getChildAt(childPosition).equals(view) 100 + } 101 + } 102 + }
+1
app/src/androidTest/java/com/example/util/simpletimetracker/utils/NavUtils.kt
··· 195 195 clickOnRecyclerItem(changeRecordTagR.id.rvChangeRecordTagType, withText(activity)) 196 196 } 197 197 198 + closeSoftKeyboard() 198 199 clickOnViewWithText(coreR.string.change_category_save) 199 200 } 200 201