1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-11-16 07:07:13 +00:00

Update ErrorPanel and retest

This commit is contained in:
Su TT
2025-09-24 16:47:21 -04:00
parent 5ba95a2c37
commit fab0d35269
3 changed files with 100 additions and 132 deletions

View File

@@ -0,0 +1,61 @@
package org.schabi.newpipe.ui.components.common
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.schabi.newpipe.R
import org.schabi.newpipe.error.ErrorInfo
import org.schabi.newpipe.error.UserAction
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException
import java.io.IOException
import java.net.SocketTimeoutException
@RunWith(AndroidJUnit4::class)
class CommentSectionErrorTest {
private val context: Context by lazy { ApplicationProvider.getApplicationContext<Context>() }
// Test 1: Network error on initial load (Resource.Error)
@Test
fun testInitialCommentNetworkError() {
val errorInfo = ErrorInfo(
throwable = SocketTimeoutException("Connection timeout"),
userAction = UserAction.REQUESTED_COMMENTS,
request = "comments"
)
Assert.assertEquals(context.getString(R.string.network_error), errorInfo.getMessage(context))
Assert.assertTrue(errorInfo.isReportable)
Assert.assertTrue(errorInfo.isRetryable)
Assert.assertNull(errorInfo.recaptchaUrl)
}
// Test 2: Network error on paging (LoadState.Error)
@Test
fun testPagingNetworkError() {
val errorInfo = ErrorInfo(
throwable = IOException("Paging failed"),
userAction = UserAction.REQUESTED_COMMENTS,
request = "comments"
)
Assert.assertEquals(context.getString(R.string.network_error), errorInfo.getMessage(context))
Assert.assertTrue(errorInfo.isReportable)
Assert.assertTrue(errorInfo.isRetryable)
Assert.assertNull(errorInfo.recaptchaUrl)
}
// Test 3: ReCaptcha during comments load
@Test
fun testReCaptchaDuringComments() {
val url = "https://www.google.com/recaptcha/api/fallback?k=test"
val errorInfo = ErrorInfo(
throwable = ReCaptchaException("ReCaptcha needed", url),
userAction = UserAction.REQUESTED_COMMENTS,
request = "comments"
)
Assert.assertEquals(context.getString(R.string.recaptcha_request_toast), errorInfo.getMessage(context))
Assert.assertEquals(url, errorInfo.recaptchaUrl)
Assert.assertTrue(errorInfo.isReportable)
Assert.assertTrue(errorInfo.isRetryable)
}
}

View File

