Fixed: CI sometimes crashes on testBookmarks.

* The issue was caused by using `CoroutineScope(Dispatchers.Main)` while our flow directly accessed the `uuid` of the ZIM file from the `ZimFileReader` object. When the fragment was switched to another screen, the `ZimFileReader` object got disposed. However, the `webViewProgressChanged` method would still trigger, initiating the flow to check if the current page was bookmarked. Since the `ZimFileReader` was already disposed, this resulted in a crash.
* We fixed this by using the viewLifecycleOwner.lifecycleScope so that the job is automatically cancelled when the fragment is destroyed. Additionally, we now retrieve the uuid once at the beginning and reuse it in the flow, avoiding repeated access to the disposed ZimFileReader.
* Improved the `testBookmarks` test case. Sometimes this test failed to find the "OPEN" button of the `Snackbar` because the `Snackbar` was automatically dismissed before `Espresso` could validate the view. This timing issue occasionally caused the test to fail. We've improved the test to properly verify whether the bookmark is saved, avoiding such situations.
* Improved the `DownloadTest`, which sometimes failed on CI.
This commit is contained in:
MohitMaliFtechiz 2025-05-16 11:50:31 +05:30
parent c69dc0190f
commit 0c91e329d4
5 changed files with 18 additions and 35 deletions

View File

@ -29,6 +29,7 @@ import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.accessibility.AccessibilityChecks
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.filters.LargeTest
import androidx.test.internal.runner.junit4.statement.UiThreadStatement
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.adevinta.android.barista.interaction.BaristaSleepInteractions
@ -157,7 +158,9 @@ class DownloadTest : BaseActivityTest() {
"Could not pause download. Original exception = $ignore"
)
}
clickLibraryOnBottomNav()
UiThreadStatement.runOnUiThread {
kiwixMainActivity.navigate(R.id.libraryFragment)
}
// refresh the local library list to show the downloaded zim file
library { refreshList(composeTestRule) }
checkIfZimFileDownloaded(composeTestRule)

View File

@ -53,8 +53,6 @@ fun bookmarks(func: BookmarksRobot.() -> Unit) =
BookmarksRobot().applyWithViewHierarchyPrinting(func)
class BookmarksRobot : BaseRobot() {
private var retryCountForBookmarkAddedButton = 5
fun assertBookMarksDisplayed(composeTestRule: ComposeContentTestRule) {
composeTestRule.apply {
waitForIdle()
@ -113,22 +111,6 @@ class BookmarksRobot : BaseRobot() {
testFlakyView({ onView(withId(R.id.bottom_toolbar_bookmark)).perform(longClick()) })
}
fun clickOnOpenSavedBookmarkButton() {
try {
onView(withText("OPEN")).perform(click())
} catch (runtimeException: RuntimeException) {
if (retryCountForBookmarkAddedButton > 0) {
retryCountForBookmarkAddedButton--
clickOnOpenSavedBookmarkButton()
} else {
throw RuntimeException(
"Unable to save the bookmark, original exception is" +
" ${runtimeException.localizedMessage}"
)
}
}
}
fun assertBookmarkSaved(composeTestRule: ComposeContentTestRule) {
pauseForBetterTestPerformance()
composeTestRule.apply {

View File

@ -134,9 +134,9 @@ class LibkiwixBookmarkTest : BaseActivityTest() {
pressBack()
// Test saving bookmark
clickOnSaveBookmarkImage()
clickOnOpenSavedBookmarkButton()
assertBookmarkSaved(composeTestRule)
pressBack()
topLevel {
clickBookmarksOnNavDrawer { assertBookmarkSaved(composeTestRule) }
}
// Test removing bookmark
clickOnSaveBookmarkImage()
longClickOnSaveBookmarkImage()

View File

@ -1899,9 +1899,10 @@ abstract class CoreReaderFragment :
protected fun setUpBookmarks(zimFileReader: ZimFileReader) {
safelyCancelBookmarkJob()
bookmarkingJob = CoroutineScope(Dispatchers.Main).launch {
val zimFileReaderId = zimFileReader.id
bookmarkingJob = viewLifecycleOwner.lifecycleScope.launch {
combine(
libkiwixBookmarks?.bookmarkUrlsForCurrentBook(zimFileReader.id) ?: emptyFlow(),
libkiwixBookmarks?.bookmarkUrlsForCurrentBook(zimFileReaderId) ?: emptyFlow(),
webUrlsFlow,
List<String?>::contains
).collect { isBookmarked ->

View File

@ -18,7 +18,6 @@
package org.kiwix.kiwixmobile.core.dao
import android.annotation.SuppressLint
import io.mockk.CapturingSlot
import io.mockk.clearAllMocks
import io.mockk.coEvery
@ -72,10 +71,8 @@ internal class NewBookDaoTest {
)
}
@SuppressLint("CheckResult")
@Test
fun `books deletes entities whose file does not exist`() =
runTest {
fun `books deletes entities whose file does not exist`() = runTest {
val (_, deletedEntity) = expectEmissionOfExistingAndNotExistingBook()
testFlow(
flow = newBookDao.books(),