Skip to content

Commit 24b14c3

Browse files
committed
add test path to capture screenshots
1 parent c571c25 commit 24b14c3

File tree

5 files changed

+207
-3
lines changed

5 files changed

+207
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
package com.example.util.simpletimetracker
2+
3+
import androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA
4+
import androidx.test.espresso.matcher.ViewMatchers.withId
5+
import androidx.test.espresso.matcher.ViewMatchers.withText
6+
import androidx.test.ext.junit.runners.AndroidJUnit4
7+
import com.example.util.simpletimetracker.core.mapper.ColorMapper
8+
import com.example.util.simpletimetracker.domain.recordType.model.CardOrder
9+
import com.example.util.simpletimetracker.domain.recordType.model.RecordType
10+
import com.example.util.simpletimetracker.domain.statistics.model.RangeLength
11+
import com.example.util.simpletimetracker.feature_change_record.R
12+
import com.example.util.simpletimetracker.utils.BaseUiTest
13+
import com.example.util.simpletimetracker.utils.clickOnRecyclerItem
14+
import com.example.util.simpletimetracker.utils.clickOnViewWithText
15+
import com.example.util.simpletimetracker.utils.getMillis
16+
import com.example.util.simpletimetracker.utils.longClickOnView
17+
import com.example.util.simpletimetracker.utils.tryAction
18+
import dagger.hilt.android.testing.HiltAndroidTest
19+
import kotlinx.coroutines.runBlocking
20+
import org.hamcrest.Matchers.allOf
21+
import org.junit.Test
22+
import org.junit.runner.RunWith
23+
import java.util.Calendar
24+
import java.util.concurrent.TimeUnit
25+
26+
@HiltAndroidTest
27+
@RunWith(AndroidJUnit4::class)
28+
class ScreenCaptureTest : BaseUiTest() {
29+
30+
@Test
31+
fun screenshots() {
32+
val colors = ColorMapper.getAvailableColors()
33+
val icons = iconImageMapper
34+
.getAvailableImages(loadSearchHints = false).values
35+
.flatten().associateBy { it.iconName }.mapValues { it.value.iconResId }
36+
val readType = "Read"
37+
val guitarType = "Guitar"
38+
val readTag = "Mody Dick"
39+
val readComment = "I think it's related to the whale"
40+
41+
// Add data
42+
runBlocking {
43+
prefsInteractor.setCardOrder(CardOrder.COLOR)
44+
prefsInteractor.setNumberOfCards(5)
45+
prefsInteractor.setShowNotifications(true)
46+
prefsInteractor.setEnableRepeatButton(true)
47+
prefsInteractor.setStatisticsDetailRange(RangeLength.All)
48+
val pomodoroStarted = System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(7)
49+
prefsInteractor.setPomodoroModeStartedTimestampMs(pomodoroStarted)
50+
}
51+
defaultTypes.forEach { type ->
52+
testUtils.addActivity(
53+
name = type.name,
54+
color = colors.getOrNull(type.colorId),
55+
icon = icons[type.icon],
56+
goals = if (type.goal != null) {
57+
GoalsTestUtils.getDailyDurationGoal(type.goal * 60L).let(::listOf)
58+
} else {
59+
emptyList()
60+
},
61+
)
62+
}
63+
testUtils.addRecordTag(tagName = readTag, typeName = readType)
64+
runBlocking {
65+
val filteredInStatistics = listOf("Work", "Sleep", "Commute")
66+
recordTypeRepo.getAll()
67+
.filter { it.name in filteredInStatistics }
68+
.map(RecordType::id)
69+
.let { prefsInteractor.setFilteredTypes(it) }
70+
}
71+
Thread.sleep(1000)
72+
73+
// Records list from June 2 2020
74+
val currentTime = System.currentTimeMillis()
75+
val calendar = Calendar.getInstance().apply {
76+
timeInMillis = currentTime - TimeUnit.DAYS.toMillis(2)
77+
}
78+
testUtils.addRecord("Read", calendar.getMillis(0, 0), calendar.getMillis(0, 20))
79+
testUtils.addRecord("Sleep", calendar.getMillis(0, 20), calendar.getMillis(8, 12))
80+
testUtils.addRecord("Breakfast", calendar.getMillis(8, 12), calendar.getMillis(8, 27))
81+
testUtils.addRecord("Work", calendar.getMillis(8, 27), calendar.getMillis(10, 28))
82+
testUtils.addRecord("Youtube", calendar.getMillis(10, 28), calendar.getMillis(10, 48))
83+
testUtils.addRecord("Work", calendar.getMillis(10, 48), calendar.getMillis(13, 0))
84+
testUtils.addRecord("Cooking", calendar.getMillis(13, 34), calendar.getMillis(13, 52))
85+
testUtils.addRecord("Youtube", calendar.getMillis(13, 34), calendar.getMillis(13, 42))
86+
testUtils.addRecord("Exercise", calendar.getMillis(13, 42), calendar.getMillis(13, 47))
87+
testUtils.addRecord("Youtube", calendar.getMillis(13, 47), calendar.getMillis(14, 32))
88+
testUtils.addRecord("Lunch", calendar.getMillis(13, 52), calendar.getMillis(14, 22))
89+
testUtils.addRecord("Work", calendar.getMillis(14, 32), calendar.getMillis(19, 33))
90+
testUtils.addRecord("Exercise", calendar.getMillis(19, 33), calendar.getMillis(19, 57))
91+
testUtils.addRecord("Language", calendar.getMillis(19, 36), calendar.getMillis(19, 57))
92+
testUtils.addRecord("Cooking", calendar.getMillis(19, 57), calendar.getMillis(20, 15))
93+
testUtils.addRecord("Youtube", calendar.getMillis(19, 57, 1), calendar.getMillis(23, 23))
94+
testUtils.addRecord("Dinner", calendar.getMillis(20, 15), calendar.getMillis(20, 39))
95+
testUtils.addRecord("Guitar", calendar.getMillis(20, 39), calendar.getMillis(22, 4))
96+
testUtils.addRecord("Meditate", calendar.getMillis(23, 23), calendar.getMillis(23, 29))
97+
testUtils.addRecord(
98+
typeName = "Read",
99+
timeStarted = calendar.getMillis(23, 38),
100+
timeEnded = calendar.getMillis(23, 59, 59) + TimeUnit.MINUTES.toMillis(8),
101+
tagNames = listOf(readTag),
102+
comment = readComment,
103+
)
104+
105+
// For detailed statistics, 551 records total, duration 495h 25m.
106+
val durationsMinutes = listOf(60 + 24, 60 + 3, 60 + 25, 55, 49, 40, 42, 34, 46, 45, 45, 60 + 22)
107+
durationsMinutes.forEachIndexed { index, minutes ->
108+
if (index == 2) return@forEachIndexed // Already added.
109+
val timeStarted = calendar.apply {
110+
timeInMillis = currentTime
111+
set(Calendar.HOUR_OF_DAY, 12)
112+
set(Calendar.MINUTE, 0)
113+
add(Calendar.DATE, -index)
114+
}.timeInMillis
115+
testUtils.addRecord(
116+
typeName = guitarType,
117+
timeStarted = timeStarted,
118+
timeEnded = timeStarted + TimeUnit.MINUTES.toMillis(minutes.toLong()),
119+
)
120+
}
121+
val timeEnded = calendar.apply {
122+
timeInMillis = currentTime
123+
set(Calendar.HOUR_OF_DAY, 12)
124+
set(Calendar.MINUTE, 0)
125+
add(Calendar.DATE, -100)
126+
}.timeInMillis
127+
val additionalRecords = 550 - durationsMinutes.size
128+
val additionalRecordsDuration = TimeUnit.MINUTES.toMillis(30)
129+
repeat(additionalRecords) {
130+
testUtils.addRecord(guitarType, timeEnded - additionalRecordsDuration, timeEnded)
131+
}
132+
val desiredDuration = 495 * 60 + 25
133+
val additionalRecordDuration = desiredDuration -
134+
durationsMinutes.sum() -
135+
additionalRecords * 30
136+
val additionalRecordDurationMillis = TimeUnit.MINUTES.toMillis(additionalRecordDuration.toLong())
137+
testUtils.addRecord(guitarType, timeEnded - additionalRecordDurationMillis, timeEnded)
138+
139+
// Main tab
140+
val hour = TimeUnit.HOURS.toMillis(1)
141+
testUtils.addRecord("Language", currentTime - hour, currentTime)
142+
testUtils.addRecord("Meditate", currentTime - hour, currentTime)
143+
tryAction { clickOnViewWithText(readType) }
144+
longClickOnView(allOf(isDescendantOfA(withId(R.id.viewRunningRecordItem)), withText(readType)))
145+
clickOnViewWithText("-30")
146+
clickOnViewWithText("+1")
147+
clickOnViewWithText(R.string.change_record_tag_field)
148+
clickOnRecyclerItem(R.id.rvChangeRecordCategories, withText(readTag))
149+
clickOnViewWithText(R.string.change_record_save)
150+
}
151+
152+
companion object {
153+
private data class DefaultRecordType(
154+
val name: String,
155+
val icon: String,
156+
val colorId: Int,
157+
val goal: Int? = null, // Minutes
158+
)
159+
160+
private val defaultTypes: List<DefaultRecordType> by lazy {
161+
listOf(
162+
DefaultRecordType(name = "Games", icon = "ic_headset_24px", colorId = 1),
163+
DefaultRecordType(name = "Tv", icon = "ic_desktop_windows_24px", colorId = 1),
164+
DefaultRecordType(name = "Youtube", icon = "ic_ondemand_video_24px", colorId = 1),
165+
166+
DefaultRecordType(name = "Exercise", icon = "ic_fitness_center_24px", colorId = 3),
167+
DefaultRecordType(name = "Guitar", icon = "ic_audiotrack_24px", colorId = 3),
168+
DefaultRecordType(name = "Language", icon = "ic_chat_24px", colorId = 3, goal = 5),
169+
DefaultRecordType(name = "Meditate", icon = "ic_lightbulb_outline_24px", colorId = 3, goal = 5),
170+
DefaultRecordType(name = "Read", icon = "ic_import_contacts_24px", colorId = 3, goal = 30),
171+
172+
DefaultRecordType(name = "Chores", icon = "ic_assignment_24px", colorId = 5),
173+
DefaultRecordType(name = "Cleaning", icon = "ic_delete_24px", colorId = 5),
174+
DefaultRecordType(name = "Indoors", icon = "ic_extension_24px", colorId = 5),
175+
DefaultRecordType(name = "Outdoors", icon = "ic_directions_walk_24px", colorId = 5),
176+
DefaultRecordType(name = "Shopping", icon = "ic_shopping_cart_24px", colorId = 5),
177+
178+
DefaultRecordType(name = "Breakfast", icon = "ic_free_breakfast_24px", colorId = 7),
179+
DefaultRecordType(name = "Cooking", icon = "ic_restaurant_menu_24px", colorId = 7),
180+
DefaultRecordType(name = "Dinner", icon = "ic_local_bar_24px", colorId = 7),
181+
DefaultRecordType(name = "Lunch", icon = "ic_restaurant_24px", colorId = 7),
182+
183+
DefaultRecordType(name = "Commute", icon = "ic_airport_shuttle_24px", colorId = 10),
184+
DefaultRecordType(name = "Sleep", icon = "ic_airline_seat_individual_suite_24px", colorId = 10),
185+
DefaultRecordType(name = "Work", icon = "ic_business_center_24px", colorId = 10, goal = 8 * 60),
186+
)
187+
}
188+
}
189+
}

