mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-08-04 20:34:14 +01:00
Add unit test coverage for regV5 screens.
This commit is contained in:
committed by
Alex Hart
parent
9814c520e2
commit
5cf61665d4
+13
-6
@@ -24,6 +24,7 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.LinkAnnotation
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
@@ -41,6 +42,7 @@ import org.signal.registration.screens.OnePaneRegistrationScaffold
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.screens.TwoPaneRegistrationScaffold
|
||||
import org.signal.registration.screens.attachDebugLogHelper
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Screen shown when the user's account is locked due to too many failed PIN attempts
|
||||
@@ -67,7 +69,9 @@ private fun OnePaneLayout(
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
OnePaneRegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.ACCOUNT_LOCKED_SCREEN),
|
||||
params = params,
|
||||
content = { paddingValues ->
|
||||
Column(
|
||||
@@ -89,7 +93,7 @@ private fun OnePaneLayout(
|
||||
isElevated = scrollState.canScrollForward
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 16.dp)
|
||||
.horizontalGutters(),
|
||||
@@ -121,7 +125,9 @@ private fun TwoPaneLayout(
|
||||
val secondPaneScrollState = rememberScrollState()
|
||||
|
||||
TwoPaneRegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.ACCOUNT_LOCKED_SCREEN),
|
||||
params = params,
|
||||
firstPane = { paddingValues ->
|
||||
Column(
|
||||
@@ -151,7 +157,7 @@ private fun TwoPaneLayout(
|
||||
isElevated = firstPaneScrollState.canScrollForward || secondPaneScrollState.canScrollForward
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.padding(vertical = 16.dp)
|
||||
.fillMaxWidth()
|
||||
.horizontalGutters(),
|
||||
@@ -195,7 +201,7 @@ private fun Description(
|
||||
private fun NextButton(onEvent: (AccountLockedScreenEvents) -> Unit, modifier: Modifier = Modifier) {
|
||||
Button(
|
||||
onClick = { onEvent(AccountLockedScreenEvents.Next) },
|
||||
modifier = modifier
|
||||
modifier = modifier.testTag(TestTags.ACCOUNT_LOCKED_NEXT_BUTTON)
|
||||
) {
|
||||
Text(stringResource(R.string.RegistrationActivity_next))
|
||||
}
|
||||
@@ -222,7 +228,8 @@ private fun LearnMore(onEvent: (AccountLockedScreenEvents) -> Unit) {
|
||||
}
|
||||
}
|
||||
},
|
||||
textAlign = TextAlign.Center
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.testTag(TestTags.ACCOUNT_LOCKED_LEARN_MORE_BUTTON)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+11
-4
@@ -38,6 +38,7 @@ import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
@@ -60,6 +61,7 @@ import org.signal.registration.screens.TwoPaneRegistrationScaffold
|
||||
import org.signal.registration.screens.attachDebugLogHelper
|
||||
import org.signal.registration.screens.localbackuprestore.attachBackupKeyAutoFillHelper
|
||||
import org.signal.registration.screens.localbackuprestore.backupKeyAutoFillHelper
|
||||
import org.signal.registration.test.TestTags
|
||||
import org.signal.registration.util.RegistrationCredentialManager
|
||||
|
||||
@Composable
|
||||
@@ -84,7 +86,9 @@ private fun OnePaneLayout(
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
OnePaneRegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.ENTER_AEP_SCREEN),
|
||||
params = params,
|
||||
content = { paddingValues ->
|
||||
Column(
|
||||
@@ -141,7 +145,9 @@ private fun TwoPaneLayout(
|
||||
val secondPaneScrollState = rememberScrollState()
|
||||
|
||||
TwoPaneRegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.ENTER_AEP_SCREEN),
|
||||
params = params,
|
||||
firstPane = { paddingValues ->
|
||||
Column(
|
||||
@@ -258,6 +264,7 @@ private fun RecoveryKeyTextField(state: EnterAepState, onEvent: (EnterAepEvents)
|
||||
visualTransformation = visualTransform,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TestTags.ENTER_AEP_INPUT)
|
||||
.focusRequester(focusRequester)
|
||||
.attachBackupKeyAutoFillHelper(autoFillHelper)
|
||||
.onGloballyPositioned {
|
||||
@@ -292,7 +299,7 @@ private fun FillFromPasswordManagerButton(onEvent: (EnterAepEvents) -> Unit, mod
|
||||
@Composable
|
||||
private fun NoRecoverKeyButton(onEvent: (EnterAepEvents) -> Unit, modifier: Modifier = Modifier) {
|
||||
TextButton(
|
||||
modifier = modifier,
|
||||
modifier = modifier.testTag(TestTags.ENTER_AEP_NO_KEY_BUTTON),
|
||||
shape = RoundedCornerShape(0.dp),
|
||||
onClick = { onEvent(EnterAepEvents.Cancel) }
|
||||
) {
|
||||
@@ -303,7 +310,7 @@ private fun NoRecoverKeyButton(onEvent: (EnterAepEvents) -> Unit, modifier: Modi
|
||||
@Composable
|
||||
private fun NextButton(state: EnterAepState, onEvent: (EnterAepEvents) -> Unit, modifier: Modifier = Modifier) {
|
||||
Buttons.LargeTonal(
|
||||
modifier = modifier,
|
||||
modifier = modifier.testTag(TestTags.ENTER_AEP_NEXT_BUTTON),
|
||||
enabled = state.isBackupKeyValid && state.aepValidationError == null && !state.isRegistering,
|
||||
onClick = { onEvent(EnterAepEvents.Submit) }
|
||||
) {
|
||||
|
||||
+4
@@ -29,12 +29,14 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import org.signal.core.ui.compose.AllDevicePreviews
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.signal.registration.R
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Screen to display a captcha verification using a WebView.
|
||||
@@ -52,6 +54,7 @@ fun CaptchaScreen(
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.testTag(TestTags.CAPTCHA_SCREEN)
|
||||
.fillMaxSize()
|
||||
.windowInsetsPadding(WindowInsets.safeDrawing)
|
||||
) {
|
||||
@@ -133,6 +136,7 @@ fun CaptchaScreen(
|
||||
onClick = { onEvent(CaptchaScreenEvents.Cancel) },
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.testTag(TestTags.CAPTCHA_CANCEL_BUTTON)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.CaptchaScreen__cancel))
|
||||
|
||||
+23
-6
@@ -44,6 +44,7 @@ import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
@@ -66,6 +67,7 @@ import org.signal.registration.screens.OnePaneRegistrationScaffold
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.screens.TwoPaneRegistrationScaffold
|
||||
import org.signal.registration.screens.attachDebugLogHelper
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Screen that allows someone to search and select a country code from a supported list of countries.
|
||||
@@ -92,7 +94,9 @@ private fun OnePaneLayout(
|
||||
val topBarScrollBehavior = RegistrationScaffold.rememberTopBarScrollBehavior()
|
||||
|
||||
OnePaneRegistrationScaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.COUNTRY_CODE_PICKER_SCREEN),
|
||||
params = layoutParams,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
@@ -128,7 +132,9 @@ private fun TwoPaneLayout(
|
||||
val topBarScrollBehavior = RegistrationScaffold.rememberTopBarScrollBehavior()
|
||||
|
||||
TwoPaneRegistrationScaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.COUNTRY_CODE_PICKER_SCREEN),
|
||||
params = params,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
@@ -176,9 +182,19 @@ fun TopAppBar(
|
||||
Scaffolds.DefaultTopAppBar(
|
||||
title = "",
|
||||
titleContent = { _, _ -> },
|
||||
onNavigationClick = onCloseClick,
|
||||
navigationIcon = SignalIcons.X.imageVector,
|
||||
navigationContentDescription = stringResource(R.string.CountryCodeSelectScreen__close),
|
||||
navigationIconContent = {
|
||||
IconButton(
|
||||
onClick = onCloseClick,
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp)
|
||||
.testTag(TestTags.COUNTRY_CODE_CLOSE_BUTTON)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = SignalIcons.X.imageVector,
|
||||
contentDescription = stringResource(R.string.CountryCodeSelectScreen__close)
|
||||
)
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
}
|
||||
@@ -393,7 +409,8 @@ private fun SearchBar(
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.fillMaxWidth()
|
||||
.defaultMinSize(minHeight = 54.dp)
|
||||
.focusRequester(focusRequester),
|
||||
.focusRequester(focusRequester)
|
||||
.testTag(TestTags.COUNTRY_CODE_SEARCH_FIELD),
|
||||
visualTransformation = VisualTransformation.None,
|
||||
colors = TextFieldDefaults.colors(
|
||||
// TODO move to SignalTheme
|
||||
|
||||
+14
-4
@@ -38,6 +38,7 @@ import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
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.text.input.ImeAction
|
||||
@@ -52,6 +53,7 @@ import org.signal.core.ui.compose.SignalIcons
|
||||
import org.signal.core.ui.rememberWindowBreakpoint
|
||||
import org.signal.registration.R
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Profile creation screen for the registration flow. Captures the user's given name, family name,
|
||||
@@ -110,7 +112,9 @@ private fun CompactLayout(
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
RegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.CREATE_PROFILE_SCREEN),
|
||||
content = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -153,7 +157,9 @@ private fun CompactLayout(
|
||||
capitalization = KeyboardCapitalization.Words,
|
||||
imeAction = ImeAction.Next
|
||||
),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TestTags.CREATE_PROFILE_GIVEN_NAME_FIELD)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
@@ -168,7 +174,9 @@ private fun CompactLayout(
|
||||
capitalization = KeyboardCapitalization.Words,
|
||||
imeAction = ImeAction.Done
|
||||
),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TestTags.CREATE_PROFILE_FAMILY_NAME_FIELD)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
@@ -193,6 +201,7 @@ private fun CompactLayout(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.widthIn(max = 320.dp)
|
||||
.testTag(TestTags.CREATE_PROFILE_NEXT_BUTTON)
|
||||
) {
|
||||
if (state.isSubmitting) {
|
||||
CircularProgressIndicator(
|
||||
@@ -241,7 +250,8 @@ private fun WhoCanFindMeRow(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(enabled = enabled, onClick = onClick)
|
||||
.padding(vertical = 12.dp),
|
||||
.padding(vertical = 12.dp)
|
||||
.testTag(TestTags.CREATE_PROFILE_WHO_CAN_FIND_ME_ROW),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
|
||||
+6
-1
@@ -21,6 +21,7 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -30,6 +31,7 @@ import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.SignalIcons
|
||||
import org.signal.registration.R
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
@Composable
|
||||
fun DeviceTransferCompleteScreen(
|
||||
@@ -40,7 +42,9 @@ fun DeviceTransferCompleteScreen(
|
||||
BackHandler(enabled = true) { /* no-op: the transfer is done, don't let the user back out */ }
|
||||
|
||||
RegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.DEVICE_TRANSFER_COMPLETE_SCREEN),
|
||||
content = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -87,6 +91,7 @@ fun DeviceTransferCompleteScreen(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.widthIn(max = 320.dp)
|
||||
.testTag(TestTags.DEVICE_TRANSFER_COMPLETE_CONTINUE_BUTTON)
|
||||
) {
|
||||
Text(stringResource(R.string.DeviceTransferComplete__continue_registration))
|
||||
}
|
||||
|
||||
+6
-1
@@ -20,6 +20,7 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -29,6 +30,7 @@ import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.SignalIcons
|
||||
import org.signal.registration.R
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
@Composable
|
||||
fun DeviceTransferInstructionsScreen(
|
||||
@@ -37,7 +39,9 @@ fun DeviceTransferInstructionsScreen(
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
RegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.DEVICE_TRANSFER_INSTRUCTIONS_SCREEN),
|
||||
content = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -84,6 +88,7 @@ fun DeviceTransferInstructionsScreen(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.widthIn(max = 320.dp)
|
||||
.testTag(TestTags.DEVICE_TRANSFER_INSTRUCTIONS_CONTINUE_BUTTON)
|
||||
) {
|
||||
Text(stringResource(R.string.DeviceTransferInstructions__continue))
|
||||
}
|
||||
|
||||
+11
-3
@@ -21,6 +21,7 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -30,6 +31,7 @@ import org.signal.core.ui.compose.Dialogs
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.signal.registration.R
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
@Composable
|
||||
fun DeviceTransferProgressScreen(
|
||||
@@ -55,7 +57,9 @@ fun DeviceTransferProgressScreen(
|
||||
}
|
||||
|
||||
RegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.DEVICE_TRANSFER_PROGRESS_SCREEN),
|
||||
content = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -127,7 +131,9 @@ fun DeviceTransferProgressScreen(
|
||||
if (state.status == DeviceTransferProgressState.Status.FAILED) {
|
||||
Buttons.LargeTonal(
|
||||
onClick = { onEvent(DeviceTransferProgressScreenEvents.TryAgainClicked) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TestTags.DEVICE_TRANSFER_PROGRESS_TRY_AGAIN_BUTTON)
|
||||
) {
|
||||
Text(stringResource(R.string.DeviceTransferProgress__try_again))
|
||||
}
|
||||
@@ -136,7 +142,9 @@ fun DeviceTransferProgressScreen(
|
||||
|
||||
Buttons.LargeTonal(
|
||||
onClick = { onEvent(DeviceTransferProgressScreenEvents.CancelClicked) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TestTags.DEVICE_TRANSFER_PROGRESS_CANCEL_BUTTON)
|
||||
) {
|
||||
Text(stringResource(R.string.DeviceTransferProgress__cancel))
|
||||
}
|
||||
|
||||
+11
-2
@@ -30,6 +30,7 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
@@ -47,6 +48,7 @@ import org.signal.core.ui.compose.Previews
|
||||
import org.signal.devicetransfer.WifiDirect
|
||||
import org.signal.registration.R
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.test.TestTags
|
||||
import java.util.Locale
|
||||
|
||||
@Composable
|
||||
@@ -129,7 +131,9 @@ internal fun DeviceTransferSetupScreen(
|
||||
}
|
||||
|
||||
RegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.DEVICE_TRANSFER_SETUP_SCREEN),
|
||||
content = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -245,6 +249,7 @@ private fun VerifyStep(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.widthIn(max = 320.dp)
|
||||
.testTag(TestTags.DEVICE_TRANSFER_SETUP_NUMBERS_MATCH_BUTTON)
|
||||
) {
|
||||
Text(stringResource(R.string.DeviceTransferSetup__numbers_match))
|
||||
}
|
||||
@@ -254,6 +259,7 @@ private fun VerifyStep(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.widthIn(max = 320.dp)
|
||||
.testTag(TestTags.DEVICE_TRANSFER_SETUP_NUMBERS_DO_NOT_MATCH_BUTTON)
|
||||
) {
|
||||
Text(stringResource(R.string.DeviceTransferSetup__numbers_do_not_match))
|
||||
}
|
||||
@@ -277,6 +283,7 @@ private fun ErrorStep(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.widthIn(max = 320.dp)
|
||||
.testTag(TestTags.DEVICE_TRANSFER_SETUP_ERROR_ACTION_BUTTON)
|
||||
) {
|
||||
Text(buttonText)
|
||||
}
|
||||
@@ -304,7 +311,9 @@ private fun TroubleshootingStep(onTryAgain: () -> Unit) {
|
||||
) {
|
||||
Buttons.LargeTonal(
|
||||
onClick = onTryAgain,
|
||||
modifier = Modifier.widthIn(max = 320.dp)
|
||||
modifier = Modifier
|
||||
.widthIn(max = 320.dp)
|
||||
.testTag(TestTags.DEVICE_TRANSFER_SETUP_TROUBLESHOOTING_RETRY_BUTTON)
|
||||
) {
|
||||
Text(stringResource(R.string.DeviceTransferSetup__try_again))
|
||||
}
|
||||
|
||||
+17
-6
@@ -26,6 +26,7 @@ import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.signal.core.ui.compose.AllDevicePreviews
|
||||
@@ -34,6 +35,7 @@ import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.SignalIcons
|
||||
import org.signal.registration.R
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
@Composable
|
||||
fun PhoneNumberDiscoverabilityScreen(
|
||||
@@ -42,13 +44,18 @@ fun PhoneNumberDiscoverabilityScreen(
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
RegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_SCREEN),
|
||||
topBar = {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 4.dp, vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
IconButton(onClick = { onEvent(PhoneNumberDiscoverabilityScreenEvents.BackClicked) }) {
|
||||
IconButton(
|
||||
onClick = { onEvent(PhoneNumberDiscoverabilityScreenEvents.BackClicked) },
|
||||
modifier = Modifier.testTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_BACK_BUTTON)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = SignalIcons.ArrowStart.imageVector,
|
||||
contentDescription = stringResource(R.string.PhoneNumberDiscoverabilityScreen__back)
|
||||
@@ -70,13 +77,15 @@ fun PhoneNumberDiscoverabilityScreen(
|
||||
DiscoverabilityOption(
|
||||
label = stringResource(R.string.PhoneNumberPrivacy_everyone),
|
||||
selected = state.discoverable,
|
||||
onClick = { onEvent(PhoneNumberDiscoverabilityScreenEvents.EveryoneSelected) }
|
||||
onClick = { onEvent(PhoneNumberDiscoverabilityScreenEvents.EveryoneSelected) },
|
||||
modifier = Modifier.testTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_EVERYONE_OPTION)
|
||||
)
|
||||
|
||||
DiscoverabilityOption(
|
||||
label = stringResource(R.string.PhoneNumberPrivacy_nobody),
|
||||
selected = !state.discoverable,
|
||||
onClick = { onEvent(PhoneNumberDiscoverabilityScreenEvents.NobodySelected) }
|
||||
onClick = { onEvent(PhoneNumberDiscoverabilityScreenEvents.NobodySelected) },
|
||||
modifier = Modifier.testTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_NOBODY_OPTION)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
@@ -107,6 +116,7 @@ fun PhoneNumberDiscoverabilityScreen(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.widthIn(max = 320.dp)
|
||||
.testTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_SAVE_BUTTON)
|
||||
) {
|
||||
Text(stringResource(R.string.PhoneNumberDiscoverabilityScreen__save))
|
||||
}
|
||||
@@ -137,10 +147,11 @@ fun PhoneNumberDiscoverabilityScreen(
|
||||
private fun DiscoverabilityOption(
|
||||
label: String,
|
||||
selected: Boolean,
|
||||
onClick: () -> Unit
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
|
||||
+14
-4
@@ -36,6 +36,7 @@ import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
@@ -54,6 +55,7 @@ import org.signal.registration.screens.OnePaneRegistrationScaffold
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.screens.TwoPaneRegistrationScaffold
|
||||
import org.signal.registration.screens.attachDebugLogHelper
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
private const val PASSPHRASE_LENGTH = 30
|
||||
private const val CHUNK_SIZE = 5
|
||||
@@ -106,7 +108,9 @@ private fun OnePaneLayout(
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
OnePaneRegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_SCREEN),
|
||||
params = params,
|
||||
content = { paddingValues ->
|
||||
Column(
|
||||
@@ -154,7 +158,9 @@ private fun TwoPaneLayout(
|
||||
val secondPaneScrollState = rememberScrollState()
|
||||
|
||||
TwoPaneRegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_SCREEN),
|
||||
params = params,
|
||||
firstPane = { paddingValues ->
|
||||
Column(
|
||||
@@ -265,6 +271,7 @@ private fun PassphraseTextField(
|
||||
visualTransformation = visualTransform,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_INPUT)
|
||||
.focusRequester(focusRequester)
|
||||
.onGloballyPositioned {
|
||||
if (requestFocus) {
|
||||
@@ -293,7 +300,9 @@ private fun FooterButtons(
|
||||
.padding(horizontal = 24.dp, vertical = 16.dp)
|
||||
) {
|
||||
TextButton(
|
||||
modifier = Modifier.weight(weight = 1f, fill = false),
|
||||
modifier = Modifier
|
||||
.weight(weight = 1f, fill = false)
|
||||
.testTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_NO_PASSPHRASE_BUTTON),
|
||||
onClick = onCancel,
|
||||
shape = RoundedCornerShape(0.dp)
|
||||
) {
|
||||
@@ -304,7 +313,8 @@ private fun FooterButtons(
|
||||
|
||||
Buttons.LargeTonal(
|
||||
enabled = isValid,
|
||||
onClick = { onSubmit(passphrase) }
|
||||
onClick = { onSubmit(passphrase) },
|
||||
modifier = Modifier.testTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_NEXT_BUTTON)
|
||||
) {
|
||||
Text(text = stringResource(R.string.LocalBackupRestoreScreen__next))
|
||||
}
|
||||
|
||||
+15
-4
@@ -51,6 +51,7 @@ import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
@@ -74,6 +75,7 @@ import org.signal.registration.screens.PinVisualTransformation
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.screens.TwoPaneRegistrationScaffold
|
||||
import org.signal.registration.screens.attachDebugLogHelper
|
||||
import org.signal.registration.test.TestTags
|
||||
import org.signal.core.ui.R as CoreR
|
||||
|
||||
private const val STEP_TRANSITION_DURATION = 250
|
||||
@@ -130,7 +132,9 @@ private fun OnePaneLayout(
|
||||
val topBarScrollBehavior = RegistrationScaffold.rememberTopBarScrollBehavior()
|
||||
|
||||
RegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.PIN_CREATION_SCREEN),
|
||||
topBar = {
|
||||
PinCreationTopBar(
|
||||
scrollBehavior = topBarScrollBehavior,
|
||||
@@ -191,7 +195,9 @@ private fun TwoPaneLayout(
|
||||
val topBarScrollBehavior = RegistrationScaffold.rememberTopBarScrollBehavior()
|
||||
|
||||
TwoPaneRegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.PIN_CREATION_SCREEN),
|
||||
params = params,
|
||||
topBar = {
|
||||
PinCreationTopBar(
|
||||
@@ -391,7 +397,9 @@ private fun PinInputField(
|
||||
TextField(
|
||||
value = pin,
|
||||
onValueChange = onPinChanged,
|
||||
modifier = modifier.focusRequester(focusRequester),
|
||||
modifier = modifier
|
||||
.testTag(TestTags.PIN_CREATION_INPUT)
|
||||
.focusRequester(focusRequester),
|
||||
textStyle = MaterialTheme.typography.bodyLarge.copy(textAlign = TextAlign.Center),
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
@@ -432,7 +440,9 @@ private fun KeyboardToggleButton(
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onToggleKeyboard,
|
||||
modifier = modifier.fillMaxWidth()
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TestTags.PIN_CREATION_TOGGLE_KEYBOARD_BUTTON)
|
||||
) {
|
||||
Icon(
|
||||
painter = SignalIcons.Keyboard.painter,
|
||||
@@ -537,6 +547,7 @@ private fun NextButton(
|
||||
modifier = Modifier
|
||||
.widthIn(max = params.maxButtonWidth)
|
||||
.padding(params.footerPadding)
|
||||
.testTag(TestTags.PIN_CREATION_NEXT_BUTTON)
|
||||
) {
|
||||
if (loading) {
|
||||
CircularProgressIndicator(
|
||||
|
||||
+14
-4
@@ -40,6 +40,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
@@ -58,6 +59,7 @@ import org.signal.registration.screens.PinVisualTransformation
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.screens.TwoPaneRegistrationScaffold
|
||||
import org.signal.registration.screens.attachDebugLogHelper
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* PIN entry screen for the registration flow.
|
||||
@@ -160,7 +162,9 @@ private fun OnePaneLayout(
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
RegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.PIN_ENTRY_SCREEN),
|
||||
content = {
|
||||
Box(
|
||||
modifier = modifier.fillMaxSize()
|
||||
@@ -233,7 +237,9 @@ private fun TwoPaneLayout(
|
||||
val secondPaneScrollState = rememberScrollState()
|
||||
|
||||
TwoPaneRegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.PIN_ENTRY_SCREEN),
|
||||
params = params,
|
||||
firstPane = { paddingValues ->
|
||||
Column(
|
||||
@@ -346,6 +352,7 @@ private fun PinInputField(
|
||||
onValueChange = onPinChanged,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TestTags.PIN_ENTRY_INPUT)
|
||||
.focusRequester(focusRequester),
|
||||
textStyle = MaterialTheme.typography.bodyLarge.copy(textAlign = TextAlign.Center),
|
||||
singleLine = true,
|
||||
@@ -403,7 +410,9 @@ private fun KeyboardToggleButton(
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onToggleKeyboard,
|
||||
modifier = modifier.fillMaxWidth()
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(TestTags.PIN_ENTRY_TOGGLE_KEYBOARD_BUTTON)
|
||||
) {
|
||||
Icon(
|
||||
painter = SignalIcons.Keyboard.painter,
|
||||
@@ -437,6 +446,7 @@ private fun ContinueButton(
|
||||
modifier = Modifier
|
||||
.widthIn(max = params.maxButtonWidth)
|
||||
.padding(params.footerPadding)
|
||||
.testTag(TestTags.PIN_ENTRY_CONTINUE_BUTTON)
|
||||
) {
|
||||
if (loading) {
|
||||
CircularProgressIndicator(
|
||||
@@ -459,7 +469,7 @@ private fun SkipButton(
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onSkip,
|
||||
modifier = modifier
|
||||
modifier = modifier.testTag(TestTags.PIN_ENTRY_SKIP_BUTTON)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.PinEntryScreen__skip),
|
||||
|
||||
+18
-5
@@ -44,6 +44,7 @@ import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
@@ -63,6 +64,7 @@ import org.signal.registration.screens.OnePaneRegistrationScaffold
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.screens.TwoPaneRegistrationScaffold
|
||||
import org.signal.registration.screens.attachDebugLogHelper
|
||||
import org.signal.registration.test.TestTags
|
||||
import org.signal.core.ui.R as CoreR
|
||||
|
||||
/**
|
||||
@@ -92,7 +94,9 @@ private fun OnePaneLayout(
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
OnePaneRegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.QUICK_RESTORE_QR_SCREEN),
|
||||
params = params,
|
||||
topBar = { TopAppBar() },
|
||||
content = { paddingValues ->
|
||||
@@ -131,7 +135,9 @@ private fun TwoPaneLayout(
|
||||
val secondPaneScrollState = rememberScrollState()
|
||||
|
||||
TwoPaneRegistrationScaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.testTag(TestTags.QUICK_RESTORE_QR_SCREEN),
|
||||
params = params,
|
||||
topBar = { TopAppBar() },
|
||||
firstPane = { paddingValues ->
|
||||
@@ -276,7 +282,10 @@ private fun QrCodePane(
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Button(onClick = { onEvent(QuickRestoreQrEvents.RetryQrCode) }) {
|
||||
Button(
|
||||
onClick = { onEvent(QuickRestoreQrEvents.RetryQrCode) },
|
||||
modifier = Modifier.testTag(TestTags.QUICK_RESTORE_QR_RETRY_BUTTON)
|
||||
) {
|
||||
Text(stringResource(R.string.QuickRestoreQRScreen__retry))
|
||||
}
|
||||
}
|
||||
@@ -296,7 +305,10 @@ private fun QrCodePane(
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Button(onClick = { onEvent(QuickRestoreQrEvents.RetryQrCode) }) {
|
||||
Button(
|
||||
onClick = { onEvent(QuickRestoreQrEvents.RetryQrCode) },
|
||||
modifier = Modifier.testTag(TestTags.QUICK_RESTORE_QR_RETRY_BUTTON)
|
||||
) {
|
||||
Text(stringResource(R.string.QuickRestoreQRScreen__retry))
|
||||
}
|
||||
}
|
||||
@@ -338,7 +350,8 @@ private fun CancelFooter(onEvent: (QuickRestoreQrEvents) -> Unit) {
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
TextButton(
|
||||
onClick = { onEvent(QuickRestoreQrEvents.Cancel) }
|
||||
onClick = { onEvent(QuickRestoreQrEvents.Cancel) },
|
||||
modifier = Modifier.testTag(TestTags.QUICK_RESTORE_QR_CANCEL_BUTTON)
|
||||
) {
|
||||
Text(stringResource(android.R.string.cancel))
|
||||
}
|
||||
|
||||
+6
-4
@@ -35,6 +35,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -51,6 +52,7 @@ import org.signal.registration.screens.OnePaneRegistrationScaffold
|
||||
import org.signal.registration.screens.RegistrationScaffold
|
||||
import org.signal.registration.screens.TwoPaneRegistrationScaffold
|
||||
import org.signal.registration.screens.attachDebugLogHelper
|
||||
import org.signal.registration.test.TestTags
|
||||
import java.util.Date
|
||||
|
||||
@Composable
|
||||
@@ -107,7 +109,7 @@ private fun OnePaneLayout(
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
OnePaneRegistrationScaffold(
|
||||
modifier = modifier,
|
||||
modifier = modifier.testTag(TestTags.REMOTE_BACKUP_RESTORE_SCREEN),
|
||||
params = params,
|
||||
content = { paddingValues ->
|
||||
Column(
|
||||
@@ -150,7 +152,7 @@ private fun TwoPaneLayout(
|
||||
val secondPaneScrollState = rememberScrollState()
|
||||
|
||||
TwoPaneRegistrationScaffold(
|
||||
modifier = modifier,
|
||||
modifier = modifier.testTag(TestTags.REMOTE_BACKUP_RESTORE_SCREEN),
|
||||
params = params,
|
||||
firstPane = { paddingValues ->
|
||||
Column(
|
||||
@@ -273,7 +275,7 @@ private fun RestoreButton(
|
||||
) {
|
||||
Buttons.LargeTonal(
|
||||
onClick = { onEvent(RemoteBackupRestoreScreenEvents.BackupRestoreBackup) },
|
||||
modifier = modifier
|
||||
modifier = modifier.testTag(TestTags.REMOTE_BACKUP_RESTORE_RESTORE_BUTTON)
|
||||
) {
|
||||
Text(text = stringResource(R.string.RemoteRestoreScreen__restore_backup))
|
||||
}
|
||||
@@ -286,7 +288,7 @@ private fun CancelButton(
|
||||
) {
|
||||
TextButton(
|
||||
onClick = { onEvent(RemoteBackupRestoreScreenEvents.Cancel) },
|
||||
modifier = modifier
|
||||
modifier = modifier.testTag(TestTags.REMOTE_BACKUP_RESTORE_CANCEL_BUTTON)
|
||||
) {
|
||||
Text(text = stringResource(android.R.string.cancel))
|
||||
}
|
||||
|
||||
@@ -76,4 +76,87 @@ object TestTags {
|
||||
const val LOCAL_BACKUP_RESTORE_RESTORE_BUTTON = "local_backup_restore_restore_button"
|
||||
const val LOCAL_BACKUP_RESTORE_PROGRESS_BAR = "local_backup_restore_progress_bar"
|
||||
const val LOCAL_BACKUP_RESTORE_CONTINUE_BUTTON = "local_backup_restore_continue_button"
|
||||
|
||||
// Account Locked Screen
|
||||
const val ACCOUNT_LOCKED_SCREEN = "account_locked_screen"
|
||||
const val ACCOUNT_LOCKED_NEXT_BUTTON = "account_locked_next_button"
|
||||
const val ACCOUNT_LOCKED_LEARN_MORE_BUTTON = "account_locked_learn_more_button"
|
||||
|
||||
// Enter AEP Screen
|
||||
const val ENTER_AEP_SCREEN = "enter_aep_screen"
|
||||
const val ENTER_AEP_INPUT = "enter_aep_input"
|
||||
const val ENTER_AEP_NEXT_BUTTON = "enter_aep_next_button"
|
||||
const val ENTER_AEP_NO_KEY_BUTTON = "enter_aep_no_key_button"
|
||||
|
||||
// Captcha Screen
|
||||
const val CAPTCHA_SCREEN = "captcha_screen"
|
||||
const val CAPTCHA_CANCEL_BUTTON = "captcha_cancel_button"
|
||||
|
||||
// Country Code Picker Screen
|
||||
const val COUNTRY_CODE_PICKER_SCREEN = "country_code_picker_screen"
|
||||
const val COUNTRY_CODE_SEARCH_FIELD = "country_code_search_field"
|
||||
const val COUNTRY_CODE_CLOSE_BUTTON = "country_code_close_button"
|
||||
|
||||
// Create Profile Screen
|
||||
const val CREATE_PROFILE_SCREEN = "create_profile_screen"
|
||||
const val CREATE_PROFILE_GIVEN_NAME_FIELD = "create_profile_given_name_field"
|
||||
const val CREATE_PROFILE_FAMILY_NAME_FIELD = "create_profile_family_name_field"
|
||||
const val CREATE_PROFILE_WHO_CAN_FIND_ME_ROW = "create_profile_who_can_find_me_row"
|
||||
const val CREATE_PROFILE_NEXT_BUTTON = "create_profile_next_button"
|
||||
|
||||
// Phone Number Discoverability Screen
|
||||
const val PHONE_NUMBER_DISCOVERABILITY_SCREEN = "phone_number_discoverability_screen"
|
||||
const val PHONE_NUMBER_DISCOVERABILITY_EVERYONE_OPTION = "phone_number_discoverability_everyone_option"
|
||||
const val PHONE_NUMBER_DISCOVERABILITY_NOBODY_OPTION = "phone_number_discoverability_nobody_option"
|
||||
const val PHONE_NUMBER_DISCOVERABILITY_SAVE_BUTTON = "phone_number_discoverability_save_button"
|
||||
const val PHONE_NUMBER_DISCOVERABILITY_BACK_BUTTON = "phone_number_discoverability_back_button"
|
||||
|
||||
// Device Transfer Complete Screen
|
||||
const val DEVICE_TRANSFER_COMPLETE_SCREEN = "device_transfer_complete_screen"
|
||||
const val DEVICE_TRANSFER_COMPLETE_CONTINUE_BUTTON = "device_transfer_complete_continue_button"
|
||||
|
||||
// Device Transfer Instructions Screen
|
||||
const val DEVICE_TRANSFER_INSTRUCTIONS_SCREEN = "device_transfer_instructions_screen"
|
||||
const val DEVICE_TRANSFER_INSTRUCTIONS_CONTINUE_BUTTON = "device_transfer_instructions_continue_button"
|
||||
|
||||
// Device Transfer Progress Screen
|
||||
const val DEVICE_TRANSFER_PROGRESS_SCREEN = "device_transfer_progress_screen"
|
||||
const val DEVICE_TRANSFER_PROGRESS_CANCEL_BUTTON = "device_transfer_progress_cancel_button"
|
||||
const val DEVICE_TRANSFER_PROGRESS_TRY_AGAIN_BUTTON = "device_transfer_progress_try_again_button"
|
||||
|
||||
// Device Transfer Setup Screen
|
||||
const val DEVICE_TRANSFER_SETUP_SCREEN = "device_transfer_setup_screen"
|
||||
const val DEVICE_TRANSFER_SETUP_NUMBERS_MATCH_BUTTON = "device_transfer_setup_numbers_match_button"
|
||||
const val DEVICE_TRANSFER_SETUP_NUMBERS_DO_NOT_MATCH_BUTTON = "device_transfer_setup_numbers_do_not_match_button"
|
||||
const val DEVICE_TRANSFER_SETUP_ERROR_ACTION_BUTTON = "device_transfer_setup_error_action_button"
|
||||
const val DEVICE_TRANSFER_SETUP_TROUBLESHOOTING_RETRY_BUTTON = "device_transfer_setup_troubleshooting_retry_button"
|
||||
|
||||
// Enter Local Backup Passphrase Screen
|
||||
const val ENTER_LOCAL_BACKUP_PASSPHRASE_SCREEN = "enter_local_backup_passphrase_screen"
|
||||
const val ENTER_LOCAL_BACKUP_PASSPHRASE_INPUT = "enter_local_backup_passphrase_input"
|
||||
const val ENTER_LOCAL_BACKUP_PASSPHRASE_NEXT_BUTTON = "enter_local_backup_passphrase_next_button"
|
||||
const val ENTER_LOCAL_BACKUP_PASSPHRASE_NO_PASSPHRASE_BUTTON = "enter_local_backup_passphrase_no_passphrase_button"
|
||||
|
||||
// Pin Creation Screen
|
||||
const val PIN_CREATION_SCREEN = "pin_creation_screen"
|
||||
const val PIN_CREATION_INPUT = "pin_creation_input"
|
||||
const val PIN_CREATION_NEXT_BUTTON = "pin_creation_next_button"
|
||||
const val PIN_CREATION_TOGGLE_KEYBOARD_BUTTON = "pin_creation_toggle_keyboard_button"
|
||||
|
||||
// Pin Entry Screen
|
||||
const val PIN_ENTRY_SCREEN = "pin_entry_screen"
|
||||
const val PIN_ENTRY_INPUT = "pin_entry_input"
|
||||
const val PIN_ENTRY_CONTINUE_BUTTON = "pin_entry_continue_button"
|
||||
const val PIN_ENTRY_TOGGLE_KEYBOARD_BUTTON = "pin_entry_toggle_keyboard_button"
|
||||
const val PIN_ENTRY_SKIP_BUTTON = "pin_entry_skip_button"
|
||||
|
||||
// Quick Restore QR Screen
|
||||
const val QUICK_RESTORE_QR_SCREEN = "quick_restore_qr_screen"
|
||||
const val QUICK_RESTORE_QR_RETRY_BUTTON = "quick_restore_qr_retry_button"
|
||||
const val QUICK_RESTORE_QR_CANCEL_BUTTON = "quick_restore_qr_cancel_button"
|
||||
|
||||
// Remote Backup Restore Screen
|
||||
const val REMOTE_BACKUP_RESTORE_SCREEN = "remote_backup_restore_screen"
|
||||
const val REMOTE_BACKUP_RESTORE_RESTORE_BUTTON = "remote_backup_restore_restore_button"
|
||||
const val REMOTE_BACKUP_RESTORE_CANCEL_BUTTON = "remote_backup_restore_cancel_button"
|
||||
}
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.accountlocked
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for AccountLockedScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class AccountLockedScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays screen and next button`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
AccountLockedScreen(
|
||||
state = AccountLockedState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.ACCOUNT_LOCKED_SCREEN).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.ACCOUNT_LOCKED_NEXT_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Next is clicked, Next event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: AccountLockedScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
AccountLockedScreen(
|
||||
state = AccountLockedState(),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.ACCOUNT_LOCKED_NEXT_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == AccountLockedScreenEvents.Next)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Learn More is clicked, LearnMore event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: AccountLockedScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
AccountLockedScreen(
|
||||
state = AccountLockedState(),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.ACCOUNT_LOCKED_LEARN_MORE_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == AccountLockedScreenEvents.LearnMore)
|
||||
}
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.aepentry
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsNotEnabled
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for EnterAepScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class EnterAepScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays screen, input, and next button`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
EnterAepScreen(
|
||||
state = EnterAepState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_AEP_SCREEN).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_AEP_INPUT).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_AEP_NEXT_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when No Recovery Key is clicked, Cancel event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: EnterAepEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
EnterAepScreen(
|
||||
state = EnterAepState(),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_AEP_NO_KEY_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == EnterAepEvents.Cancel)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Next button is disabled when backup key is not valid`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
EnterAepScreen(
|
||||
state = EnterAepState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_AEP_NEXT_BUTTON).assertIsNotEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Next is clicked and backup key is valid, Submit event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: EnterAepEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
EnterAepScreen(
|
||||
state = EnterAepState(
|
||||
isBackupKeyValid = true,
|
||||
aepValidationError = null,
|
||||
isRegistering = false
|
||||
),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_AEP_NEXT_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == EnterAepEvents.Submit)
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.allownotifications
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.screens.util.MockPermissionsState
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for AllowNotificationsScreen that validate its callbacks.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class AllowNotificationsScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Test
|
||||
fun `screen displays buttons`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
AllowNotificationsScreen(
|
||||
permissionState = MockPermissionsState(permission = Manifest.permission.POST_NOTIFICATIONS),
|
||||
onProceed = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ALLOW_NOTIFICATIONS_SCREEN).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.ALLOW_NOTIFICATIONS_NEXT_BUTTON).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.ALLOW_NOTIFICATIONS_NOT_NOW_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Test
|
||||
fun `when Not Now is clicked, onProceed is invoked`() {
|
||||
var proceeded = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
AllowNotificationsScreen(
|
||||
permissionState = MockPermissionsState(permission = Manifest.permission.POST_NOTIFICATIONS),
|
||||
onProceed = { proceeded = true }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ALLOW_NOTIFICATIONS_NOT_NOW_BUTTON).performClick()
|
||||
|
||||
assert(proceeded)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Test
|
||||
fun `when Next is clicked with granted permission, onProceed is invoked`() {
|
||||
var proceeded = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
AllowNotificationsScreen(
|
||||
permissionState = MockPermissionsState(permission = Manifest.permission.POST_NOTIFICATIONS),
|
||||
onProceed = { proceeded = true }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ALLOW_NOTIFICATIONS_NEXT_BUTTON).performClick()
|
||||
|
||||
assert(proceeded)
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.captcha
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for CaptchaScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class CaptchaScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays cancel button`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
CaptchaScreen(
|
||||
state = CaptchaState(captchaUrl = "https://example.com"),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.CAPTCHA_CANCEL_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Cancel is clicked, Cancel event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: CaptchaScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
CaptchaScreen(
|
||||
state = CaptchaState(captchaUrl = "https://example.com"),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.CAPTCHA_CANCEL_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == CaptchaScreenEvents.Cancel)
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.countrycode
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for CountryCodePickerScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class CountryCodePickerScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays search field`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
CountryCodePickerScreen(
|
||||
state = CountryCodeState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.COUNTRY_CODE_SEARCH_FIELD).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when close button is clicked, Dismissed event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: CountryCodePickerScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
CountryCodePickerScreen(
|
||||
state = CountryCodeState(),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.COUNTRY_CODE_CLOSE_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == CountryCodePickerScreenEvents.Dismissed)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when typing in search field, Search event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: CountryCodePickerScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
CountryCodePickerScreen(
|
||||
state = CountryCodeState(),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.COUNTRY_CODE_SEARCH_FIELD).performTextInput("US")
|
||||
|
||||
// Then
|
||||
assert(emittedEvent is CountryCodePickerScreenEvents.Search)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when a country is selected, CountrySelected event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: CountryCodePickerScreenEvents? = null
|
||||
val country = Country("🇺🇸", "United States", 1, "US")
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
CountryCodePickerScreen(
|
||||
state = CountryCodeState(
|
||||
countryList = listOf(country),
|
||||
filteredList = listOf(country)
|
||||
),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithText("United States").performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent is CountryCodePickerScreenEvents.CountrySelected)
|
||||
}
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.createprofile
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsEnabled
|
||||
import androidx.compose.ui.test.assertIsNotEnabled
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for CreateProfileScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class CreateProfileScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays given name and family name fields`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
CreateProfileScreen(
|
||||
state = CreateProfileState(isLoading = false),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.CREATE_PROFILE_GIVEN_NAME_FIELD).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.CREATE_PROFILE_FAMILY_NAME_FIELD).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when typing in given name field, GivenNameChanged event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: CreateProfileScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
CreateProfileScreen(
|
||||
state = CreateProfileState(isLoading = false),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.CREATE_PROFILE_GIVEN_NAME_FIELD).performTextInput("Alice")
|
||||
|
||||
// Then
|
||||
assert(emittedEvent is CreateProfileScreenEvents.GivenNameChanged)
|
||||
}
|
||||
|
||||
@Config(qualifiers = "w360dp-h1200dp")
|
||||
@Test
|
||||
fun `when who can find me row is clicked, WhoCanFindMeClicked event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: CreateProfileScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
CreateProfileScreen(
|
||||
state = CreateProfileState(isLoading = false),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.CREATE_PROFILE_WHO_CAN_FIND_ME_ROW).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == CreateProfileScreenEvents.WhoCanFindMeClicked)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when given name is blank, Next button is disabled`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
CreateProfileScreen(
|
||||
state = CreateProfileState(isLoading = false),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.CREATE_PROFILE_NEXT_BUTTON).assertIsNotEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when given name is present, Next button is enabled and emits NextClicked`() {
|
||||
// Given
|
||||
var emittedEvent: CreateProfileScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
CreateProfileScreen(
|
||||
state = CreateProfileState(givenName = "Alice", isLoading = false),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.CREATE_PROFILE_NEXT_BUTTON).assertIsEnabled().performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == CreateProfileScreenEvents.NextClicked)
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.devicetransfer.complete
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for DeviceTransferCompleteScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class DeviceTransferCompleteScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays continue button`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferCompleteScreen(
|
||||
state = DeviceTransferCompleteState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_COMPLETE_CONTINUE_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Continue is clicked, ContinueClicked event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: DeviceTransferCompleteScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferCompleteScreen(
|
||||
state = DeviceTransferCompleteState(),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_COMPLETE_CONTINUE_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == DeviceTransferCompleteScreenEvents.ContinueClicked)
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.devicetransfer.instructions
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for DeviceTransferInstructionsScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class DeviceTransferInstructionsScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays continue button`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferInstructionsScreen(
|
||||
state = DeviceTransferInstructionsState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_INSTRUCTIONS_CONTINUE_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Continue is clicked, ContinueClicked event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: DeviceTransferInstructionsScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferInstructionsScreen(
|
||||
state = DeviceTransferInstructionsState(),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_INSTRUCTIONS_CONTINUE_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == DeviceTransferInstructionsScreenEvents.ContinueClicked)
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.devicetransfer.progress
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for DeviceTransferProgressScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class DeviceTransferProgressScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `default state displays cancel button`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferProgressScreen(
|
||||
state = DeviceTransferProgressState(),
|
||||
showCancelDialog = false,
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_PROGRESS_CANCEL_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Cancel is clicked, CancelClicked event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: DeviceTransferProgressScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferProgressScreen(
|
||||
state = DeviceTransferProgressState(),
|
||||
showCancelDialog = false,
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_PROGRESS_CANCEL_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == DeviceTransferProgressScreenEvents.CancelClicked)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `failed state displays try again button`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferProgressScreen(
|
||||
state = DeviceTransferProgressState(status = DeviceTransferProgressState.Status.FAILED),
|
||||
showCancelDialog = false,
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_PROGRESS_TRY_AGAIN_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Try Again is clicked, TryAgainClicked event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: DeviceTransferProgressScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferProgressScreen(
|
||||
state = DeviceTransferProgressState(status = DeviceTransferProgressState.Status.FAILED),
|
||||
showCancelDialog = false,
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_PROGRESS_TRY_AGAIN_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == DeviceTransferProgressScreenEvents.TryAgainClicked)
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.devicetransfer.setup
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for DeviceTransferSetupScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class DeviceTransferSetupScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `verify step displays match and do not match buttons`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferSetupScreen(
|
||||
state = DeviceTransferSetupState(step = SetupStep.VERIFY, authenticationCode = 1234567),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_SETUP_NUMBERS_MATCH_BUTTON).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_SETUP_NUMBERS_DO_NOT_MATCH_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when numbers match is clicked, UserVerifiedCode event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: DeviceTransferSetupScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferSetupScreen(
|
||||
state = DeviceTransferSetupState(step = SetupStep.VERIFY, authenticationCode = 1234567),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_SETUP_NUMBERS_MATCH_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == DeviceTransferSetupScreenEvents.UserVerifiedCode)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when numbers do not match is clicked, UserRejectedCode event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: DeviceTransferSetupScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferSetupScreen(
|
||||
state = DeviceTransferSetupState(step = SetupStep.VERIFY, authenticationCode = 1234567),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_SETUP_NUMBERS_DO_NOT_MATCH_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == DeviceTransferSetupScreenEvents.UserRejectedCode)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `troubleshooting step displays retry button`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferSetupScreen(
|
||||
state = DeviceTransferSetupState(step = SetupStep.TROUBLESHOOTING),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_SETUP_TROUBLESHOOTING_RETRY_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when troubleshooting retry is clicked, RetryClicked event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: DeviceTransferSetupScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
DeviceTransferSetupScreen(
|
||||
state = DeviceTransferSetupState(step = SetupStep.TROUBLESHOOTING),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.DEVICE_TRANSFER_SETUP_TROUBLESHOOTING_RETRY_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == DeviceTransferSetupScreenEvents.RetryClicked)
|
||||
}
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.discoverability
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for PhoneNumberDiscoverabilityScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class PhoneNumberDiscoverabilityScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays everyone and nobody options and save button`() {
|
||||
// Given
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PhoneNumberDiscoverabilityScreen(
|
||||
state = PhoneNumberDiscoverabilityState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Then
|
||||
composeTestRule.onNodeWithTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_EVERYONE_OPTION).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_NOBODY_OPTION).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_SAVE_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when nobody option is clicked, NobodySelected event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: PhoneNumberDiscoverabilityScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PhoneNumberDiscoverabilityScreen(
|
||||
state = PhoneNumberDiscoverabilityState(),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_NOBODY_OPTION).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == PhoneNumberDiscoverabilityScreenEvents.NobodySelected)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when everyone option is clicked, EveryoneSelected event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: PhoneNumberDiscoverabilityScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PhoneNumberDiscoverabilityScreen(
|
||||
state = PhoneNumberDiscoverabilityState(discoverable = false),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_EVERYONE_OPTION).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == PhoneNumberDiscoverabilityScreenEvents.EveryoneSelected)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when save button is clicked, SaveClicked event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: PhoneNumberDiscoverabilityScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PhoneNumberDiscoverabilityScreen(
|
||||
state = PhoneNumberDiscoverabilityState(),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_SAVE_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == PhoneNumberDiscoverabilityScreenEvents.SaveClicked)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when back button is clicked, BackClicked event is emitted`() {
|
||||
// Given
|
||||
var emittedEvent: PhoneNumberDiscoverabilityScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PhoneNumberDiscoverabilityScreen(
|
||||
state = PhoneNumberDiscoverabilityState(),
|
||||
onEvent = { event ->
|
||||
emittedEvent = event
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// When
|
||||
composeTestRule.onNodeWithTag(TestTags.PHONE_NUMBER_DISCOVERABILITY_BACK_BUTTON).performClick()
|
||||
|
||||
// Then
|
||||
assert(emittedEvent == PhoneNumberDiscoverabilityScreenEvents.BackClicked)
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.localbackuprestore
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsEnabled
|
||||
import androidx.compose.ui.test.assertIsNotEnabled
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for EnterLocalBackupV1PassphaseScreen that validate callback invocations.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class EnterLocalBackupV1PassphaseScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays input and next button`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
EnterLocalBackupV1PassphaseScreen(
|
||||
onSubmit = {},
|
||||
onCancel = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_INPUT).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_NEXT_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when No passphrase is clicked, onCancel is invoked`() {
|
||||
var cancelled = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
EnterLocalBackupV1PassphaseScreen(
|
||||
onSubmit = {},
|
||||
onCancel = { cancelled = true }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_NO_PASSPHRASE_BUTTON).performClick()
|
||||
|
||||
assert(cancelled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `next is disabled initially`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
EnterLocalBackupV1PassphaseScreen(
|
||||
onSubmit = {},
|
||||
onCancel = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_NEXT_BUTTON).assertIsNotEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when a 30 digit passphrase is entered, next is enabled and clicking it submits`() {
|
||||
val passphrase = "012345678901234567890123456789"
|
||||
var submitted: String? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
EnterLocalBackupV1PassphaseScreen(
|
||||
onSubmit = { submitted = it },
|
||||
onCancel = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_INPUT).performTextInput(passphrase)
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_NEXT_BUTTON).assertIsEnabled()
|
||||
composeTestRule.onNodeWithTag(TestTags.ENTER_LOCAL_BACKUP_PASSPHRASE_NEXT_BUTTON).performClick()
|
||||
|
||||
assert(submitted == passphrase)
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.localbackuprestore
|
||||
|
||||
import android.app.Application
|
||||
import android.net.Uri
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class LocalBackupRestoreScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `SelectFolder phase displays screen and select folder button`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
LocalBackupRestoreScreen(
|
||||
state = LocalBackupRestoreState(restorePhase = LocalBackupRestoreState.RestorePhase.SelectFolder),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.LOCAL_BACKUP_RESTORE_SCREEN).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.LOCAL_BACKUP_RESTORE_SELECT_FOLDER_BUTTON).performScrollTo().assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when select folder button is clicked, PickBackupFolder is emitted`() {
|
||||
var emittedEvent: LocalBackupRestoreEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
LocalBackupRestoreScreen(
|
||||
state = LocalBackupRestoreState(restorePhase = LocalBackupRestoreState.RestorePhase.SelectFolder),
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.LOCAL_BACKUP_RESTORE_SELECT_FOLDER_BUTTON).performScrollTo().performClick()
|
||||
|
||||
assert(emittedEvent == LocalBackupRestoreEvents.PickBackupFolder)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `BackupFound phase displays restore button and clicking it emits RestoreBackup`() {
|
||||
var emittedEvent: LocalBackupRestoreEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
LocalBackupRestoreScreen(
|
||||
state = LocalBackupRestoreState(
|
||||
restorePhase = LocalBackupRestoreState.RestorePhase.BackupFound,
|
||||
backupInfo = LocalBackupInfo(
|
||||
type = LocalBackupInfo.BackupType.V2,
|
||||
date = LocalDateTime.of(2026, 3, 15, 14, 30, 0),
|
||||
name = "signal-backup-2026-03-15-14-30-00",
|
||||
uri = Uri.EMPTY,
|
||||
sizeBytes = 1_482_184_499
|
||||
)
|
||||
),
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.LOCAL_BACKUP_RESTORE_RESTORE_BUTTON).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.LOCAL_BACKUP_RESTORE_RESTORE_BUTTON).performClick()
|
||||
|
||||
assert(emittedEvent == LocalBackupRestoreEvents.RestoreBackup)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `InProgress phase displays progress bar`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
LocalBackupRestoreScreen(
|
||||
state = LocalBackupRestoreState(
|
||||
restorePhase = LocalBackupRestoreState.RestorePhase.InProgress,
|
||||
progressFraction = 0.5f
|
||||
),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.LOCAL_BACKUP_RESTORE_PROGRESS_BAR).performScrollTo().assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.messagesync
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsNotEnabled
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.core.util.kibiBytes
|
||||
import org.signal.core.util.mebiBytes
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for MessageSyncScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class MessageSyncScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays cancel button`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
MessageSyncScreen(
|
||||
state = MessageSyncScreenState(downloadedBytes = 1.mebiBytes, totalBytes = 3300.kibiBytes),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.MESSAGE_SYNC_SCREEN).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.MESSAGE_SYNC_CANCEL_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Cancel is clicked, CancelClick event is emitted`() {
|
||||
var emittedEvent: MessageSyncScreenEvent? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
MessageSyncScreen(
|
||||
state = MessageSyncScreenState(downloadedBytes = 1.mebiBytes, totalBytes = 3300.kibiBytes),
|
||||
onEvent = { event -> emittedEvent = event }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.MESSAGE_SYNC_CANCEL_BUTTON).performClick()
|
||||
|
||||
assert(emittedEvent == MessageSyncScreenEvent.CancelClick)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `learn more link is displayed`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
MessageSyncScreen(
|
||||
state = MessageSyncScreenState(downloadedBytes = 1.mebiBytes, totalBytes = 3300.kibiBytes),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.MESSAGE_SYNC_LEARN_MORE_LINK).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when finishing, Cancel button is disabled`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
MessageSyncScreen(
|
||||
state = MessageSyncScreenState(isFinishing = true),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.MESSAGE_SYNC_CANCEL_BUTTON).assertIsNotEnabled()
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalPermissionsApi::class)
|
||||
|
||||
package org.signal.registration.screens.permissions
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.screens.util.MockMultiplePermissionsState
|
||||
import org.signal.registration.screens.util.MockPermissionsState
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for PermissionsScreen that validate its callbacks.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class PermissionsScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays buttons`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PermissionsScreen(
|
||||
permissionsState = MockMultiplePermissionsState(
|
||||
permissions = listOf(
|
||||
MockPermissionsState(Manifest.permission.POST_NOTIFICATIONS),
|
||||
MockPermissionsState(Manifest.permission.READ_CONTACTS)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PERMISSIONS_SCREEN).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.PERMISSIONS_NEXT_BUTTON).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.PERMISSIONS_NOT_NOW_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Not Now is clicked, onProceed is invoked`() {
|
||||
var proceeded = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PermissionsScreen(
|
||||
permissionsState = MockMultiplePermissionsState(
|
||||
permissions = listOf(
|
||||
MockPermissionsState(Manifest.permission.POST_NOTIFICATIONS),
|
||||
MockPermissionsState(Manifest.permission.READ_CONTACTS)
|
||||
)
|
||||
),
|
||||
onProceed = { proceeded = true }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PERMISSIONS_NOT_NOW_BUTTON).performClick()
|
||||
|
||||
assert(proceeded)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Next is clicked with all permissions granted, onProceed is invoked`() {
|
||||
var proceeded = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PermissionsScreen(
|
||||
permissionsState = MockMultiplePermissionsState(
|
||||
allPermissionsGranted = true,
|
||||
permissions = listOf(
|
||||
MockPermissionsState(Manifest.permission.POST_NOTIFICATIONS),
|
||||
MockPermissionsState(Manifest.permission.READ_CONTACTS)
|
||||
)
|
||||
),
|
||||
onProceed = { proceeded = true }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PERMISSIONS_NEXT_BUTTON).performClick()
|
||||
|
||||
assert(proceeded)
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.pincreation
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsNotEnabled
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for PinCreationScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class PinCreationScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays input and next button`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PinCreationScreen(
|
||||
state = PinCreationState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_CREATION_INPUT).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_CREATION_NEXT_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when toggle keyboard is clicked, ToggleKeyboard event is emitted`() {
|
||||
var emittedEvent: PinCreationScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PinCreationScreen(
|
||||
state = PinCreationState(),
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_CREATION_TOGGLE_KEYBOARD_BUTTON).performClick()
|
||||
|
||||
assert(emittedEvent == PinCreationScreenEvents.ToggleKeyboard)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `next is disabled when pin is empty`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PinCreationScreen(
|
||||
state = PinCreationState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_CREATION_NEXT_BUTTON).assertIsNotEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when a pin is entered and next is clicked, PinSubmitted event is emitted`() {
|
||||
var emittedEvent: PinCreationScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PinCreationScreen(
|
||||
state = PinCreationState(),
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_CREATION_INPUT).performTextInput("1234")
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_CREATION_NEXT_BUTTON).performClick()
|
||||
|
||||
assert(emittedEvent is PinCreationScreenEvents.PinSubmitted)
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.pinentry
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsNotEnabled
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
/**
|
||||
* Tests for PinEntryScreen that validate event emissions.
|
||||
* Uses Robolectric to run fast JUnit tests without an emulator.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class PinEntryScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays input and continue button`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PinEntryScreen(
|
||||
state = PinEntryState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_ENTRY_INPUT).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_ENTRY_CONTINUE_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when toggle keyboard is clicked, ToggleKeyboard event is emitted`() {
|
||||
var emittedEvent: PinEntryScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PinEntryScreen(
|
||||
state = PinEntryState(),
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_ENTRY_TOGGLE_KEYBOARD_BUTTON).performClick()
|
||||
|
||||
assert(emittedEvent == PinEntryScreenEvents.ToggleKeyboard)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `continue is disabled when pin is empty`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PinEntryScreen(
|
||||
state = PinEntryState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_ENTRY_CONTINUE_BUTTON).assertIsNotEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when a pin is entered and continue is clicked, PinEntered event is emitted`() {
|
||||
var emittedEvent: PinEntryScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PinEntryScreen(
|
||||
state = PinEntryState(),
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_ENTRY_INPUT).performTextInput("1234")
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_ENTRY_CONTINUE_BUTTON).performClick()
|
||||
|
||||
assert(emittedEvent is PinEntryScreenEvents.PinEntered)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `skip button is displayed in SvrRestore mode`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PinEntryScreen(
|
||||
state = PinEntryState(),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_ENTRY_SKIP_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when skip is confirmed in the dialog, Skip event is emitted`() {
|
||||
var emittedEvent: PinEntryScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
PinEntryScreen(
|
||||
state = PinEntryState(),
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.PIN_ENTRY_SKIP_BUTTON).performClick()
|
||||
composeTestRule.onNodeWithText("Create New PIN").performClick()
|
||||
|
||||
assert(emittedEvent == PinEntryScreenEvents.Skip)
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.quickrestore
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class QuickRestoreQrScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
@Test
|
||||
fun `screen displays cancel button`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
QuickRestoreQrScreen(
|
||||
state = QuickRestoreQrState(qrState = QrState.Loading),
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.QUICK_RESTORE_QR_CANCEL_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Cancel is clicked, Cancel event is emitted`() {
|
||||
var emittedEvent: QuickRestoreQrEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
QuickRestoreQrScreen(
|
||||
state = QuickRestoreQrState(qrState = QrState.Loading),
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.QUICK_RESTORE_QR_CANCEL_BUTTON).performClick()
|
||||
|
||||
assert(emittedEvent == QuickRestoreQrEvents.Cancel)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when qr state is Failed, Retry button is displayed and clicking it emits RetryQrCode`() {
|
||||
var emittedEvent: QuickRestoreQrEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
QuickRestoreQrScreen(
|
||||
state = QuickRestoreQrState(qrState = QrState.Failed),
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.QUICK_RESTORE_QR_RETRY_BUTTON).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.QUICK_RESTORE_QR_RETRY_BUTTON).performClick()
|
||||
|
||||
assert(emittedEvent == QuickRestoreQrEvents.RetryQrCode)
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.remotebackuprestore
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.models.AccountEntropyPool
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class RemoteBackupRestoreScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
private val loadedState = RemoteBackupRestoreState(
|
||||
aep = AccountEntropyPool("0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
loadState = RemoteBackupRestoreState.LoadState.Loaded,
|
||||
backupTime = System.currentTimeMillis(),
|
||||
backupSize = 1234567
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `screen displays restore and cancel buttons`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
RemoteRestoreScreen(
|
||||
state = loadedState,
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.REMOTE_BACKUP_RESTORE_RESTORE_BUTTON).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.REMOTE_BACKUP_RESTORE_CANCEL_BUTTON).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Restore is clicked, BackupRestoreBackup event is emitted`() {
|
||||
var emittedEvent: RemoteBackupRestoreScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
RemoteRestoreScreen(
|
||||
state = loadedState,
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.REMOTE_BACKUP_RESTORE_RESTORE_BUTTON).performClick()
|
||||
|
||||
assert(emittedEvent == RemoteBackupRestoreScreenEvents.BackupRestoreBackup)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Cancel is clicked, Cancel event is emitted`() {
|
||||
var emittedEvent: RemoteBackupRestoreScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
RemoteRestoreScreen(
|
||||
state = loadedState,
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.REMOTE_BACKUP_RESTORE_CANCEL_BUTTON).performClick()
|
||||
|
||||
assert(emittedEvent == RemoteBackupRestoreScreenEvents.Cancel)
|
||||
}
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.signal.registration.screens.restoreselection
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.signal.core.ui.CoreUiDependenciesRule
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.registration.test.TestTags
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(application = Application::class)
|
||||
class ArchiveRestoreSelectionScreenTest {
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@get:Rule
|
||||
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
|
||||
|
||||
private val allOptionsState = ArchiveRestoreSelectionState(
|
||||
restoreOptions = listOf(
|
||||
ArchiveRestoreOption.SignalSecureBackup,
|
||||
ArchiveRestoreOption.LocalBackup,
|
||||
ArchiveRestoreOption.DeviceTransfer,
|
||||
ArchiveRestoreOption.None
|
||||
)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `screen displays all option cards`() {
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
ArchiveRestoreSelectionScreen(
|
||||
state = allOptionsState,
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ARCHIVE_RESTORE_SELECTION_SCREEN).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.ARCHIVE_RESTORE_SELECTION_FROM_SIGNAL_BACKUPS).performScrollTo().assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.ARCHIVE_RESTORE_SELECTION_FROM_BACKUP_FOLDER).performScrollTo().assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.ARCHIVE_RESTORE_SELECTION_DEVICE_TRANSFER).performScrollTo().assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag(TestTags.ARCHIVE_RESTORE_SELECTION_NONE).performScrollTo().assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Signal Backups card is clicked, RestoreOptionSelected SignalSecureBackup is emitted`() {
|
||||
var emittedEvent: ArchiveRestoreSelectionScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
ArchiveRestoreSelectionScreen(
|
||||
state = allOptionsState,
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ARCHIVE_RESTORE_SELECTION_FROM_SIGNAL_BACKUPS).performScrollTo().performClick()
|
||||
|
||||
assert(emittedEvent == ArchiveRestoreSelectionScreenEvents.RestoreOptionSelected(ArchiveRestoreOption.SignalSecureBackup))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Device Transfer card is clicked, RestoreOptionSelected DeviceTransfer is emitted`() {
|
||||
var emittedEvent: ArchiveRestoreSelectionScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
ArchiveRestoreSelectionScreen(
|
||||
state = allOptionsState,
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ARCHIVE_RESTORE_SELECTION_DEVICE_TRANSFER).performScrollTo().performClick()
|
||||
|
||||
assert(emittedEvent == ArchiveRestoreSelectionScreenEvents.RestoreOptionSelected(ArchiveRestoreOption.DeviceTransfer))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when Backup Folder card is clicked, RestoreOptionSelected LocalBackup is emitted`() {
|
||||
var emittedEvent: ArchiveRestoreSelectionScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
ArchiveRestoreSelectionScreen(
|
||||
state = allOptionsState,
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ARCHIVE_RESTORE_SELECTION_FROM_BACKUP_FOLDER).performScrollTo().performClick()
|
||||
|
||||
assert(emittedEvent == ArchiveRestoreSelectionScreenEvents.RestoreOptionSelected(ArchiveRestoreOption.LocalBackup))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when None card is clicked, RestoreOptionSelected None is emitted`() {
|
||||
var emittedEvent: ArchiveRestoreSelectionScreenEvents? = null
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignalTheme {
|
||||
ArchiveRestoreSelectionScreen(
|
||||
state = allOptionsState,
|
||||
onEvent = { emittedEvent = it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag(TestTags.ARCHIVE_RESTORE_SELECTION_NONE).performScrollTo().performClick()
|
||||
|
||||
assert(emittedEvent == ArchiveRestoreSelectionScreenEvents.RestoreOptionSelected(ArchiveRestoreOption.None))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user