Skip to content

Commit 000ed35

Browse files
committed
tests: screenshot tests for ScheduleReminders, AddEditReminderDialog
Screenshot tests for the two key review reminder UI interfaces. In particular, making sure the ScheduleRemindersFragment looks good no matter where it is opened from. As edits to the UI accumulate over the coming years, we don't want ScheduleRemindersFragment to silently regress in one of the four hosts. Instrumented tests coming soon. Assisted-by: Claude Sonnet 4.6 Medium [Initial test drafts]
1 parent 846851d commit 000ed35

2 files changed

Lines changed: 216 additions & 0 deletions

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
// Copyright (c) 2026 Eric Li <ericli3690@gmail.com>
3+
4+
package com.ichi2.anki.reviewreminders
5+
6+
import android.view.View
7+
import androidx.fragment.app.FragmentActivity
8+
import com.ichi2.anki.R
9+
import com.ichi2.anki.ScreenshotTest
10+
import com.ichi2.anki.reviewreminders.AddEditReminderDialog.DialogMode
11+
import org.junit.Test
12+
import org.robolectric.Robolectric.buildActivity
13+
14+
class AddEditReminderDialogScreenshotTest : ScreenshotTest() {
15+
@Test
16+
fun `add mode`() {
17+
val activity = buildActivity(FragmentActivity::class.java).setup().get()
18+
AddEditReminderDialog
19+
.getInstance(DialogMode.Add(ReviewReminderScope.Global))
20+
.show(activity.supportFragmentManager, "dialog")
21+
advanceRobolectricLooper()
22+
captureScreen("add_mode")
23+
24+
val dialogFragment =
25+
activity.supportFragmentManager.findFragmentByTag("dialog") as AddEditReminderDialog
26+
dialogFragment.dialog?.findViewById<View>(R.id.add_edit_reminder_advanced_dropdown)?.performClick()
27+
advanceRobolectricLooper()
28+
captureScreen("add_mode_advanced_open")
29+
}
30+
31+
@Test
32+
fun `edit mode`() {
33+
val deckId = addDeck("Test Deck")
34+
val reminder =
35+
ReviewReminder.createReviewReminder(
36+
time = ReviewReminderTime(9, 0),
37+
scope = ReviewReminderScope.DeckSpecific(deckId),
38+
onlyNotifyIfNoReviews = true,
39+
)
40+
val activity = buildActivity(FragmentActivity::class.java).setup().get()
41+
AddEditReminderDialog
42+
.getInstance(DialogMode.Edit(reminder))
43+
.show(activity.supportFragmentManager, "dialog")
44+
advanceRobolectricLooper()
45+
captureScreen("edit_mode")
46+
47+
val dialogFragment =
48+
activity.supportFragmentManager.findFragmentByTag("dialog") as AddEditReminderDialog
49+
dialogFragment.dialog?.findViewById<View>(R.id.add_edit_reminder_advanced_dropdown)?.performClick()
50+
advanceRobolectricLooper()
51+
captureScreen("edit_mode_advanced_open")
52+
}
53+
}
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
// Copyright (c) 2026 Eric Li <ericli3690@gmail.com>
3+
4+
package com.ichi2.anki.reviewreminders
5+
6+
import android.content.Intent
7+
import androidx.annotation.IdRes
8+
import androidx.fragment.app.FragmentManager
9+
import androidx.fragment.app.commit
10+
import androidx.test.core.app.ActivityScenario
11+
import com.google.android.material.appbar.AppBarLayout
12+
import com.ichi2.anki.R
13+
import com.ichi2.anki.ScreenshotTest
14+
import com.ichi2.anki.StudyOptionsActivity
15+
import com.ichi2.anki.preferences.PreferencesActivity
16+
import com.ichi2.anki.preferences.PreferencesFragment
17+
import com.ichi2.anki.reviewreminders.ScheduleRemindersFragment.FragmentHost
18+
import com.ichi2.anki.utils.ConfigAwareSingleFragmentActivity
19+
import com.ichi2.anki.withDeckPicker
20+
import com.ichi2.testutils.BackupManagerTestUtilities
21+
import org.junit.Test
22+
23+
/**
24+
* Covers all [FragmentHost] configurations of the fragment.
25+
*/
26+
class ReviewRemindersScreenshotTest : ScreenshotTest() {
27+
@Test
28+
fun `settings host`() {
29+
captureSettingsHost("settingsHost")
30+
}
31+
32+
@Test
33+
fun `settings host tablet`() {
34+
setTabletQualifiers()
35+
// The toolbar is not collapsible on wide screens
36+
captureSettingsHost("settingsHostTablet", captureScrolled = false)
37+
}
38+
39+
private fun captureSettingsHost(
40+
prefix: String,
41+
captureScrolled: Boolean = true,
42+
) {
43+
ActivityScenario.launch<PreferencesActivity>(PreferencesActivity.getIntent(targetContext)).use { scenario ->
44+
scenario.onActivity { activity ->
45+
val fm = (activity.fragment as PreferencesFragment).childFragmentManager
46+
commitScheduleRemindersAndCapture(
47+
fragmentManager = fm,
48+
containerId = R.id.settings_container,
49+
host = FragmentHost.SETTINGS,
50+
scope = ReviewReminderScope.Global,
51+
prefix = prefix,
52+
)
53+
if (captureScrolled) {
54+
fm
55+
.findFragmentById(R.id.settings_container)
56+
?.view
57+
?.findViewById<AppBarLayout>(R.id.appbar)
58+
?.setExpanded(false, false)
59+
advanceRobolectricLooper()
60+
captureScreen("${prefix}_scheduleReminders_scrolled")
61+
}
62+
commitTroubleshootingAndCapture(
63+
fragmentManager = fm,
64+
containerId = R.id.settings_container,
65+
host = FragmentHost.SETTINGS,
66+
prefix = prefix,
67+
)
68+
}
69+
}
70+
}
71+
72+
@Test
73+
fun `study options fragment host`() {
74+
setTabletQualifiers()
75+
withDeckPicker(deckCount = 1, withCards = true) { deckPicker ->
76+
val deckId = addDeck("Test Deck")
77+
commitScheduleRemindersAndCapture(
78+
fragmentManager = deckPicker.supportFragmentManager,
79+
containerId = R.id.studyoptions_fragment,
80+
host = FragmentHost.STUDY_OPTIONS_FRAGMENT,
81+
scope = ReviewReminderScope.DeckSpecific(deckId),
82+
prefix = "studyOptionsFragmentHost",
83+
)
84+
commitTroubleshootingAndCapture(
85+
fragmentManager = deckPicker.supportFragmentManager,
86+
containerId = R.id.studyoptions_fragment,
87+
host = FragmentHost.STUDY_OPTIONS_FRAGMENT,
88+
prefix = "studyOptionsFragmentHost",
89+
)
90+
}
91+
BackupManagerTestUtilities.reset()
92+
}
93+
94+
@Test
95+
fun `study options frame host`() {
96+
val deckId = addDeck("Test Deck")
97+
ActivityScenario
98+
.launch<StudyOptionsActivity>(
99+
Intent(targetContext, StudyOptionsActivity::class.java),
100+
).use { scenario ->
101+
scenario.onActivity { activity ->
102+
commitScheduleRemindersAndCapture(
103+
fragmentManager = activity.supportFragmentManager,
104+
containerId = R.id.studyoptions_frame,
105+
host = FragmentHost.STUDY_OPTIONS_FRAME,
106+
scope = ReviewReminderScope.DeckSpecific(deckId),
107+
prefix = "studyOptionsFrameHost",
108+
)
109+
commitTroubleshootingAndCapture(
110+
fragmentManager = activity.supportFragmentManager,
111+
containerId = R.id.studyoptions_frame,
112+
host = FragmentHost.STUDY_OPTIONS_FRAME,
113+
prefix = "studyOptionsFrameHost",
114+
)
115+
}
116+
}
117+
}
118+
119+
@Test
120+
fun `standalone activity host`() {
121+
val intent = ScheduleRemindersFragment.getIntent(targetContext, ReviewReminderScope.Global)
122+
ActivityScenario.launch<ConfigAwareSingleFragmentActivity>(intent).use { scenario ->
123+
advanceRobolectricLooper()
124+
scenario.onActivity { activity ->
125+
captureScreen("standaloneActivityHost_scheduleReminders")
126+
commitTroubleshootingAndCapture(
127+
fragmentManager = activity.supportFragmentManager,
128+
containerId = R.id.fragment_container,
129+
host = FragmentHost.STANDALONE_ACTIVITY,
130+
prefix = "standaloneActivityHost",
131+
)
132+
}
133+
}
134+
}
135+
136+
private fun commitScheduleRemindersAndCapture(
137+
fragmentManager: FragmentManager,
138+
@IdRes containerId: Int,
139+
host: FragmentHost,
140+
scope: ReviewReminderScope,
141+
prefix: String,
142+
) {
143+
fragmentManager.commit {
144+
replace(containerId, ScheduleRemindersFragment.newInstance(scope, host))
145+
}
146+
advanceRobolectricLooper()
147+
captureScreen("${prefix}_scheduleReminders")
148+
}
149+
150+
private fun commitTroubleshootingAndCapture(
151+
fragmentManager: FragmentManager,
152+
@IdRes containerId: Int,
153+
host: FragmentHost,
154+
prefix: String,
155+
) {
156+
fragmentManager.commit {
157+
replace(containerId, ReminderTroubleshootingFragment.newInstance(host))
158+
addToBackStack(null)
159+
}
160+
advanceRobolectricLooper()
161+
captureScreen("${prefix}_troubleshooting")
162+
}
163+
}

0 commit comments

Comments
 (0)