Complete Android adaptive and accessibility hardening (#105)
This commit is contained in:
1 parent
f4a6edbc68
commit
45d78aa5b3
33 files changed
+4596
-1376
No files matched your search
+6
@@ -6,6 +6,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.test.assertIsEnabled
|
||||
import androidx.compose.ui.test.assertIsNotEnabled
|
||||
import androidx.compose.ui.test.junit4.accessibility.enableAccessibilityChecks
|
||||
import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
@@ -14,11 +15,16 @@ import de.rfc1437.ironstorage.core.CredentialCandidate
|
||||
import de.rfc1437.ironstorage.core.ProviderRequest
|
||||
import de.rfc1437.ironstorage.features.CredentialSelectionScreen
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class CredentialSelectionScreenTest {
|
||||
@get:Rule val compose = createAndroidComposeRule<MainActivity>()
|
||||
|
||||
@Before fun enableChecks() {
|
||||
compose.enableAccessibilityChecks()
|
||||
}
|
||||
private var selected by mutableStateOf<String?>(null)
|
||||
private var destination by mutableStateOf("")
|
||||
private var consent by mutableStateOf(false)
|
||||
|
||||
@@ -2,8 +2,12 @@ package de.rfc1437.ironstorage
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcel
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.adaptive.HingeInfo
|
||||
import androidx.compose.material3.adaptive.Posture
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.input.InputMode
|
||||
import androidx.compose.ui.input.InputModeManager
|
||||
import androidx.compose.ui.input.key.Key
|
||||
@@ -20,10 +24,13 @@ import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performKeyInput
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.performScrollToNode
|
||||
import androidx.compose.ui.test.performSemanticsAction
|
||||
import androidx.compose.ui.test.performTextReplacement
|
||||
import androidx.compose.ui.test.performTouchInput
|
||||
import androidx.compose.ui.test.pressKey
|
||||
import androidx.compose.ui.test.swipeUp
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import de.rfc1437.ironstorage.core.AuthenticationRepository
|
||||
@@ -35,6 +42,7 @@ import de.rfc1437.ironstorage.core.EditorState
|
||||
import de.rfc1437.ironstorage.core.ProtectedPresentation
|
||||
import de.rfc1437.ironstorage.features.EditorDiscardDialog
|
||||
import de.rfc1437.ironstorage.features.EntryEditorScreen
|
||||
import de.rfc1437.ironstorage.features.HingeSafeLayout
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
@@ -50,6 +58,55 @@ class EntryEditorScreenTest {
|
||||
compose.enableAccessibilityChecks()
|
||||
}
|
||||
|
||||
@Test fun tabletopGeneratorKeepsEveryControlReachableAtLargeFont() {
|
||||
val repository = Fixture()
|
||||
val authentication = object : AuthenticationRepository by compose.activity.authentication {
|
||||
override val state = MutableStateFlow(AuthenticationState(unlocked = true))
|
||||
}
|
||||
compose.activity.runOnUiThread {
|
||||
compose.activity.setProtectedTestContent {
|
||||
BoxWithConstraints {
|
||||
val density = LocalDensity.current
|
||||
val width = with(density) { maxWidth.toPx() }
|
||||
val height = with(density) { maxHeight.toPx() }
|
||||
CompositionLocalProvider(LocalDensity provides Density(density.density, 2f)) {
|
||||
MaterialTheme {
|
||||
HingeSafeLayout(
|
||||
Posture(
|
||||
true,
|
||||
listOf(
|
||||
HingeInfo(
|
||||
Rect(
|
||||
0f,
|
||||
height * .5f,
|
||||
width,
|
||||
height * .5f + 12f
|
||||
),
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
)
|
||||
)
|
||||
)
|
||||
) { EntryEditorScreen(repository, authentication) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
compose.onNodeWithTag("entry-editor")
|
||||
.performScrollToNode(hasText("Generate password"))
|
||||
compose.onNodeWithText("Generate password").performClick()
|
||||
compose.onNodeWithText("Password length").performScrollTo().performTextReplacement("24")
|
||||
compose.onNodeWithTag("hinge-dialog-content").performTouchInput { swipeUp() }
|
||||
compose.onNodeWithText("Use letters and numbers only").performScrollTo()
|
||||
compose.onNodeWithText("Use letters and numbers only").assertIsDisplayed()
|
||||
compose.onNodeWithText("Generate replacement").performScrollTo().performClick()
|
||||
assertEquals(1, repository.generations)
|
||||
assertEquals(24u, repository.length)
|
||||
}
|
||||
|
||||
@Test fun structuredInputsGenerationAndAccessibleReorderForwardTypedIds() {
|
||||
val repository = Fixture()
|
||||
val lease = MutableStateFlow(AuthenticationState(unlocked = true))
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package de.rfc1437.ironstorage
|
||||
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.adaptive.HingeInfo
|
||||
import androidx.compose.material3.adaptive.Posture
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertTextContains
|
||||
import androidx.compose.ui.test.getUnclippedBoundsInRoot
|
||||
import androidx.compose.ui.test.junit4.accessibility.enableAccessibilityChecks
|
||||
import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import de.rfc1437.ironstorage.core.HomeActionKind
|
||||
import de.rfc1437.ironstorage.features.HingeSafeLayout
|
||||
import de.rfc1437.ironstorage.features.HomeScreen
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class HingeWindowTest {
|
||||
@get:Rule val compose = createAndroidComposeRule<MainActivity>()
|
||||
|
||||
@Test fun livePostureChangesKeepContentAndProtectedDialogOutsideTheHinge() {
|
||||
compose.enableAccessibilityChecks()
|
||||
val repository = HomeScreenTest.Fixture()
|
||||
var mode by mutableStateOf(0)
|
||||
var hinge = Rect.Zero
|
||||
var density = 1f
|
||||
compose.activity.runOnUiThread {
|
||||
compose.activity.setProtectedTestContent {
|
||||
BoxWithConstraints(Modifier.fillMaxSize()) {
|
||||
density = LocalDensity.current.density
|
||||
val width = maxWidth.value * density
|
||||
val height = maxHeight.value * density
|
||||
hinge = if (mode == 1) {
|
||||
Rect(width * .35f, 0f, width * .35f + 12f, height)
|
||||
} else {
|
||||
Rect(0f, height * .5f, width, height * .5f + 12f)
|
||||
}
|
||||
val posture = Posture(
|
||||
isTabletop = mode == 2,
|
||||
hingeList = if (mode == 0) {
|
||||
emptyList()
|
||||
} else {
|
||||
listOf(
|
||||
HingeInfo(hinge, false, mode == 1, true, true)
|
||||
)
|
||||
}
|
||||
)
|
||||
MaterialTheme {
|
||||
HingeSafeLayout(posture) { HomeScreen(repository) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
compose.onAllNodesWithText("Commit")[0].performScrollTo().performClick()
|
||||
compose.onNodeWithText("Commit message").performTextInput("Public posture fixture")
|
||||
for (posture in listOf(1, 2, 0)) {
|
||||
compose.runOnIdle { mode = posture }
|
||||
if (posture != 0) {
|
||||
compose.onNodeWithText("Create commit").performScrollTo()
|
||||
}
|
||||
val action = compose.onNodeWithText("Create commit")
|
||||
action.assertIsDisplayed()
|
||||
if (posture != 0) {
|
||||
val bounds = action.getUnclippedBoundsInRoot()
|
||||
val pixels = Rect(
|
||||
bounds.left.value * density,
|
||||
bounds.top.value * density,
|
||||
bounds.right.value * density,
|
||||
bounds.bottom.value * density
|
||||
)
|
||||
assertTrue("Dialog action must avoid the hinge", !pixels.overlaps(hinge))
|
||||
if (posture == 2) assertTrue(pixels.bottom <= hinge.top)
|
||||
compose.onNodeWithText("Public posture fixture").performScrollTo()
|
||||
}
|
||||
compose.onNodeWithText("Public posture fixture")
|
||||
.assertTextContains("Public posture fixture")
|
||||
}
|
||||
compose.onNodeWithText("Create commit").performClick()
|
||||
assertEquals(
|
||||
HomeActionKind.Commit to "Public posture fixture",
|
||||
repository.requests.single()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import androidx.compose.ui.test.junit4.accessibility.enableAccessibilityChecks
|
||||
import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.onRoot
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.performScrollToNode
|
||||
@@ -93,12 +92,12 @@ class HomeScreenTest {
|
||||
@Test fun swipeRefreshRequestsTheRustRefreshWorkflow() {
|
||||
val repository = Fixture()
|
||||
show(repository)
|
||||
compose.onRoot().performTouchInput { swipeDown() }
|
||||
compose.onNode(hasScrollAction()).performTouchInput { swipeDown() }
|
||||
compose.waitUntil(5000) { repository.refreshes == 1 }
|
||||
assertTrue(repository.requests.isEmpty())
|
||||
compose.onNodeWithText("Cancel").performClick()
|
||||
}
|
||||
private class Fixture(changes: Int = 1) : HomeRepository {
|
||||
internal class Fixture(changes: Int = 1) : HomeRepository {
|
||||
private val actions = HomeActionKind.entries.map {
|
||||
HomeAction(
|
||||
it,
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.compose.ui.test.assertIsNotEnabled
|
||||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
import androidx.compose.ui.test.hasTestTag
|
||||
import androidx.compose.ui.test.hasText
|
||||
import androidx.compose.ui.test.junit4.accessibility.enableAccessibilityChecks
|
||||
import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
@@ -23,6 +24,7 @@ import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollToNode
|
||||
import androidx.compose.ui.test.performTouchInput
|
||||
import androidx.compose.ui.test.swipeLeft
|
||||
import androidx.compose.ui.test.swipeRight
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import de.rfc1437.ironstorage.core.AuthenticationState
|
||||
import de.rfc1437.ironstorage.core.PasswordDestination
|
||||
@@ -38,12 +40,17 @@ import java.util.concurrent.TimeUnit
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Assume.assumeTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
class MutationWorkflowTest {
|
||||
@get:Rule val compose = createAndroidComposeRule<MainActivity>()
|
||||
|
||||
@Before fun enableChecks() {
|
||||
compose.enableAccessibilityChecks()
|
||||
}
|
||||
private fun display(fixture: Fixture) {
|
||||
compose.activity.runOnUiThread {
|
||||
compose.activity.setProtectedTestContent {
|
||||
@@ -55,7 +62,10 @@ class MutationWorkflowTest {
|
||||
@Test fun fullSwipeOnlySelectsDeleteAndCancelNeverMutates() {
|
||||
val fixture = Fixture()
|
||||
display(fixture)
|
||||
compose.onNodeWithText("Source").performTouchInput { swipeLeft() }
|
||||
val rtl = InstrumentationRegistry.getArguments().getString("hardeningRtl") == "true"
|
||||
compose.onNodeWithText("Source").performTouchInput {
|
||||
if (rtl) swipeRight() else swipeLeft()
|
||||
}
|
||||
compose.waitUntil(5000) { fixture.state.value.mutation != null }
|
||||
assertEquals(PasswordMutation.Delete, fixture.state.value.mutation!!.action)
|
||||
assertEquals(0, fixture.committed)
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.platform.InterceptPlatformTextInput
|
||||
import androidx.compose.ui.test.ExperimentalTestApi
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
@@ -49,6 +50,43 @@ class PresentationSecurityTest {
|
||||
compose.enableAccessibilityChecks()
|
||||
}
|
||||
|
||||
@Test fun foregroundCleanupUnmasksOnlyAfterTheCleanGenerationIsComposed() {
|
||||
val presentation = de.rfc1437.ironstorage.core.ProtectedPresentation()
|
||||
val dirty = mutableStateOf(true)
|
||||
val registration = presentation.register { dirty.value = false }
|
||||
try {
|
||||
compose.runOnIdle {
|
||||
compose.activity.setProtectedTestContent(presentation) {
|
||||
MaterialTheme {
|
||||
Text(
|
||||
if (dirty.value) "Disposable protected fixture" else "Clean foreground"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
compose.onNodeWithText("Disposable protected fixture").assertIsDisplayed()
|
||||
compose.runOnIdle {
|
||||
presentation.clear()
|
||||
assertEquals(
|
||||
View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
|
||||
compose.activity.window.decorView.importantForAccessibility
|
||||
)
|
||||
assertFalse(dirty.value)
|
||||
}
|
||||
compose.onNodeWithText("Clean foreground").assertIsDisplayed()
|
||||
compose.onNodeWithText("Disposable protected fixture").assertDoesNotExist()
|
||||
compose.runOnIdle {
|
||||
assertFalse(
|
||||
"The rebuilt foreground surface must be visible to accessibility",
|
||||
compose.activity.window.decorView.importantForAccessibility ==
|
||||
View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
|
||||
)
|
||||
}
|
||||
} finally {
|
||||
registration.close()
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun inspectTaskSwitchingWithDisposableProtectedInput() {
|
||||
assumeTrue(InstrumentationRegistry.getArguments().getString("securityInspect") == "true")
|
||||
val done = CountDownLatch(1)
|
||||
|
||||
@@ -5,6 +5,7 @@ import androidx.compose.ui.test.hasText
|
||||
import androidx.compose.ui.test.isHeading
|
||||
import androidx.compose.ui.test.junit4.accessibility.enableAccessibilityChecks
|
||||
import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
@@ -28,9 +29,7 @@ class ShellScreenTest {
|
||||
compose.onNodeWithText("Fixture: ${state.name}").performScrollTo().performClick()
|
||||
ShellTab.entries.forEach { tab ->
|
||||
val page = ShellFixtures.all.getValue(state).first { it.tab == tab }
|
||||
compose.onNode(
|
||||
hasText(page.title) and androidx.compose.ui.test.isSelectable()
|
||||
).performClick()
|
||||
compose.onNodeWithTag("shell-tab-${tab.name}").performClick()
|
||||
compose.waitUntil(timeoutMillis = 10_000) {
|
||||
compose.onAllNodes(hasText(page.stateTitle) and isHeading())
|
||||
.fetchSemanticsNodes().size == 1
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package de.rfc1437.ironstorage
|
||||
|
||||
import android.app.KeyguardManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.ui.input.InputMode
|
||||
import androidx.compose.ui.input.InputModeManager
|
||||
import androidx.compose.ui.input.key.Key
|
||||
@@ -20,6 +24,7 @@ import androidx.compose.ui.test.performKeyInput
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.performScrollToNode
|
||||
import androidx.compose.ui.test.performSemanticsAction
|
||||
import androidx.compose.ui.test.performTextReplacement
|
||||
import androidx.compose.ui.test.pressKey
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
@@ -30,10 +35,12 @@ import de.rfc1437.ironstorage.core.AuthenticationRepository
|
||||
import de.rfc1437.ironstorage.core.AuthenticationState
|
||||
import de.rfc1437.ironstorage.core.ProtectedPresentation
|
||||
import de.rfc1437.ironstorage.features.ApplicationTheme
|
||||
import de.rfc1437.ironstorage.features.SearchScreen
|
||||
import de.rfc1437.ironstorage.features.SetupFormViewModel
|
||||
import de.rfc1437.ironstorage.features.ShellScreen
|
||||
import de.rfc1437.ironstorage.features.ShellViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
@@ -43,8 +50,32 @@ class Tier2WindowTest {
|
||||
@get:Rule val compose = createAndroidComposeRule<MainActivity>()
|
||||
|
||||
@Test fun settingsAndKeyboardNavigationFitTheCurrentWindow() {
|
||||
compose.runOnIdle {
|
||||
if (Build.VERSION.SDK_INT >= 27) compose.activity.setTurnScreenOn(true)
|
||||
val keyguard = compose.activity.getSystemService(KeyguardManager::class.java)
|
||||
if (!keyguard.isDeviceSecure) keyguard.requestDismissKeyguard(compose.activity, null)
|
||||
}
|
||||
compose.enableAccessibilityChecks()
|
||||
val original = ViewModelProvider(compose.activity)[ShellViewModel::class.java]
|
||||
if (InstrumentationRegistry.getArguments().getString("hardeningResize") == "true") {
|
||||
val initialWidth = compose.activity.window.decorView.width
|
||||
compose.activity.runOnUiThread {
|
||||
compose.activity.setProtectedTestContent {
|
||||
MaterialTheme { SearchScreen(original.search, {}) }
|
||||
}
|
||||
}
|
||||
compose.onNodeWithText("Entry name or path").performTextReplacement("appearance")
|
||||
InstrumentationRegistry.getInstrumentation().sendStatus(
|
||||
0,
|
||||
Bundle().apply { putBoolean("ironstorage_resize_ready", true) }
|
||||
)
|
||||
compose.waitUntil(30000) { compose.activity.window.decorView.width != initialWidth }
|
||||
compose.runOnIdle {
|
||||
val current = ViewModelProvider(compose.activity)[ShellViewModel::class.java]
|
||||
assertEquals("appearance", current.search.state.value.query)
|
||||
current.search.clear()
|
||||
}
|
||||
}
|
||||
val setup = ViewModelProvider(compose.activity)[SetupFormViewModel::class.java]
|
||||
val authentication = object : AuthenticationRepository by original.authentication {
|
||||
override val state = MutableStateFlow(AuthenticationState())
|
||||
@@ -72,7 +103,8 @@ class Tier2WindowTest {
|
||||
val width =
|
||||
compose.activity.window.decorView.width /
|
||||
compose.activity.resources.displayMetrics.density
|
||||
val navigation = if (width >= 600) "shell-navigation-rail" else "shell-bottom-navigation"
|
||||
val navigation = InstrumentationRegistry.getArguments().getString("expectedNavigation")
|
||||
?: if (width >= 600) "shell-navigation-rail" else "shell-bottom-navigation"
|
||||
compose.onNodeWithTag(navigation).assertIsDisplayed()
|
||||
compose.onNodeWithTag("settings-search").assertIsDisplayed()
|
||||
if (InstrumentationRegistry.getArguments().getString("hardeningIme") == "true") {
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.ui.semantics.SemanticsActions
|
||||
import androidx.compose.ui.test.ExperimentalTestApi
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertTextEquals
|
||||
import androidx.compose.ui.test.junit4.accessibility.enableAccessibilityChecks
|
||||
import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onLast
|
||||
@@ -36,6 +37,7 @@ import java.util.concurrent.TimeUnit
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assume.assumeTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
@@ -43,6 +45,10 @@ import org.junit.Test
|
||||
class TotpScreenTest {
|
||||
@get:Rule val compose = createAndroidComposeRule<MainActivity>()
|
||||
|
||||
@Before fun enableChecks() {
|
||||
compose.enableAccessibilityChecks()
|
||||
}
|
||||
|
||||
private fun display(fixture: Fixture, fontScale: Float = 1f) {
|
||||
compose.activity.runOnUiThread {
|
||||
compose.activity.setProtectedTestContent {
|
||||
|
||||
+3432
-1116
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user