app/src/androidTest/java/com/example/util/simpletimetracker/utils/BaseUiTest.kt

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import com.example.util.simpletimetracker.core.utils.TestUtils
1919
import com.example.util.simpletimetracker.domain.prefs.interactor.PrefsInteractor
2020
import com.example.util.simpletimetracker.domain.complexRule.repo.ComplexRuleRepo
2121
import com.example.util.simpletimetracker.domain.backup.repo.BackupRepo
22+
import com.example.util.simpletimetracker.domain.recordType.repo.RecordTypeRepo
2223
import com.example.util.simpletimetracker.feature_records.view.RecordsContainerFragment
2324
import com.example.util.simpletimetracker.feature_settings.viewModel.delegate.SettingsFileWorkDelegate
2425
import com.example.util.simpletimetracker.feature_statistics.view.StatisticsContainerFragment
@@ -62,6 +63,9 @@ open class BaseUiTest {
6263
@Inject
6364
lateinit var backupRepo: BackupRepo
6465

66+
@Inject
67+
lateinit var recordTypeRepo: RecordTypeRepo
68+
6569
@get:Rule(order = 0)
6670
var hiltRule = HiltAndroidRule(this)
6771

app/src/androidTest/java/com/example/util/simpletimetracker/utils/Extensions.kt

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@ package com.example.util.simpletimetracker.utils
22

33
import java.util.Calendar
44

5-
fun Calendar.getMillis(hour: Int, minute: Int = 0, millis: Int = 0): Long {
5+
fun Calendar.getMillis(
6+
hour: Int,
7+
minute: Int = 0,
8+
seconds: Int = 0,
9+
millis: Int = 0,
10+
): Long {
611
set(Calendar.HOUR_OF_DAY, hour)
712
set(Calendar.MINUTE, minute)
13+
set(Calendar.SECOND, seconds)
814
set(Calendar.MILLISECOND, millis)
915
return timeInMillis
1016
}

features/feature_notification/src/main/java/com/example/util/simpletimetracker/feature_notification/recordType/interactor/ActivityStartStopFromBroadcastInteractor.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ class ActivityStartStopFromBroadcastInteractor @Inject constructor(
2828
suspend fun onActionActivityStop(
2929
typeId: Long,
3030
) {
31-
val runningRecord = runningRecordInteractor.get(typeId)
32-
?: return // Not running.
31+
val runningRecord = runningRecordInteractor.get(typeId) ?: run {
32+
notificationTypeInteractor.checkAndHide(typeId)
33+
return // Not running.
34+
}
3335

3436
removeRunningRecordMediator.removeWithRecordAdd(
3537
runningRecord = runningRecord,

features/feature_statistics_detail/src/main/java/com/example/util/simpletimetracker/feature_statistics_detail/interactor/StatisticsDetailSplitChartInteractor.kt

+3
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ class StatisticsDetailSplitChartInteractor @Inject constructor(
231231
startOfDayShift: Long,
232232
splitRecords: MutableList<Range> = mutableListOf(),
233233
): List<Range> {
234+
// Avoid infinite loop.
235+
if (record.duration < 0) return emptyList()
236+
234237
val rangeCheck = when (splitChartGrouping) {
235238
SplitChartGrouping.HOURLY -> timeMapper.sameHour(
236239
date1 = record.timeStarted,

0 commit comments

Comments
 (0)