7

I have an intent from an activity that I created like so:

    private fun startShareIntent() {
        val sendIntent = Intent().apply {
            action = Intent.ACTION_SEND
            putExtra(Intent.EXTRA_TEXT, "Watch ${viewmodel.movie.value?.title} with me!\n\n${viewmodel.movie.value?.summary}")
            type="text/plain"
        }
        val shareIntent = Intent.createChooser(sendIntent, null)
        startActivity(shareIntent)
    }

That function is run when I click on an icon on the toolbar. I want to run an Espresso UI test on it to check if the activity started is indeed of the above intent. To do that, I'm just checking first if the intent is actually the above intent like so:

    @Test
    fun test_clicking_share_icon_shows_sharing_sheet() {
        val scenario = activityScenarioRule.scenario
        Intents.init()
        val expectedIntent = allOf(
            hasAction(Intent.ACTION_SEND),
            hasExtra(Intent.EXTRA_TEXT, "Watch ${dummyMovieData.title} with me!\n\n${dummyMovieData.summary}"),
            hasType("text/plain")
        )

        onView(withText(dummyMovieData.title)).perform(click())
        onView(withId(R.id.share_detail)).perform(click())
        intended(expectedIntent)
        Intents.release()
    }

However, this returns me an AssertionFailedError:

junit.framework.AssertionFailedError: Wanted to match 1 intents. Actually matched 0 intents.

IntentMatcher: (has action: is "android.intent.action.SEND" and has extras: has bundle with: key: is "android.intent.extra.TEXT" value: is "Watch Enola Holmes with me!\n\nWhile searching for her missing mother, intrepid teen Enola Holmes uses her sleuthing skills to outsmart big brother Sherlock and help a runaway lord." and has type: is "text/plain")

Matched intents:[]

Recorded intents:
-Intent { act=android.intent.action.CHOOSER (has extras) } handling packages:[[android]], extras:[Bundle[{android.intent.extra.INTENT=Intent { act=android.intent.action.SEND typ=text/plain flg=0x1 clip={text/plain T:Watch Enola Holmes with me!

While searching for her missing mother, intrepid teen Enola Holmes uses her sleuthing skills to outsmart big brother Sherlock and help a runaway lord.} (has extras) }}]])

How can I make it so that the test can match the intent? It seems from the error message the two are already the same.

Richard
  • 7,037
  • 2
  • 23
  • 76

1 Answers1

7

The problem is that you need to add a CHOOSER as :

fun chooser(matcher: Matcher<Intent>): Matcher<Intent> {
      return allOf(
          hasAction(Intent.ACTION_CHOOSER),
          hasExtra(`is`(Intent.EXTRA_INTENT), matcher))
}

And then you can do :

intended(chooser(expectedIntent))

Create a variable like this one to match with your Intent

private val expectedIntent = Matchers.allOf(
            IntentMatchers.hasAction(Intent.ACTION_SEND),
            IntentMatchers.hasExtra("Your key", "Watch ${dummyMovieData.title} with me!\n\n${dummyMovieData.summary}"),
            IntentMatchers.hasType("text/plain")
        )

Then change your test to :

@Test
    fun test_clicking_share_icon_shows_sharing_sheet() {
        Intents.init()
        onView(withText(dummyMovieData.title)).perform(click())
        onView(withId(R.id.share_detail)).perform(click())
        intended(chooser(expectedIntent))
        Intents.release()
    }
Mikhail Sharin
  • 3,661
  • 3
  • 27
  • 36
Skizo-ozᴉʞS ツ
  • 19,464
  • 18
  • 81
  • 148
  • What should I substitute `your_key` with? I'm not using any key unfortunately. Also, why isn't `Intents.init()` and `Intents.release()` not required? – Richard Oct 28 '20 at 16:47
  • I'm not using Intents.init neither release I'd say, and your key is Intent.EXTRA_TEXT – Skizo-ozᴉʞS ツ Oct 28 '20 at 16:50
  • Hm, it worked. Could you perhaps add an explanation why I needed the Matcher you created and why `Intents.init()` isn't needed? – Richard Oct 28 '20 at 16:52
  • 1
    I just tested without `Intents.init()` and `Intents.release()`. The result is the test failed with this exception `java.lang.RuntimeException: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.test.espresso.intent.Intents.internalIntended(org.hamcrest.Matcher, androidx.test.espresso.intent.VerificationMode, java.util.List)' on a null object reference`. However, adding them works. You should edit your answer. – Richard Oct 28 '20 at 16:56
  • What is `Intents.init()`? – IgorGanapolsky Aug 20 '21 at 19:08
  • Why intent has an intent within? – apex39 Jan 31 '22 at 10:33
  • @apex39 what do you mean? – Skizo-ozᴉʞS ツ Jan 31 '22 at 11:55
  • Do you know why chooser, while being an intent itself, has an intentent in its extras. – apex39 Feb 01 '22 at 17:03
  • Am I right that it should be `intended(chooser(expectedIntent))` instead of `intended(expectedIntent)` in the `test_clicking_share_icon_shows_sharing_sheet ` method? – Mikhail Sharin Aug 18 '23 at 16:31