mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 10:46:53 -04:00
Refactored the ZimHostFragmentTest according to compose.
This commit is contained in:
parent
6e370a1e74
commit
a72d021e95
@ -53,12 +53,14 @@ class ErrorActivityRobot : BaseRobot() {
|
||||
}
|
||||
|
||||
fun assertCheckBoxesDisplayed(composeTestRule: ComposeContentTestRule) {
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.crash_checkbox_language))
|
||||
.assertIsDisplayed()
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.crash_checkbox_logs))
|
||||
.assertIsDisplayed()
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.crash_checkbox_zimfiles))
|
||||
.assertIsDisplayed()
|
||||
composeTestRule.apply {
|
||||
onNodeWithText(context.getString(R.string.crash_checkbox_language))
|
||||
.assertIsDisplayed()
|
||||
onNodeWithText(context.getString(R.string.crash_checkbox_logs))
|
||||
.assertIsDisplayed()
|
||||
onNodeWithText(context.getString(R.string.crash_checkbox_zimfiles))
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
|
||||
fun clickOnSendDetailsButton(composeTestRule: ComposeContentTestRule) {
|
||||
|
@ -21,6 +21,7 @@ package org.kiwix.kiwixmobile.webserver
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.espresso.accessibility.AccessibilityChecks
|
||||
@ -31,7 +32,6 @@ import androidx.test.uiautomator.UiDevice
|
||||
import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils.matchesCheck
|
||||
import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils.matchesViews
|
||||
import com.google.android.apps.common.testing.accessibility.framework.checks.DuplicateClickableBoundsCheck
|
||||
import leakcanary.LeakAssertions
|
||||
import org.hamcrest.Matchers.allOf
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
@ -54,6 +54,9 @@ class ZimHostFragmentTest {
|
||||
@JvmField
|
||||
var retryRule = RetryRule()
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
private lateinit var sharedPreferenceUtil: SharedPreferenceUtil
|
||||
|
||||
private lateinit var activityScenario: ActivityScenario<KiwixMainActivity>
|
||||
@ -150,53 +153,52 @@ class ZimHostFragmentTest {
|
||||
openZimHostFragment()
|
||||
|
||||
// Check if server is already started
|
||||
stopServerIfAlreadyStarted()
|
||||
stopServerIfAlreadyStarted(composeTestRule)
|
||||
|
||||
// Check if both zim file are selected or not to properly run our test case
|
||||
selectZimFileIfNotAlreadySelected()
|
||||
selectZimFileIfNotAlreadySelected(composeTestRule)
|
||||
|
||||
clickOnTestZim()
|
||||
clickOnTestZim(composeTestRule)
|
||||
|
||||
// Start the server with one ZIM file
|
||||
startServer()
|
||||
assertServerStarted()
|
||||
startServer(composeTestRule)
|
||||
assertServerStarted(composeTestRule)
|
||||
|
||||
// Check that only one ZIM file is hosted on the server
|
||||
assertItemHostedOnServer(1)
|
||||
assertItemHostedOnServer(1, composeTestRule)
|
||||
|
||||
// Check QR code shown
|
||||
assertQrShown()
|
||||
assertQrShown(composeTestRule)
|
||||
|
||||
// Stop the server
|
||||
stopServer()
|
||||
assertServerStopped()
|
||||
stopServer(composeTestRule)
|
||||
assertServerStopped(composeTestRule)
|
||||
|
||||
// Check QR code not shown after stopping the server
|
||||
assertQrNotShown()
|
||||
assertQrNotShown(composeTestRule)
|
||||
|
||||
// Select the test ZIM file to host on the server
|
||||
clickOnTestZim()
|
||||
clickOnTestZim(composeTestRule)
|
||||
|
||||
// Start the server with two ZIM files
|
||||
startServer()
|
||||
assertServerStarted()
|
||||
startServer(composeTestRule)
|
||||
assertServerStarted(composeTestRule)
|
||||
|
||||
// Check that both ZIM files are hosted on the server
|
||||
assertItemHostedOnServer(2)
|
||||
assertItemHostedOnServer(2, composeTestRule)
|
||||
|
||||
// Unselect the test ZIM to test restarting server functionality
|
||||
clickOnTestZim()
|
||||
clickOnTestZim(composeTestRule)
|
||||
|
||||
// Check if the server is running
|
||||
assertServerStarted()
|
||||
assertServerStarted(composeTestRule)
|
||||
|
||||
// Check that only one ZIM file is hosted on the server after unselecting
|
||||
assertItemHostedOnServer(1)
|
||||
assertItemHostedOnServer(1, composeTestRule)
|
||||
|
||||
// finally close the server at the end of test case
|
||||
stopServer()
|
||||
stopServer(composeTestRule)
|
||||
}
|
||||
LeakAssertions.assertNoLeaks()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,30 +18,28 @@
|
||||
|
||||
package org.kiwix.kiwixmobile.webserver
|
||||
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsNotDisplayed
|
||||
import androidx.compose.ui.test.assertIsOn
|
||||
import androidx.compose.ui.test.assertTextEquals
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.espresso.matcher.ViewMatchers.assertThat
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||
import applyWithViewHierarchyPrinting
|
||||
import com.adevinta.android.barista.interaction.BaristaSleepInteractions
|
||||
import com.adevinta.android.barista.interaction.BaristaSwipeRefreshInteractions.refresh
|
||||
import junit.framework.AssertionFailedError
|
||||
import org.hamcrest.CoreMatchers
|
||||
import org.kiwix.kiwixmobile.BaseRobot
|
||||
import org.kiwix.kiwixmobile.Findable.StringId.TextId
|
||||
import org.kiwix.kiwixmobile.Findable.Text
|
||||
import org.kiwix.kiwixmobile.Findable.ViewId
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.R.id
|
||||
import org.kiwix.kiwixmobile.core.utils.files.Log
|
||||
import org.kiwix.kiwixmobile.testutils.TestUtils
|
||||
import org.kiwix.kiwixmobile.testutils.TestUtils.testFlakyView
|
||||
import org.kiwix.kiwixmobile.utils.RecyclerViewItemCount
|
||||
import org.kiwix.kiwixmobile.utils.RecyclerViewMatcher
|
||||
import org.kiwix.kiwixmobile.utils.RecyclerViewSelectedCheckBoxCountAssertion
|
||||
import org.kiwix.kiwixmobile.ui.BOOK_ITEM_CHECKBOX_TESTING_TAG
|
||||
import org.kiwix.kiwixmobile.utils.StandardActions.openDrawer
|
||||
|
||||
fun zimHost(func: ZimHostRobot.() -> Unit) = ZimHostRobot().applyWithViewHierarchyPrinting(func)
|
||||
@ -66,15 +64,20 @@ class ZimHostRobot : BaseRobot() {
|
||||
clickOn(TextId(R.string.menu_wifi_hotspot))
|
||||
}
|
||||
|
||||
fun clickOnTestZim() {
|
||||
pauseForBetterTestPerformance()
|
||||
clickOn(Text("Test_Zim"))
|
||||
fun clickOnTestZim(composeTestRule: ComposeContentTestRule) {
|
||||
testFlakyView({
|
||||
composeTestRule.apply {
|
||||
waitForIdle()
|
||||
onNodeWithTag("${BOOK_ITEM_CHECKBOX_TESTING_TAG}2").performClick()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun startServer() {
|
||||
fun startServer(composeTestRule: ComposeContentTestRule) {
|
||||
// stop the server if it is already running.
|
||||
stopServerIfAlreadyStarted()
|
||||
clickOn(ViewId(id.startServerButton))
|
||||
stopServerIfAlreadyStarted(composeTestRule)
|
||||
composeTestRule.onNodeWithTag(START_SERVER_BUTTON_TESTING_TAG)
|
||||
.performClick()
|
||||
assetWifiDialogDisplayed()
|
||||
testFlakyView({ onView(withText("PROCEED")).perform(click()) })
|
||||
}
|
||||
@ -83,24 +86,30 @@ class ZimHostRobot : BaseRobot() {
|
||||
testFlakyView({ isVisible(Text("WiFi connection detected")) })
|
||||
}
|
||||
|
||||
fun assertServerStarted() {
|
||||
fun assertServerStarted(composeTestRule: ComposeContentTestRule) {
|
||||
pauseForBetterTestPerformance()
|
||||
// starting server takes a bit so sometimes it fails to find this view.
|
||||
// which makes this view flaky so we are testing this with FlakyView.
|
||||
testFlakyView({ isVisible(Text("STOP SERVER")) })
|
||||
testFlakyView({
|
||||
composeTestRule.apply {
|
||||
waitForIdle()
|
||||
onNodeWithTag(START_SERVER_BUTTON_TESTING_TAG)
|
||||
.assertTextEquals(context.getString(R.string.stop_server_label).uppercase())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun stopServerIfAlreadyStarted() {
|
||||
fun stopServerIfAlreadyStarted(composeTestRule: ComposeContentTestRule) {
|
||||
try {
|
||||
// Check if the "START SERVER" button is visible because, in most scenarios,
|
||||
// this button will appear when the server is already stopped.
|
||||
// This will expedite our test case, as verifying the visibility of
|
||||
// non-visible views takes more time due to the try mechanism needed
|
||||
// to properly retrieve the view.
|
||||
assertServerStopped()
|
||||
} catch (exception: Exception) {
|
||||
assertServerStopped(composeTestRule)
|
||||
} catch (_: Exception) {
|
||||
// if "START SERVER" button is not visible it means server is started so close it.
|
||||
stopServer()
|
||||
stopServer(composeTestRule)
|
||||
Log.i(
|
||||
"ZIM_HOST_FRAGMENT",
|
||||
"Stopped the server to perform our test case since it was already running"
|
||||
@ -108,66 +117,76 @@ class ZimHostRobot : BaseRobot() {
|
||||
}
|
||||
}
|
||||
|
||||
fun selectZimFileIfNotAlreadySelected() {
|
||||
fun selectZimFileIfNotAlreadySelected(composeTestRule: ComposeContentTestRule) {
|
||||
try {
|
||||
// check both files are selected.
|
||||
assertItemHostedOnServer(2)
|
||||
} catch (assertionFailedError: AssertionFailedError) {
|
||||
assertItemHostedOnServer(2, composeTestRule)
|
||||
} catch (_: AssertionFailedError) {
|
||||
try {
|
||||
val recyclerViewItemsCount =
|
||||
RecyclerViewItemCount(id.recyclerViewZimHost).checkRecyclerViewCount()
|
||||
(0 until recyclerViewItemsCount)
|
||||
.asSequence()
|
||||
.filter { it != 0 }
|
||||
.forEach(::selectZimFile)
|
||||
} catch (assertionFailedError: AssertionFailedError) {
|
||||
selectZimFile(1, composeTestRule)
|
||||
selectZimFile(2, composeTestRule)
|
||||
} catch (_: AssertionFailedError) {
|
||||
Log.i("ZIM_HOST_FRAGMENT", "Failed to select the zim file, probably it is already selected")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectZimFile(position: Int) {
|
||||
private fun selectZimFile(position: Int, composeTestRule: ComposeContentTestRule) {
|
||||
try {
|
||||
onView(
|
||||
RecyclerViewMatcher(id.recyclerViewZimHost).atPositionOnView(
|
||||
position,
|
||||
R.id.itemBookCheckbox
|
||||
)
|
||||
).check(matches(ViewMatchers.isChecked()))
|
||||
} catch (assertionError: AssertionFailedError) {
|
||||
onView(
|
||||
RecyclerViewMatcher(id.recyclerViewZimHost).atPositionOnView(
|
||||
position,
|
||||
R.id.itemBookCheckbox
|
||||
)
|
||||
).perform(click())
|
||||
composeTestRule.onNodeWithTag("$BOOK_ITEM_CHECKBOX_TESTING_TAG$position")
|
||||
.assertIsOn()
|
||||
} catch (_: AssertionFailedError) {
|
||||
composeTestRule.onNodeWithTag("$BOOK_ITEM_CHECKBOX_TESTING_TAG$position")
|
||||
.performClick()
|
||||
}
|
||||
}
|
||||
|
||||
fun assertItemHostedOnServer(itemCount: Int) {
|
||||
val checkedCheckboxCount =
|
||||
RecyclerViewSelectedCheckBoxCountAssertion(
|
||||
id.recyclerViewZimHost,
|
||||
R.id.itemBookCheckbox
|
||||
).countCheckedCheckboxes()
|
||||
assertThat(checkedCheckboxCount, CoreMatchers.`is`(itemCount))
|
||||
fun assertItemHostedOnServer(itemCount: Int, composeTestRule: ComposeContentTestRule) {
|
||||
for (i in 0 until itemCount) {
|
||||
composeTestRule.onNodeWithTag("$BOOK_ITEM_CHECKBOX_TESTING_TAG${i + 1}")
|
||||
.assertIsOn()
|
||||
}
|
||||
}
|
||||
|
||||
fun stopServer() {
|
||||
testFlakyView({ onView(withId(id.startServerButton)).perform(click()) })
|
||||
fun stopServer(composeTestRule: ComposeContentTestRule) {
|
||||
testFlakyView(
|
||||
{
|
||||
composeTestRule.apply {
|
||||
waitForIdle()
|
||||
onNodeWithTag(START_SERVER_BUTTON_TESTING_TAG).performClick()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun assertServerStopped() {
|
||||
pauseForBetterTestPerformance()
|
||||
isVisible(Text("START SERVER"))
|
||||
fun assertServerStopped(composeTestRule: ComposeContentTestRule) {
|
||||
testFlakyView({
|
||||
composeTestRule.apply {
|
||||
waitForIdle()
|
||||
onNodeWithTag(START_SERVER_BUTTON_TESTING_TAG)
|
||||
.assertTextEquals(context.getString(R.string.start_server_label).uppercase())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun assertQrShown() {
|
||||
isVisible(ViewId(id.serverQrCode))
|
||||
fun assertQrShown(composeTestRule: ComposeContentTestRule) {
|
||||
testFlakyView({
|
||||
composeTestRule.apply {
|
||||
waitForIdle()
|
||||
onNodeWithTag(QR_IMAGE_TESTING_TAG)
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun assertQrNotShown() {
|
||||
isNotVisible(ViewId(id.serverQrCode))
|
||||
fun assertQrNotShown(composeTestRule: ComposeContentTestRule) {
|
||||
testFlakyView({
|
||||
composeTestRule.apply {
|
||||
waitForIdle()
|
||||
onNodeWithTag(QR_IMAGE_TESTING_TAG)
|
||||
.assertIsNotDisplayed()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun pauseForBetterTestPerformance() {
|
||||
|
@ -40,6 +40,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
@ -56,9 +57,12 @@ import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.ArticleCount
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.SelectionMode
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
|
||||
|
||||
const val BOOK_ITEM_CHECKBOX_TESTING_TAG = "bookItemCheckboxTestingTag"
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun BookItem(
|
||||
index: Int,
|
||||
bookOnDisk: BookOnDisk,
|
||||
onClick: ((BookOnDisk) -> Unit)? = null,
|
||||
onLongClick: ((BookOnDisk) -> Unit)? = null,
|
||||
@ -87,7 +91,7 @@ fun BookItem(
|
||||
elevation = CardDefaults.elevatedCardElevation(),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainer)
|
||||
) {
|
||||
BookContent(bookOnDisk, selectionMode, onMultiSelect, onClick)
|
||||
BookContent(bookOnDisk, selectionMode, onMultiSelect, onClick, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -98,6 +102,7 @@ private fun BookContent(
|
||||
selectionMode: SelectionMode,
|
||||
onMultiSelect: ((BookOnDisk) -> Unit)?,
|
||||
onClick: ((BookOnDisk) -> Unit)?,
|
||||
index: Int,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@ -106,7 +111,7 @@ private fun BookContent(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (selectionMode == SelectionMode.MULTI) {
|
||||
BookCheckbox(bookOnDisk, selectionMode, onMultiSelect, onClick)
|
||||
BookCheckbox(bookOnDisk, selectionMode, onMultiSelect, onClick, index)
|
||||
}
|
||||
BookIcon(bookOnDisk.book.faviconToPainter())
|
||||
BookDetails(Modifier.weight(1f), bookOnDisk)
|
||||
@ -118,7 +123,8 @@ private fun BookCheckbox(
|
||||
bookOnDisk: BookOnDisk,
|
||||
selectionMode: SelectionMode,
|
||||
onMultiSelect: ((BookOnDisk) -> Unit)?,
|
||||
onClick: ((BookOnDisk) -> Unit)?
|
||||
onClick: ((BookOnDisk) -> Unit)?,
|
||||
index: Int
|
||||
) {
|
||||
Checkbox(
|
||||
checked = bookOnDisk.isSelected,
|
||||
@ -127,7 +133,8 @@ private fun BookCheckbox(
|
||||
SelectionMode.MULTI -> onMultiSelect?.invoke(bookOnDisk)
|
||||
SelectionMode.NORMAL -> onClick?.invoke(bookOnDisk)
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.testTag("$BOOK_ITEM_CHECKBOX_TESTING_TAG$index")
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
@ -65,6 +66,9 @@ import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDis
|
||||
import org.kiwix.kiwixmobile.ui.BookItem
|
||||
import org.kiwix.kiwixmobile.ui.ZimFilesLanguageHeader
|
||||
|
||||
const val START_SERVER_BUTTON_TESTING_TAG = "startServerButtonTestingTag"
|
||||
const val QR_IMAGE_TESTING_TAG = "qrImageTestingTag"
|
||||
|
||||
@Suppress("ComposableLambdaParameterNaming", "LongParameterList")
|
||||
@Composable
|
||||
fun ZimHostScreen(
|
||||
@ -104,7 +108,10 @@ fun ZimHostScreen(
|
||||
KiwixButton(
|
||||
startServerButtonItem.first,
|
||||
startServerButtonItem.third,
|
||||
modifier = Modifier.fillMaxWidth().padding(FOUR_DP),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(FOUR_DP)
|
||||
.testTag(START_SERVER_BUTTON_TESTING_TAG),
|
||||
buttonBackgroundColor = startServerButtonItem.second
|
||||
)
|
||||
}
|
||||
@ -157,7 +164,8 @@ private fun QRImage(qrImageItem: Pair<Boolean, IconItem>) {
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = MINIMUM_HEIGHT_OF_QR_CODE, max = MAXIMUM_HEIGHT_OF_QR_CODE)
|
||||
.padding(horizontal = SIXTEEN_DP),
|
||||
.padding(horizontal = SIXTEEN_DP)
|
||||
.testTag(QR_IMAGE_TESTING_TAG),
|
||||
contentScale = ContentScale.Fit
|
||||
)
|
||||
}
|
||||
@ -181,7 +189,7 @@ private fun BookItemList(
|
||||
item {
|
||||
QRImage(qrImageItem)
|
||||
}
|
||||
itemsIndexed(booksList) { _, bookItem ->
|
||||
itemsIndexed(booksList) { index, bookItem ->
|
||||
when (bookItem) {
|
||||
is BooksOnDiskListItem.LanguageItem -> {
|
||||
ZimFilesLanguageHeader(bookItem)
|
||||
@ -189,6 +197,7 @@ private fun BookItemList(
|
||||
|
||||
is BookOnDisk -> {
|
||||
BookItem(
|
||||
index = index,
|
||||
bookOnDisk = bookItem,
|
||||
selectionMode = selectionMode,
|
||||
onClick = onClick,
|
||||
|
Loading…
x
Reference in New Issue
Block a user