@@ -1,7 +1,6 @@
package org.schabi.newpipe.ui.components.common
import android.content.Intent
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
@@ -11,6 +10,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
@@ -19,31 +19,10 @@ import org.schabi.newpipe.R
import org.schabi.newpipe.error.ErrorInfo
import org.schabi.newpipe.error.ErrorUtil
import org.schabi.newpipe.error.ReCaptchaActivity
import org.schabi.newpipe.extractor.exceptions.AccountTerminatedException
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException
import org.schabi.newpipe.ui.theme.AppTheme
import org.schabi.newpipe.ui.theme.SizeTokens.SpacingExtraLarge
import org.schabi.newpipe.ui.theme.SizeTokens.SpacingMedium
import org.schabi.newpipe.ui.theme.SizeTokens.SpacingSmall
import org.schabi.newpipe.ui.theme.SizeTokens
import org.schabi.newpipe.util.external_communication.ShareUtils
enum class ErrorAction(@StringRes val actionStringId: Int) {
REPORT(R.string.error_snackbar_action),
SOLVE_CAPTCHA(R.string.recaptcha_solve)
}
/**
* Determines the error action type based on the throwable in ErrorInfo
*
*/
fun determineErrorAction(errorInfo: ErrorInfo): ErrorAction {
return when (errorInfo.throwable) {
is ReCaptchaException -> ErrorAction.SOLVE_CAPTCHA
is AccountTerminatedException -> ErrorAction.REPORT
else -> ErrorAction.REPORT
}
}
@Composable
fun ErrorPanel(
errorInfo: ErrorInfo,
@@ -51,11 +30,13 @@ fun ErrorPanel(
onRetry: (() -> Unit)? = null,
) {
val explanation = errorInfo.getExplanation()
val canOpenInBrowser = errorInfo.openInBrowserUrl != null
val errorActionType = determineErrorAction(errorInfo)
val context = LocalContext.current
val isPreview = LocalInspectionMode.current
val messageText = if (isPreview) {
stringResource(R.string.error_snackbar_message)
} else {
errorInfo.getMessage(context)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
@@ -63,61 +44,48 @@ fun ErrorPanel(
) {
Text(
text = stringResource(errorInfo.messageStringId),
text = messageText,
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold),
textAlign = TextAlign.Center
)
if (explanation.isNotBlank()) {
Spacer(Modifier.height(SpacingSmall))
Text(
text = explanation,
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center
)
}
Spacer(Modifier.height(SpacingMedium))
when (errorActionType) {
ErrorAction.REPORT -> {
ServiceColoredButton(onClick = {
ErrorUtil.openActivity(context, errorInfo)
}) {
Text(stringResource(errorActionType.actionStringId).uppercase())
}
}
ErrorAction.SOLVE_CAPTCHA -> {
ServiceColoredButton(onClick = {
// Starting ReCaptcha Challenge Activity
val intent = Intent(context, ReCaptchaActivity::class.java)
.putExtra(
ReCaptchaActivity.RECAPTCHA_URL_EXTRA,
(errorInfo.throwable as ReCaptchaException).url
)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
}) {
Text(stringResource(errorActionType.actionStringId).uppercase())
}
}
}
onRetry?.let {
ServiceColoredButton(onClick = it) {
Text(stringResource(R.string.retry).uppercase())
}
}
if (canOpenInBrowser) {
Spacer(Modifier.height(SizeTokens.SpacingMedium))
if (errorInfo.isReportable) {
ServiceColoredButton(onClick = {
errorInfo.openInBrowserUrl?.let { url ->
ShareUtils.openUrlInBrowser(context, url)
ErrorUtil.openActivity(context, errorInfo)
}) {
Text(stringResource(R.string.error_snackbar_action).uppercase())
}
}
errorInfo.recaptchaUrl?.let { recaptchaUrl ->
ServiceColoredButton(onClick = {
val intent = Intent(context, ReCaptchaActivity::class.java)
.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, recaptchaUrl)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
}) {
Text(stringResource(R.string.recaptcha_solve).uppercase())
}
}
if (errorInfo.isRetryable) {
onRetry?.let {
ServiceColoredButton(onClick = it) {
Text(stringResource(R.string.retry).uppercase())
}
}
}
errorInfo.openInBrowserUrl?.let { url ->
ServiceColoredButton(onClick = {
ShareUtils.openUrlInBrowser(context, url)
}) {
Text(stringResource(R.string.open_in_browser).uppercase())
}
}
Spacer(Modifier.height(SpacingExtraLarge))
Spacer(Modifier.height(SizeTokens.SpacingExtraLarge))
}
}

View File

@@ -1,61 +0,0 @@
package org.schabi.newpipe.ui.components.common
import androidx.paging.LoadState
import org.junit.Assert
import org.junit.Test
import org.schabi.newpipe.error.ErrorInfo
import org.schabi.newpipe.error.UserAction
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException
import java.io.IOException
import java.net.SocketTimeoutException
class CommentSectionErrorTest {
// Test 1: Network error on initial load (Resource.Error)
@Test
fun testInitialCommentNetworkError() {
val expectedMessage = "Connection timeout"
val networkError = SocketTimeoutException(expectedMessage)
val errorInfo = ErrorInfo(
throwable = networkError,
userAction = UserAction.REQUESTED_COMMENTS,
request = "comments"
)
Assert.assertEquals(networkError, errorInfo.throwable)
Assert.assertEquals(ErrorAction.REPORT, determineErrorAction(errorInfo))
Assert.assertEquals(expectedMessage, errorInfo.getExplanation())
}
// Test 2: Network error on paging (LoadState.Error)
@Test
fun testPagingNetworkError() {
val expectedMessage = "Paging failed"
val pagingError = IOException(expectedMessage)
val loadStateError = LoadState.Error(pagingError)
val errorInfo = ErrorInfo(
throwable = loadStateError.error,
userAction = UserAction.REQUESTED_COMMENTS,
request = "comments"
)
Assert.assertEquals(pagingError, errorInfo.throwable)
Assert.assertEquals(ErrorAction.REPORT, determineErrorAction(errorInfo))
Assert.assertEquals(expectedMessage, errorInfo.getExplanation())
}
// Test 3: ReCaptcha during comments load
@Test
fun testReCaptchaDuringComments() {
val url = "https://www.google.com/recaptcha/api/fallback?k=test"
val expectedMessage = "ReCaptcha needed"
val captcha = ReCaptchaException(expectedMessage, url)
val errorInfo = ErrorInfo(
throwable = captcha,
userAction = UserAction.REQUESTED_COMMENTS,
request = "comments"
)
Assert.assertEquals(ErrorAction.SOLVE_CAPTCHA, determineErrorAction(errorInfo))
Assert.assertEquals(expectedMessage, errorInfo.getExplanation())
}
}