Migrate to v2 testing APIs

This commit is contained in:
Benoit Marty 2026-04-30 15:54:33 +02:00
parent da36323006
commit 11b9efa2c9
83 changed files with 2197 additions and 2320 deletions

View file

@ -6,12 +6,15 @@
* Please see LICENSE files in the repository root for full details.
*/
@file:OptIn(ExperimentalTestApi::class)
package io.element.android.libraries.textcomposer.impl.components.markdown
import android.widget.EditText
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.AndroidComposeUiTest
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
import androidx.core.text.getSpans
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
@ -32,66 +35,54 @@ import io.element.android.libraries.textcomposer.model.SuggestionType
import io.element.android.libraries.textcomposer.model.aMarkdownTextEditorState
import io.element.android.tests.testutils.EnsureCalledOnceWithParam
import io.element.android.tests.testutils.EventsRecorder
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestRule
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class MarkdownTextInputTest {
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
@Test
fun `when user types onTyping is triggered with value 'true'`() = runTest {
fun `when user types onTyping is triggered with value 'true'`() = runAndroidComposeUiTest {
val state = aMarkdownTextEditorState(initialFocus = true)
val onTyping = EnsureCalledOnceWithParam(expectedParam = true, result = Unit)
rule.setMarkdownTextInput(state = state, onTyping = onTyping)
rule.activityRule.scenario.onActivity {
it.findEditor().setText("Test")
}
rule.awaitIdle()
setMarkdownTextInput(state = state, onTyping = onTyping)
activity!!.findEditor().setText("Test")
awaitIdle()
onTyping.assertSuccess()
}
@Test
fun `when user removes text onTyping is triggered with value 'false'`() = runTest {
fun `when user removes text onTyping is triggered with value 'false'`() = runAndroidComposeUiTest {
val state = aMarkdownTextEditorState(initialFocus = true)
val onTyping = EventsRecorder<Boolean>()
rule.setMarkdownTextInput(state = state, onTyping = onTyping)
rule.activityRule.scenario.onActivity {
val editText = it.findEditor()
editText.setText("Test")
editText.setText("")
editText.setText(null)
}
rule.awaitIdle()
setMarkdownTextInput(state = state, onTyping = onTyping)
val editText = activity!!.findEditor()
editText.setText("Test")
editText.setText("")
editText.setText(null)
awaitIdle()
onTyping.assertList(listOf(true, false, false))
}
@Test
fun `when user types something that's not a mention onSuggestionReceived is triggered with 'null'`() = runTest {
fun `when user types something that's not a mention onSuggestionReceived is triggered with 'null'`() = runAndroidComposeUiTest {
val state = aMarkdownTextEditorState(initialFocus = true)
val onSuggestionReceived = EventsRecorder<Suggestion?>()
rule.setMarkdownTextInput(state = state, onSuggestionReceived = onSuggestionReceived)
rule.activityRule.scenario.onActivity {
it.findEditor().setText("Test")
}
rule.awaitIdle()
setMarkdownTextInput(state = state, onSuggestionReceived = onSuggestionReceived)
activity!!.findEditor().setText("Test")
awaitIdle()
onSuggestionReceived.assertSingle(null)
}
@Test
fun `when user types something that's a mention onSuggestionReceived is triggered a real value`() = runTest {
fun `when user types something that's a mention onSuggestionReceived is triggered a real value`() = runAndroidComposeUiTest {
val state = aMarkdownTextEditorState(initialFocus = true)
val onSuggestionReceived = EventsRecorder<Suggestion?>()
rule.setMarkdownTextInput(state = state, onSuggestionReceived = onSuggestionReceived)
rule.activityRule.scenario.onActivity {
it.findEditor().setText("@")
it.findEditor().setText("#")
it.findEditor().setText("/")
}
rule.awaitIdle()
setMarkdownTextInput(state = state, onSuggestionReceived = onSuggestionReceived)
val editor = activity!!.findEditor()
editor.setText("@")
editor.setText("#")
editor.setText("/")
awaitIdle()
onSuggestionReceived.assertList(
listOf(
// User mention suggestion
@ -105,69 +96,59 @@ class MarkdownTextInputTest {
}
@Test
fun `when the selection changes in the UI the state is updated`() = runTest {
fun `when the selection changes in the UI the state is updated`() = runAndroidComposeUiTest {
val state = aMarkdownTextEditorState(initialText = "Test", initialFocus = true)
rule.setMarkdownTextInput(state = state)
rule.activityRule.scenario.onActivity {
val editor = it.findEditor()
editor.setSelection(2)
}
rule.awaitIdle()
setMarkdownTextInput(state = state)
val editor = activity!!.findEditor()
editor.setSelection(2)
awaitIdle()
// Selection is updated
assertThat(state.selection).isEqualTo(2..2)
}
@Test
fun `when the selection state changes in the view is updated`() = runTest {
fun `when the selection state changes in the view is updated`() = runAndroidComposeUiTest {
val state = aMarkdownTextEditorState(initialText = "Test", initialFocus = true)
rule.setMarkdownTextInput(state = state)
var editor: EditText? = null
rule.activityRule.scenario.onActivity {
editor = it.findEditor()
state.selection = 2..2
}
rule.awaitIdle()
setMarkdownTextInput(state = state)
val editor = activity!!.findEditor()
state.selection = 2..2
awaitIdle()
// Selection state is updated
assertThat(editor?.selectionStart).isEqualTo(2)
assertThat(editor?.selectionEnd).isEqualTo(2)
assertThat(editor.selectionStart).isEqualTo(2)
assertThat(editor.selectionEnd).isEqualTo(2)
}
@Test
fun `when the view focus changes the state is updated`() = runTest {
fun `when the view focus changes the state is updated`() = runAndroidComposeUiTest {
val state = aMarkdownTextEditorState(initialText = "Test", initialFocus = false)
rule.setMarkdownTextInput(state = state)
rule.activityRule.scenario.onActivity {
val editor = it.findEditor()
editor.requestFocus()
}
setMarkdownTextInput(state = state)
val editor = activity!!.findEditor()
editor.requestFocus()
// Focus state is updated
assertThat(state.hasFocus).isTrue()
}
@Test
fun `inserting a mention replaces the existing text with a span`() = runTest {
fun `inserting a mention replaces the existing text with a span`() = runAndroidComposeUiTest {
val permalinkParser = FakePermalinkParser(result = { PermalinkData.UserLink(A_SESSION_ID) })
val state = aMarkdownTextEditorState(initialText = "@", initialFocus = true)
state.currentSuggestion = Suggestion(0, 1, SuggestionType.Mention, "")
rule.setMarkdownTextInput(state = state)
var editor: EditText? = null
rule.activityRule.scenario.onActivity {
editor = it.findEditor()
state.insertSuggestion(
ResolvedSuggestion.Member(roomMember = aRoomMember()),
aMentionSpanProvider(permalinkParser),
)
}
rule.awaitIdle()
setMarkdownTextInput(state = state)
val editor = activity!!.findEditor()
state.insertSuggestion(
ResolvedSuggestion.Member(roomMember = aRoomMember()),
aMentionSpanProvider(permalinkParser),
)
awaitIdle()
// Text is replaced with a placeholder
assertThat(editor?.editableText.toString()).isEqualTo("@ ")
assertThat(editor.editableText.toString()).isEqualTo("@ ")
// The placeholder contains a MentionSpan
val mentionSpans = editor?.editableText?.getSpans<MentionSpan>(0, 2).orEmpty()
val mentionSpans = editor.editableText?.getSpans<MentionSpan>(0, 2).orEmpty()
assertThat(mentionSpans).isNotEmpty()
}
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setMarkdownTextInput(
private fun AndroidComposeUiTest<ComponentActivity>.setMarkdownTextInput(
state: MarkdownTextEditorState = aMarkdownTextEditorState(),
onTyping: (Boolean) -> Unit = {},
onSuggestionReceived: (Suggestion?) -> Unit = {},