fix: add UI test for URL modal dialog and fix mention infinite layout inflation bugs (#841)
This commit is contained in:
parent
07ccc2696b
commit
b01075cef6
|
@ -1,26 +1,44 @@
|
||||||
package network.loki.messenger
|
package network.loki.messenger
|
||||||
|
|
||||||
|
import android.app.Instrumentation
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
import androidx.test.espresso.Espresso.pressBack
|
import androidx.test.espresso.Espresso.pressBack
|
||||||
|
import androidx.test.espresso.UiController
|
||||||
|
import androidx.test.espresso.ViewAction
|
||||||
import androidx.test.espresso.action.ViewActions
|
import androidx.test.espresso.action.ViewActions
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
|
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.isRoot
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withSubstring
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.filters.LargeTest
|
import androidx.test.filters.LargeTest
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import network.loki.messenger.util.InputBarButtonDrawableMatcher.Companion.inputButtonWithDrawable
|
import network.loki.messenger.util.InputBarButtonDrawableMatcher.Companion.inputButtonWithDrawable
|
||||||
import network.loki.messenger.util.NewConversationButtonDrawableMatcher.Companion.newConversationButtonWithDrawable
|
import network.loki.messenger.util.NewConversationButtonDrawableMatcher.Companion.newConversationButtonWithDrawable
|
||||||
|
import org.hamcrest.Matcher
|
||||||
import org.hamcrest.Matchers.allOf
|
import org.hamcrest.Matchers.allOf
|
||||||
import org.hamcrest.Matchers.not
|
import org.hamcrest.Matchers.not
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
|
import org.session.libsignal.utilities.guava.Optional
|
||||||
|
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
|
||||||
|
import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBar
|
||||||
import org.thoughtcrime.securesms.home.HomeActivity
|
import org.thoughtcrime.securesms.home.HomeActivity
|
||||||
|
import org.thoughtcrime.securesms.mms.GlideApp
|
||||||
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@LargeTest
|
@LargeTest
|
||||||
|
@ -29,10 +47,29 @@ class HomeActivityTests {
|
||||||
@get:Rule
|
@get:Rule
|
||||||
var activityRule = ActivityScenarioRule(HomeActivity::class.java)
|
var activityRule = ActivityScenarioRule(HomeActivity::class.java)
|
||||||
|
|
||||||
private fun sendMessage(messageToSend: String) {
|
private val activityMonitor = Instrumentation.ActivityMonitor(ConversationActivityV2::class.java.name, null, false)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
InstrumentationRegistry.getInstrumentation().addMonitor(activityMonitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
InstrumentationRegistry.getInstrumentation().removeMonitor(activityMonitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendMessage(messageToSend: String, linkPreview: LinkPreview? = null) {
|
||||||
// assume in chat activity
|
// assume in chat activity
|
||||||
onView(allOf(isDescendantOfA(withId(R.id.inputBar)),withId(R.id.inputBarEditText))).perform(ViewActions.replaceText(messageToSend))
|
onView(allOf(isDescendantOfA(withId(R.id.inputBar)),withId(R.id.inputBarEditText))).perform(ViewActions.replaceText(messageToSend))
|
||||||
|
if (linkPreview != null) {
|
||||||
|
val activity = activityMonitor.waitForActivity() as ConversationActivityV2
|
||||||
|
val glide = GlideApp.with(activity)
|
||||||
|
activity.findViewById<InputBar>(R.id.inputBar).updateLinkPreviewDraft(glide, linkPreview)
|
||||||
|
}
|
||||||
onView(allOf(isDescendantOfA(withId(R.id.inputBar)),inputButtonWithDrawable(R.drawable.ic_arrow_up))).perform(ViewActions.click())
|
onView(allOf(isDescendantOfA(withId(R.id.inputBar)),inputButtonWithDrawable(R.drawable.ic_arrow_up))).perform(ViewActions.click())
|
||||||
|
// TODO: text can flaky on cursor reload, figure out a better way to wait for the UI to settle with new data
|
||||||
|
onView(isRoot()).perform(waitFor(500))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupLoggedInState(hasViewedSeed: Boolean = false) {
|
private fun setupLoggedInState(hasViewedSeed: Boolean = false) {
|
||||||
|
@ -99,7 +136,43 @@ class HomeActivityTests {
|
||||||
// tests url rewriter doesn't crash
|
// tests url rewriter doesn't crash
|
||||||
sendMessage("https://www.getsession.org?random_query_parameter=testtesttesttesttesttesttesttest&other_query_parameter=testtesttesttesttesttesttesttest")
|
sendMessage("https://www.getsession.org?random_query_parameter=testtesttesttesttesttesttesttest&other_query_parameter=testtesttesttesttesttesttesttest")
|
||||||
sendMessage("https://www.ámazon.com")
|
sendMessage("https://www.ámazon.com")
|
||||||
// TODO: check data / tap URL and check it's displayed properly here
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testChat_displaysCorrectUrl() {
|
||||||
|
setupLoggedInState()
|
||||||
|
goToMyChat()
|
||||||
|
TextSecurePreferences.setLinkPreviewsEnabled(InstrumentationRegistry.getInstrumentation().targetContext, true)
|
||||||
|
// given the link url text
|
||||||
|
val url = "https://www.ámazon.com"
|
||||||
|
sendMessage(url, LinkPreview(url, "amazon", Optional.absent()))
|
||||||
|
|
||||||
|
// when the URL span is clicked
|
||||||
|
onView(withSubstring(url)).perform(ViewActions.click())
|
||||||
|
|
||||||
|
// then the URL dialog should be displayed with a known punycode url
|
||||||
|
val amazonPuny = "https://www.xn--mazon-wqa.com/"
|
||||||
|
|
||||||
|
val dialogPromptText = InstrumentationRegistry.getInstrumentation().targetContext.getString(R.string.dialog_open_url_explanation, amazonPuny)
|
||||||
|
|
||||||
|
onView(withText(dialogPromptText)).check(matches(isDisplayed()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform action of waiting for a specific time.
|
||||||
|
*/
|
||||||
|
fun waitFor(millis: Long): ViewAction {
|
||||||
|
return object : ViewAction {
|
||||||
|
override fun getConstraints(): Matcher<View>? {
|
||||||
|
return isRoot()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDescription(): String = "Wait for $millis milliseconds."
|
||||||
|
|
||||||
|
override fun perform(uiController: UiController, view: View?) {
|
||||||
|
uiController.loopMainThreadForAtLeast(millis)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -622,6 +622,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||||
val query = text.substring(currentMentionStartIndex + 1) // + 1 to get rid of the "@"
|
val query = text.substring(currentMentionStartIndex + 1) // + 1 to get rid of the "@"
|
||||||
showOrUpdateMentionCandidatesIfNeeded(query)
|
showOrUpdateMentionCandidatesIfNeeded(query)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
currentMentionStartIndex = -1
|
||||||
|
hideMentionCandidates()
|
||||||
}
|
}
|
||||||
previousText = text
|
previousText = text
|
||||||
}
|
}
|
||||||
|
@ -636,13 +639,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||||
val candidates = MentionsManager.getMentionCandidates(query, viewModel.threadId, viewModel.recipient.isOpenGroupRecipient)
|
val candidates = MentionsManager.getMentionCandidates(query, viewModel.threadId, viewModel.recipient.isOpenGroupRecipient)
|
||||||
this.mentionCandidatesView = view
|
this.mentionCandidatesView = view
|
||||||
view.show(candidates, viewModel.threadId)
|
view.show(candidates, viewModel.threadId)
|
||||||
view.alpha = 0.0f
|
|
||||||
val animation = ValueAnimator.ofObject(FloatEvaluator(), view.alpha, 1.0f)
|
|
||||||
animation.duration = 250L
|
|
||||||
animation.addUpdateListener { animator ->
|
|
||||||
view.alpha = animator.animatedValue as Float
|
|
||||||
}
|
|
||||||
animation.start()
|
|
||||||
} else {
|
} else {
|
||||||
val candidates = MentionsManager.getMentionCandidates(query, viewModel.threadId, viewModel.recipient.isOpenGroupRecipient)
|
val candidates = MentionsManager.getMentionCandidates(query, viewModel.threadId, viewModel.recipient.isOpenGroupRecipient)
|
||||||
this.mentionCandidatesView!!.setMentionCandidates(candidates)
|
this.mentionCandidatesView!!.setMentionCandidates(candidates)
|
||||||
|
|
|
@ -93,6 +93,7 @@ class VisibleMessageContentView : LinearLayout {
|
||||||
binding.quoteView.isVisible = message is MmsMessageRecord && message.quote != null
|
binding.quoteView.isVisible = message is MmsMessageRecord && message.quote != null
|
||||||
|
|
||||||
binding.linkPreviewView.isVisible = message is MmsMessageRecord && message.linkPreviews.isNotEmpty()
|
binding.linkPreviewView.isVisible = message is MmsMessageRecord && message.linkPreviews.isNotEmpty()
|
||||||
|
binding.linkPreviewView.bodyTextView = binding.bodyTextView
|
||||||
|
|
||||||
val linkPreviewLayout = binding.linkPreviewView.layoutParams
|
val linkPreviewLayout = binding.linkPreviewView.layoutParams
|
||||||
linkPreviewLayout.width = if (mediaThumbnailMessage) 0 else ViewGroup.LayoutParams.WRAP_CONTENT
|
linkPreviewLayout.width = if (mediaThumbnailMessage) 0 else ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.conversation.v2.ConversationRecyclerView
|
<org.thoughtcrime.securesms.conversation.v2.ConversationRecyclerView
|
||||||
android:id="@+id/conversationRecyclerView"
|
android:id="@+id/conversationRecyclerView"
|
||||||
android:layout_above="@+id/typingIndicatorViewContainer"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent"
|
||||||
|
android:layout_above="@+id/typingIndicatorViewContainer" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.conversation.v2.components.TypingIndicatorViewContainer
|
<org.thoughtcrime.securesms.conversation.v2.components.TypingIndicatorViewContainer
|
||||||
android:id="@+id/typingIndicatorViewContainer"
|
android:id="@+id/typingIndicatorViewContainer"
|
||||||
|
@ -45,8 +45,7 @@
|
||||||
android:id="@+id/additionalContentContainer"
|
android:id="@+id/additionalContentContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignBottom="@+id/conversationRecyclerView"/>
|
||||||
android:layout_marginBottom="@dimen/input_bar_height" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/attachmentOptionsContainer"
|
android:id="@+id/attachmentOptionsContainer"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<org.thoughtcrime.securesms.conversation.v2.input_bar.mentions.MentionCandidateView
|
<RelativeLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="44dp"
|
android:layout_height="44dp"
|
||||||
|
@ -51,4 +51,4 @@
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:background="@color/separator" />
|
android:background="@color/separator" />
|
||||||
|
|
||||||
</org.thoughtcrime.securesms.conversation.v2.input_bar.mentions.MentionCandidateView>
|
</RelativeLayout>
|
Loading…
Reference in New Issue