mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-16 10:56:50 -04:00
Merge pull request #4201 from kiwix/Fixes#4200
Fixed: `FIND_IN_PAGE` feature only works with first tab page.
This commit is contained in:
commit
6e3ceacd26
@ -220,7 +220,7 @@ object TestUtils {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun deleteTemporaryFilesOfTestCases(context: Context) {
|
fun deleteTemporaryFilesOfTestCases(context: Context) {
|
||||||
ContextCompat.getExternalFilesDirs(context, null).filterNotNull()
|
context.getExternalFilesDirs(null).filterNotNull()
|
||||||
.map(::deleteAllFilesInDirectory)
|
.map(::deleteAllFilesInDirectory)
|
||||||
ContextWrapper(context).externalMediaDirs.filterNotNull()
|
ContextWrapper(context).externalMediaDirs.filterNotNull()
|
||||||
.map(::deleteAllFilesInDirectory)
|
.map(::deleteAllFilesInDirectory)
|
||||||
|
@ -505,16 +505,6 @@ abstract class CoreReaderFragment :
|
|||||||
readAloudService?.registerCallBack(this@CoreReaderFragment)
|
readAloudService?.registerCallBack(this@CoreReaderFragment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requireActivity().observeNavigationResult<String>(
|
|
||||||
FIND_IN_PAGE_SEARCH_STRING,
|
|
||||||
viewLifecycleOwner,
|
|
||||||
Observer(::findInPage)
|
|
||||||
)
|
|
||||||
requireActivity().observeNavigationResult<SearchItemToOpen>(
|
|
||||||
TAG_FILE_SEARCHED,
|
|
||||||
viewLifecycleOwner,
|
|
||||||
Observer(::openSearchItem)
|
|
||||||
)
|
|
||||||
handleClicks()
|
handleClicks()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2617,6 +2607,28 @@ abstract class CoreReaderFragment :
|
|||||||
Log.w(TAG_KIWIX, "Kiwix shared preferences corrupted", e)
|
Log.w(TAG_KIWIX, "Kiwix shared preferences corrupted", e)
|
||||||
activity.toast(R.string.could_not_restore_tabs, Toast.LENGTH_LONG)
|
activity.toast(R.string.could_not_restore_tabs, Toast.LENGTH_LONG)
|
||||||
}
|
}
|
||||||
|
// After restoring the tabs, observe any search actions that the user might have triggered.
|
||||||
|
// Since the ZIM file opening functionality has been moved to a background thread,
|
||||||
|
// we ensure that all necessary actions are completed before observing these search actions.
|
||||||
|
observeSearchActions()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observes any search-related actions triggered by the user, such as "Find in Page" or
|
||||||
|
* opening a specific search item.
|
||||||
|
* This method sets up observers for navigation results related to search functionality.
|
||||||
|
*/
|
||||||
|
private fun observeSearchActions() {
|
||||||
|
requireActivity().observeNavigationResult<String>(
|
||||||
|
FIND_IN_PAGE_SEARCH_STRING,
|
||||||
|
viewLifecycleOwner,
|
||||||
|
Observer(::findInPage)
|
||||||
|
)
|
||||||
|
requireActivity().observeNavigationResult<SearchItemToOpen>(
|
||||||
|
TAG_FILE_SEARCHED,
|
||||||
|
viewLifecycleOwner,
|
||||||
|
Observer(::openSearchItem)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onReadAloudPauseOrResume(isPauseTTS: Boolean) {
|
override fun onReadAloudPauseOrResume(isPauseTTS: Boolean) {
|
||||||
|
@ -90,8 +90,10 @@ class SearchFragmentTestForCustomApp {
|
|||||||
private lateinit var downloadingZimFile: File
|
private lateinit var downloadingZimFile: File
|
||||||
private lateinit var activityScenario: ActivityScenario<CustomMainActivity>
|
private lateinit var activityScenario: ActivityScenario<CustomMainActivity>
|
||||||
|
|
||||||
private val rayCharlesZimFileUrl =
|
private val scientificAllianceZIMUrl =
|
||||||
"https://download.kiwix.org/zim/zimit/scientific-alliance.obscurative.ru_ru_all_2024-06.zim"
|
"https://download.kiwix.org/zim/zimit/scientific-alliance.obscurative.ru_ru_all_2024-06.zim"
|
||||||
|
private val rayCharlesZIMFileUrl =
|
||||||
|
"https://dev.kiwix.org/kiwix-android/test/wikipedia_en_ray_charles_maxi_2023-12.zim"
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun waitForIdle() {
|
fun waitForIdle() {
|
||||||
@ -129,7 +131,7 @@ class SearchFragmentTestForCustomApp {
|
|||||||
customMainActivity = it
|
customMainActivity = it
|
||||||
}
|
}
|
||||||
// test with a large ZIM file to properly test the scenario
|
// test with a large ZIM file to properly test the scenario
|
||||||
downloadingZimFile = getDownloadingZimFile()
|
downloadingZimFile = getDownloadingZimFileFromDataFolder()
|
||||||
getOkkHttpClientForTesting().newCall(downloadRequest()).execute().use { response ->
|
getOkkHttpClientForTesting().newCall(downloadRequest()).execute().use { response ->
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
response.body?.let { responseBody ->
|
response.body?.let { responseBody ->
|
||||||
@ -145,7 +147,7 @@ class SearchFragmentTestForCustomApp {
|
|||||||
UiThreadStatement.runOnUiThread {
|
UiThreadStatement.runOnUiThread {
|
||||||
customMainActivity.navigate(customMainActivity.readerFragmentResId)
|
customMainActivity.navigate(customMainActivity.readerFragmentResId)
|
||||||
}
|
}
|
||||||
openZimFileInReaderWithAssetFileDescriptor(downloadingZimFile)
|
openZimFileInReader(zimFile = downloadingZimFile)
|
||||||
openSearchWithQuery()
|
openSearchWithQuery()
|
||||||
val searchTerm = "gard"
|
val searchTerm = "gard"
|
||||||
val searchedItem = "Gardanta Spirito"
|
val searchedItem = "Gardanta Spirito"
|
||||||
@ -258,6 +260,44 @@ class SearchFragmentTestForCustomApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPreviouslyLoadedArticleLoadsAgainWhenSwitchingToAnotherScreen() {
|
||||||
|
activityScenario.onActivity {
|
||||||
|
customMainActivity = it
|
||||||
|
}
|
||||||
|
// test with a large ZIM file to properly test the scenario
|
||||||
|
downloadingZimFile = getDownloadingZimFileFromDataFolder()
|
||||||
|
getOkkHttpClientForTesting().newCall(downloadRequest(rayCharlesZIMFileUrl)).execute()
|
||||||
|
.use { response ->
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
response.body?.let { responseBody ->
|
||||||
|
writeZimFileData(responseBody, downloadingZimFile)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw RuntimeException(
|
||||||
|
"Download Failed. Error: ${response.message}\n" +
|
||||||
|
" Status Code: ${response.code}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UiThreadStatement.runOnUiThread {
|
||||||
|
customMainActivity.navigate(customMainActivity.readerFragmentResId)
|
||||||
|
}
|
||||||
|
openZimFileInReader(zimFile = downloadingZimFile)
|
||||||
|
search {
|
||||||
|
// click on home button to load the main page of ZIM file.
|
||||||
|
clickOnHomeButton()
|
||||||
|
// click on an article to load the other page.
|
||||||
|
clickOnAFoolForYouArticle()
|
||||||
|
assertAFoolForYouArticleLoaded()
|
||||||
|
// open note screen.
|
||||||
|
openNoteFragment()
|
||||||
|
pressBack()
|
||||||
|
// after came back check the previously loaded article is still showing or not.
|
||||||
|
assertAFoolForYouArticleLoaded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun openSearchWithQuery(query: String = "") {
|
private fun openSearchWithQuery(query: String = "") {
|
||||||
UiThreadStatement.runOnUiThread {
|
UiThreadStatement.runOnUiThread {
|
||||||
customMainActivity.openSearch(searchString = query)
|
customMainActivity.openSearch(searchString = query)
|
||||||
@ -270,7 +310,10 @@ class SearchFragmentTestForCustomApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openZimFileInReader(assetFileDescriptor: AssetFileDescriptor) {
|
private fun openZimFileInReader(
|
||||||
|
assetFileDescriptor: AssetFileDescriptor? = null,
|
||||||
|
zimFile: File? = null
|
||||||
|
) {
|
||||||
UiThreadStatement.runOnUiThread {
|
UiThreadStatement.runOnUiThread {
|
||||||
val navHostFragment: NavHostFragment =
|
val navHostFragment: NavHostFragment =
|
||||||
customMainActivity.supportFragmentManager
|
customMainActivity.supportFragmentManager
|
||||||
@ -280,10 +323,17 @@ class SearchFragmentTestForCustomApp {
|
|||||||
val customReaderFragment =
|
val customReaderFragment =
|
||||||
navHostFragment.childFragmentManager.fragments[0] as CustomReaderFragment
|
navHostFragment.childFragmentManager.fragments[0] as CustomReaderFragment
|
||||||
runBlocking {
|
runBlocking {
|
||||||
|
assetFileDescriptor?.let {
|
||||||
customReaderFragment.openZimFile(
|
customReaderFragment.openZimFile(
|
||||||
ZimReaderSource(null, null, listOf(assetFileDescriptor)),
|
ZimReaderSource(assetFileDescriptorList = listOf(assetFileDescriptor)),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
} ?: run {
|
||||||
|
customReaderFragment.openZimFile(
|
||||||
|
ZimReaderSource(zimFile),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -318,9 +368,9 @@ class SearchFragmentTestForCustomApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadRequest() =
|
private fun downloadRequest(zimUrl: String = scientificAllianceZIMUrl) =
|
||||||
Request.Builder()
|
Request.Builder()
|
||||||
.url(URI.create(rayCharlesZimFileUrl).toURL())
|
.url(URI.create(zimUrl).toURL())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
private fun getDownloadingZimFile(): File {
|
private fun getDownloadingZimFile(): File {
|
||||||
@ -330,6 +380,13 @@ class SearchFragmentTestForCustomApp {
|
|||||||
return zimFile
|
return zimFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getDownloadingZimFileFromDataFolder(): File {
|
||||||
|
val zimFile = File(context.getExternalFilesDirs(null)[0], "ray_charles.zim")
|
||||||
|
if (zimFile.exists()) zimFile.delete()
|
||||||
|
zimFile.createNewFile()
|
||||||
|
return zimFile
|
||||||
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
private fun getOkkHttpClientForTesting(): OkHttpClient =
|
private fun getOkkHttpClientForTesting(): OkHttpClient =
|
||||||
OkHttpClient().newBuilder()
|
OkHttpClient().newBuilder()
|
||||||
|
@ -19,19 +19,31 @@
|
|||||||
package org.kiwix.kiwixmobile.custom.search
|
package org.kiwix.kiwixmobile.custom.search
|
||||||
|
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
|
import androidx.core.view.GravityCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.test.espresso.Espresso
|
import androidx.test.espresso.Espresso
|
||||||
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.action.ViewActions
|
import androidx.test.espresso.action.ViewActions
|
||||||
|
import androidx.test.espresso.action.ViewActions.click
|
||||||
import androidx.test.espresso.assertion.ViewAssertions
|
import androidx.test.espresso.assertion.ViewAssertions
|
||||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||||
import androidx.test.espresso.matcher.ViewMatchers
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
|
import androidx.test.espresso.web.assertion.WebViewAssertions.webMatches
|
||||||
import androidx.test.espresso.web.sugar.Web
|
import androidx.test.espresso.web.sugar.Web
|
||||||
|
import androidx.test.espresso.web.sugar.Web.onWebView
|
||||||
import androidx.test.espresso.web.webdriver.DriverAtoms
|
import androidx.test.espresso.web.webdriver.DriverAtoms
|
||||||
|
import androidx.test.espresso.web.webdriver.DriverAtoms.findElement
|
||||||
|
import androidx.test.espresso.web.webdriver.DriverAtoms.getText
|
||||||
|
import androidx.test.espresso.web.webdriver.DriverAtoms.webClick
|
||||||
import androidx.test.espresso.web.webdriver.Locator
|
import androidx.test.espresso.web.webdriver.Locator
|
||||||
import androidx.test.uiautomator.UiDevice
|
import androidx.test.uiautomator.UiDevice
|
||||||
|
import com.adevinta.android.barista.interaction.BaristaDrawerInteractions.openDrawerWithGravity
|
||||||
import com.adevinta.android.barista.interaction.BaristaSleepInteractions
|
import com.adevinta.android.barista.interaction.BaristaSleepInteractions
|
||||||
import com.adevinta.android.barista.internal.matcher.HelperMatchers
|
import com.adevinta.android.barista.internal.matcher.HelperMatchers
|
||||||
|
import org.hamcrest.CoreMatchers.containsString
|
||||||
import org.kiwix.kiwixmobile.core.R
|
import org.kiwix.kiwixmobile.core.R
|
||||||
|
import org.kiwix.kiwixmobile.custom.R.id
|
||||||
import org.kiwix.kiwixmobile.custom.testutils.TestUtils
|
import org.kiwix.kiwixmobile.custom.testutils.TestUtils
|
||||||
import org.kiwix.kiwixmobile.custom.testutils.TestUtils.testFlakyView
|
import org.kiwix.kiwixmobile.custom.testutils.TestUtils.testFlakyView
|
||||||
|
|
||||||
@ -88,14 +100,16 @@ class SearchRobot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun searchAndClickOnArticle(searchString: String) {
|
fun searchAndClickOnArticle(searchString: String) {
|
||||||
// wait a bit to properly load the ZIM file in the reader
|
// Wait a bit to properly load the ZIM file in the reader.
|
||||||
BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS_FOR_SEARCH_TEST.toLong())
|
BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS_FOR_SEARCH_TEST.toLong())
|
||||||
openSearchScreen()
|
openSearchScreen()
|
||||||
|
// Wait a bit to properly visible the search screen.
|
||||||
|
BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS_FOR_SEARCH_TEST.toLong())
|
||||||
searchWithFrequentlyTypedWords(searchString)
|
searchWithFrequentlyTypedWords(searchString)
|
||||||
clickOnSearchItemInSearchList()
|
clickOnSearchItemInSearchList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clickOnSearchItemInSearchList() {
|
private fun clickOnSearchItemInSearchList() {
|
||||||
testFlakyView({
|
testFlakyView({
|
||||||
BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS_FOR_SEARCH_TEST.toLong())
|
BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS_FOR_SEARCH_TEST.toLong())
|
||||||
Espresso.onView(ViewMatchers.withId(R.id.search_list)).perform(
|
Espresso.onView(ViewMatchers.withId(R.id.search_list)).perform(
|
||||||
@ -118,4 +132,43 @@ class SearchRobot {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clickOnHomeButton() {
|
||||||
|
testFlakyView({
|
||||||
|
Espresso.onView(ViewMatchers.withId(R.id.bottom_toolbar_home))
|
||||||
|
.perform(ViewActions.click())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clickOnAFoolForYouArticle() {
|
||||||
|
BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS.toLong())
|
||||||
|
testFlakyView({
|
||||||
|
onWebView()
|
||||||
|
.withElement(
|
||||||
|
findElement(
|
||||||
|
Locator.XPATH,
|
||||||
|
"//*[contains(text(), 'A Fool for You')]"
|
||||||
|
)
|
||||||
|
).perform(webClick())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assertAFoolForYouArticleLoaded() {
|
||||||
|
BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS.toLong())
|
||||||
|
testFlakyView({
|
||||||
|
onWebView()
|
||||||
|
.withElement(
|
||||||
|
findElement(
|
||||||
|
Locator.XPATH,
|
||||||
|
"//*[contains(text(), '\"A Fool for You\"')]"
|
||||||
|
)
|
||||||
|
).check(webMatches(getText(), containsString("\"A Fool for You\"")))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openNoteFragment() {
|
||||||
|
BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS.toLong())
|
||||||
|
openDrawerWithGravity(id.custom_drawer_container, GravityCompat.START)
|
||||||
|
testFlakyView({ onView(withText(R.string.pref_notes)).perform(click()) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@ package org.kiwix.kiwixmobile.custom.testutils
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.test.uiautomator.By
|
import androidx.test.uiautomator.By
|
||||||
import androidx.test.uiautomator.UiDevice
|
import androidx.test.uiautomator.UiDevice
|
||||||
import androidx.test.uiautomator.UiObject
|
import androidx.test.uiautomator.UiObject
|
||||||
@ -32,6 +31,7 @@ import java.io.File
|
|||||||
object TestUtils {
|
object TestUtils {
|
||||||
private const val TAG = "TESTUTILS"
|
private const val TAG = "TESTUTILS"
|
||||||
var TEST_PAUSE_MS_FOR_SEARCH_TEST = 1000
|
var TEST_PAUSE_MS_FOR_SEARCH_TEST = 1000
|
||||||
|
var TEST_PAUSE_MS = 3000
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun isSystemUINotRespondingDialogVisible(uiDevice: UiDevice) =
|
fun isSystemUINotRespondingDialogVisible(uiDevice: UiDevice) =
|
||||||
@ -92,7 +92,7 @@ object TestUtils {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun deleteTemporaryFilesOfTestCases(context: Context) {
|
fun deleteTemporaryFilesOfTestCases(context: Context) {
|
||||||
ContextCompat.getExternalFilesDirs(context, null).filterNotNull()
|
context.getExternalFilesDirs(null).filterNotNull()
|
||||||
.map(::deleteAllFilesInDirectory)
|
.map(::deleteAllFilesInDirectory)
|
||||||
ContextWrapper(context).externalMediaDirs.filterNotNull()
|
ContextWrapper(context).externalMediaDirs.filterNotNull()
|
||||||
.map(::deleteAllFilesInDirectory)
|
.map(::deleteAllFilesInDirectory)
|
||||||
|
@ -144,7 +144,6 @@ class CustomReaderFragment : CoreReaderFragment() {
|
|||||||
zimReaderContainer?.zimFileReader?.let(::setUpBookmarks)
|
zimReaderContainer?.zimFileReader?.let(::setUpBookmarks)
|
||||||
} else {
|
} else {
|
||||||
openObbOrZim()
|
openObbOrZim()
|
||||||
manageExternalLaunchAndRestoringViewState()
|
|
||||||
}
|
}
|
||||||
requireArguments().clear()
|
requireArguments().clear()
|
||||||
}
|
}
|
||||||
@ -207,11 +206,15 @@ class CustomReaderFragment : CoreReaderFragment() {
|
|||||||
val bookOnDisk = BookOnDisk(zimFileReader)
|
val bookOnDisk = BookOnDisk(zimFileReader)
|
||||||
repositoryActions?.saveBook(bookOnDisk)
|
repositoryActions?.saveBook(bookOnDisk)
|
||||||
}
|
}
|
||||||
|
// Open the previous loaded pages after ZIM file loads.
|
||||||
|
manageExternalLaunchAndRestoringViewState()
|
||||||
}
|
}
|
||||||
|
|
||||||
is ValidationState.HasBothFiles -> {
|
is ValidationState.HasBothFiles -> {
|
||||||
it.zimFile.delete()
|
it.zimFile.delete()
|
||||||
openZimFile(ZimReaderSource(it.obbFile), true)
|
openZimFile(ZimReaderSource(it.obbFile), true)
|
||||||
|
// Open the previous loaded pages after ZIM file loads.
|
||||||
|
manageExternalLaunchAndRestoringViewState()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {}
|
else -> {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user