Reputation: 41
I am using Android Studio Arctic fox and I try to test the behaviour of a variable that is stored using rememberSaveable. I did the test manualy by doing "Rotate Left" in Emulator. There the behaviour is as expected : value stored using remember
is gone. value stored using rememberSaveable
is still available.
Now I want to get rid of manually testing and create an Instrumented test. But there I don't get the expected result.
In the test both values are displayed in my output-Textfield.
I tried to get right behaviour by adding waitForIdleSync()
but it did not help.
I think it could have to do with "setting" the orientation. Maybe there is a method that is called by system when the orientation changes that I miss in my test case. But I have no clue what method I miss and how to call that method in my test.
@RunWith(AndroidJUnit4::class)
class SavingTurnTest {
@get:Rule
val composeTestRule = createComposeRule()
@Before
fun setUp(){
composeTestRule.setContent{
MyApplicationTheme {
SampleRemember_saveable()
}
}
composeTestRule.onNodeWithTag("remember").performTextInput("Text_Remember")
composeTestRule.onNodeWithTag("saveable").performTextInput("Text_Saveable")
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
}
@Test
fun saveTextOnTurn(){
uiAutomation.setRotation(ROTATION_FREEZE_0)
uiAutomation.setRotation(ROTATION_UNFREEZE)
uiAutomation.setRotation(ROTATION_FREEZE_90)
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
// The next Line should fail, but test passes
// composeTestRule.onNodeWithTag("output").assertTextContains("Text_Remember")
// This test is ok
composeTestRule.onNodeWithTag("output").assertTextContains("Text_Saveable")
// The next Line should pass, but test fails
composeTestRule.onNodeWithTag("output").assertTextEquals("Text_Saveable")
}
}
Upvotes: 4
Views: 1584
Reputation: 486
the below code will test a saveable but there are some caveats, first make sure that you add the ComponentActivity class to your AndroidManifest.xml file or replace it with your own activity class.
<activity android:name="androidx.activity.ComponentActivity" />
Second, it appears that the default option of using the line number for the key of a rememberSaveable doesn't work (At least I couldn't get it to work). However a custom key seems to work fine.
The basic idea is that we use createEmptyComposableRule to create a rule that is not attached to a specific Activity, then we create one with ActivityScenario. After setting content and making changes we use recreate() to restart the activity. Then you set your content once again, and check that the saveable was restored. There may be better ways of doing this as I am new to android development.
@RunWith(AndroidJUnit4::class)
class ExampleTestForSaveables {
@get:Rule
val composeTestRule = createEmptyComposeRule()
private lateinit var scenario: ActivityScenario<ComponentActivity>
@Before
fun setup() {
scenario = ActivityScenario.launch(ComponentActivity::class.java)
}
@Test
fun composeWithFontSizeTest() {
@Composable
fun SomeTextFields() {
var text1 by remember { mutableStateOf("") }
// By default rememberSavable uses it's line number as its key, this doesn't seem
// to work when testing, instead pass a key
var savableText: String by rememberSaveable(key = "savableText") {
mutableStateOf("")
}
Column() {
TextField(modifier = Modifier.testTag("remember"),
value = text1,
onValueChange = {text1 = it},
label = {})
TextField(modifier = Modifier.testTag("saveable"),
value = savableText,
onValueChange = { savableText = it },
label = { }
)
}
}
scenario.onActivity { activity ->
activity.setContent {
SomeTextFields()
}
}
composeTestRule.onNodeWithTag("remember").performTextInput("Text_Remember")
composeTestRule.onNodeWithTag("saveable").performTextInput("Text_Saveable")
// Check that our input worked
composeTestRule.onNodeWithTag("remember").assertTextContains("Text_Remember")
composeTestRule.onNodeWithTag("saveable").assertTextContains("Text_Saveable")
// Restart the activity
scenario.recreate()
// Compose our content
scenario.onActivity { activity ->
activity.setContent {
SomeTextFields()
}
}
// Was the text saved
composeTestRule.onNodeWithTag("remember").assertTextContains("")
composeTestRule.onNodeWithTag("saveable").assertTextContains("Text_Saveable")
}
}
Upvotes: 1