Skip to content

Commit dcc0e26

Browse files
authored
Merge pull request #967 from square/ray/nested-overlays
Nested overlays sample, small bug fixes
2 parents 51d5936 + f355249 commit dcc0e26

File tree

30 files changed

+642
-232
lines changed

30 files changed

+642
-232
lines changed
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,29 @@
11
package com.squareup.sample.poetryapp
22

3+
import androidx.test.espresso.Espresso.onView
34
import androidx.test.espresso.assertion.ViewAssertions.matches
45
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
56
import androidx.test.espresso.matcher.ViewMatchers.withText
67
import androidx.test.ext.junit.rules.ActivityScenarioRule
78
import androidx.test.ext.junit.runners.AndroidJUnit4
89
import com.squareup.sample.container.poetryapp.R
9-
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
1010
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
11-
import com.squareup.workflow1.ui.internal.test.inAnyView
1211
import leakcanary.DetectLeaksAfterTestSuccess
1312
import org.junit.Rule
1413
import org.junit.Test
1514
import org.junit.rules.RuleChain
1615
import org.junit.runner.RunWith
1716

1817
@RunWith(AndroidJUnit4::class)
19-
@OptIn(WorkflowUiExperimentalApi::class)
2018
class PoetryAppTest {
2119

2220
private val scenarioRule = ActivityScenarioRule(PoetryActivity::class.java)
2321

24-
@get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
22+
@get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
2523
.around(scenarioRule)
2624
.around(IdlingDispatcherRule)
2725

2826
@Test fun launches() {
29-
inAnyView(withText(R.string.poems))
30-
.check(matches(isDisplayed()))
27+
onView(withText(R.string.poems)).check(matches(isDisplayed()))
3128
}
3229
}
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
11
package com.squareup.sample.ravenapp
22

3+
import androidx.test.espresso.Espresso.onView
34
import androidx.test.espresso.assertion.ViewAssertions.matches
45
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
56
import androidx.test.espresso.matcher.ViewMatchers.withText
67
import androidx.test.ext.junit.rules.ActivityScenarioRule
78
import androidx.test.ext.junit.runners.AndroidJUnit4
8-
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
99
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
10-
import com.squareup.workflow1.ui.internal.test.inAnyView
1110
import leakcanary.DetectLeaksAfterTestSuccess
1211
import org.junit.Rule
1312
import org.junit.Test
1413
import org.junit.rules.RuleChain
1514
import org.junit.runner.RunWith
1615

1716
@RunWith(AndroidJUnit4::class)
18-
@OptIn(WorkflowUiExperimentalApi::class)
1917
class RavenAppTest {
2018

2119
private val scenarioRule = ActivityScenarioRule(RavenActivity::class.java)
2220

23-
@get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
21+
@get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
2422
.around(scenarioRule)
2523
.around(IdlingDispatcherRule)
2624

2725
@Test fun launches() {
28-
inAnyView(withText("The Raven"))
26+
onView(withText("The Raven"))
2927
.check(matches(isDisplayed()))
3028
}
3129
}
Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
package com.squareup.sample.hellobackbutton
22

3+
import androidx.test.espresso.Espresso.onView
34
import androidx.test.espresso.action.ViewActions.click
5+
import androidx.test.espresso.action.ViewActions.pressBack
46
import androidx.test.espresso.assertion.ViewAssertions.matches
7+
import androidx.test.espresso.matcher.RootMatchers.isDialog
58
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
69
import androidx.test.espresso.matcher.ViewMatchers.withId
710
import androidx.test.espresso.matcher.ViewMatchers.withText
811
import androidx.test.ext.junit.rules.ActivityScenarioRule
912
import androidx.test.ext.junit.runners.AndroidJUnit4
1013
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
1114
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
12-
import com.squareup.workflow1.ui.internal.test.actuallyPressBack
13-
import com.squareup.workflow1.ui.internal.test.inAnyView
14-
import com.squareup.workflow1.ui.internal.test.retryBlocking
1515
import leakcanary.DetectLeaksAfterTestSuccess
1616
import org.junit.Rule
1717
import org.junit.Test
@@ -24,29 +24,32 @@ class HelloBackButtonEspressoTest {
2424

2525
private val scenarioRule = ActivityScenarioRule(HelloBackButtonActivity::class.java)
2626

27-
@get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
27+
@get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
2828
.around(scenarioRule)
2929
.around(IdlingDispatcherRule)
3030

31-
@Test fun wrappedTakesPrecedence() = retryBlocking {
32-
inAnyView(withId(R.id.hello_message)).apply {
31+
@Test fun wrappedTakesPrecedence() {
32+
onView(withId(R.id.hello_message)).apply {
3333
check(matches(withText("Able")))
3434
perform(click())
3535
check(matches(withText("Baker")))
3636
perform(click())
3737
check(matches(withText("Charlie")))
38-
actuallyPressBack()
38+
perform(pressBack())
3939
check(matches(withText("Baker")))
40-
actuallyPressBack()
40+
perform(pressBack())
4141
check(matches(withText("Able")))
4242
}
4343
}
4444

45-
@Test fun outerHandlerAppliesIfWrappedHandlerIsNull() = retryBlocking {
46-
inAnyView(withId(R.id.hello_message)).apply {
47-
actuallyPressBack()
48-
inAnyView(withText("Are you sure you want to do this thing?"))
49-
.check(matches(isDisplayed()))
45+
@Test fun outerHandlerAppliesIfWrappedHandlerIsNull() {
46+
onView(withId(R.id.hello_message)).apply {
47+
check(matches(isDisplayed()))
48+
perform(pressBack())
5049
}
50+
51+
onView(withText("Are you sure you want to do this thing?"))
52+
.inRoot(isDialog())
53+
.check(matches(isDisplayed()))
5154
}
5255
}
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
11
package com.squareup.sample.dungeon
22

3+
import androidx.test.espresso.Espresso.onView
34
import androidx.test.espresso.assertion.ViewAssertions.matches
45
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
56
import androidx.test.espresso.matcher.ViewMatchers.withText
67
import androidx.test.ext.junit.rules.ActivityScenarioRule
78
import androidx.test.ext.junit.runners.AndroidJUnit4
8-
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
99
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
10-
import com.squareup.workflow1.ui.internal.test.inAnyView
1110
import leakcanary.DetectLeaksAfterTestSuccess
1211
import org.junit.Rule
1312
import org.junit.Test
1413
import org.junit.rules.RuleChain
1514
import org.junit.runner.RunWith
1615

1716
@RunWith(AndroidJUnit4::class)
18-
@OptIn(WorkflowUiExperimentalApi::class)
1917
class DungeonAppTest {
2018

2119
private val scenarioRule = ActivityScenarioRule(DungeonActivity::class.java)
2220

23-
@get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
21+
@get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
2422
.around(scenarioRule)
2523
.around(IdlingDispatcherRule)
2624

2725
@Test fun loadsBoardsList() {
28-
inAnyView(withText(R.string.boards_list_label))
26+
onView(withText(R.string.boards_list_label))
2927
.check(matches(isDisplayed()))
3028
}
3129
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package com.squareup.sample.helloworkflowfragment
22

3+
import androidx.test.espresso.Espresso.onView
34
import androidx.test.espresso.action.ViewActions.click
45
import androidx.test.espresso.assertion.ViewAssertions.matches
56
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
67
import androidx.test.espresso.matcher.ViewMatchers.withText
78
import androidx.test.ext.junit.rules.ActivityScenarioRule
89
import androidx.test.ext.junit.runners.AndroidJUnit4
9-
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
1010
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
11-
import com.squareup.workflow1.ui.internal.test.inAnyView
1211
import leakcanary.DetectLeaksAfterTestSuccess
1312
import org.hamcrest.Matchers.containsString
1413
import org.junit.Rule
@@ -17,25 +16,24 @@ import org.junit.rules.RuleChain
1716
import org.junit.runner.RunWith
1817

1918
@RunWith(AndroidJUnit4::class)
20-
@OptIn(WorkflowUiExperimentalApi::class)
2119
class HelloWorkflowFragmentAppTest {
2220

2321
private val scenarioRule = ActivityScenarioRule(HelloWorkflowFragmentActivity::class.java)
2422

25-
@get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
23+
@get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
2624
.around(scenarioRule)
2725
.around(IdlingDispatcherRule)
2826

2927
@Test fun togglesHelloAndGoodbye() {
30-
inAnyView(withText(containsString("Hello")))
28+
onView(withText(containsString("Hello")))
3129
.check(matches(isDisplayed()))
3230
.perform(click())
3331

34-
inAnyView(withText(containsString("Goodbye")))
32+
onView(withText(containsString("Goodbye")))
3533
.check(matches(isDisplayed()))
3634
.perform(click())
3735

38-
inAnyView(withText(containsString("Hello")))
36+
onView(withText(containsString("Hello")))
3937
.check(matches(isDisplayed()))
4038
}
4139
}
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,38 @@
11
package com.squareup.sample.helloworkflow
22

3+
import androidx.test.espresso.Espresso.onView
34
import androidx.test.espresso.action.ViewActions.click
45
import androidx.test.espresso.assertion.ViewAssertions.matches
56
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
67
import androidx.test.espresso.matcher.ViewMatchers.withText
78
import androidx.test.ext.junit.rules.ActivityScenarioRule
89
import androidx.test.ext.junit.runners.AndroidJUnit4
9-
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
1010
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
11-
import com.squareup.workflow1.ui.internal.test.inAnyView
1211
import leakcanary.DetectLeaksAfterTestSuccess
1312
import org.junit.Rule
1413
import org.junit.Test
1514
import org.junit.rules.RuleChain
1615
import org.junit.runner.RunWith
1716

1817
@RunWith(AndroidJUnit4::class)
19-
@OptIn(WorkflowUiExperimentalApi::class)
2018
class HelloWorkflowAppTest {
2119

2220
private val scenarioRule = ActivityScenarioRule(HelloWorkflowActivity::class.java)
2321

24-
@get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
22+
@get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
2523
.around(scenarioRule)
2624
.around(IdlingDispatcherRule)
2725

2826
@Test fun togglesHelloAndGoodbye() {
29-
inAnyView(withText("Hello"))
27+
onView(withText("Hello"))
3028
.check(matches(isDisplayed()))
3129
.perform(click())
3230

33-
inAnyView(withText("Goodbye"))
31+
onView(withText("Goodbye"))
3432
.check(matches(isDisplayed()))
3533
.perform(click())
3634

37-
inAnyView(withText("Hello"))
35+
onView(withText("Hello"))
3836
.check(matches(isDisplayed()))
3937
}
4038
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
plugins {
2+
id("com.android.application")
3+
`kotlin-android`
4+
`android-sample-app`
5+
`android-ui-tests`
6+
}
7+
8+
android {
9+
defaultConfig {
10+
applicationId = "com.squareup.sample.nestedoverlays"
11+
}
12+
namespace = "com.squareup.sample.nestedoverlays"
13+
}
14+
15+
dependencies {
16+
debugImplementation(libs.squareup.leakcanary.android)
17+
18+
implementation(libs.androidx.activity.ktx)
19+
implementation(libs.androidx.lifecycle.viewmodel.ktx)
20+
implementation(libs.androidx.lifecycle.viewmodel.savedstate)
21+
implementation(libs.androidx.viewbinding)
22+
23+
implementation(project(":workflow-ui:core-android"))
24+
implementation(project(":workflow-ui:core-common"))
25+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<issues format="6" by="lint 7.4.1" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.1)" variant="fatal" version="7.4.1">
3+
4+
</issues>
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.squareup.sample.nestedoverlays
2+
3+
import androidx.test.espresso.Espresso.onView
4+
import androidx.test.espresso.ViewInteraction
5+
import androidx.test.espresso.action.ViewActions.click
6+
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
7+
import androidx.test.espresso.assertion.ViewAssertions.matches
8+
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
9+
import androidx.test.espresso.matcher.ViewMatchers.withParent
10+
import androidx.test.espresso.matcher.ViewMatchers.withParentIndex
11+
import androidx.test.espresso.matcher.ViewMatchers.withText
12+
import androidx.test.ext.junit.rules.ActivityScenarioRule
13+
import androidx.test.ext.junit.runners.AndroidJUnit4
14+
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
15+
import leakcanary.DetectLeaksAfterTestSuccess
16+
import org.hamcrest.core.AllOf.allOf
17+
import org.hamcrest.core.IsNot.not
18+
import org.junit.Rule
19+
import org.junit.Test
20+
import org.junit.rules.RuleChain
21+
import org.junit.runner.RunWith
22+
23+
@RunWith(AndroidJUnit4::class)
24+
class NestedOverlaysAppTest {
25+
26+
private val scenarioRule = ActivityScenarioRule(NestedOverlaysActivity::class.java)
27+
28+
@get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
29+
.around(scenarioRule)
30+
.around(IdlingDispatcherRule)
31+
32+
@Test fun basics() {
33+
onTopCoverBody().assertDisplayed()
34+
onTopCoverEverything().assertDisplayed()
35+
onBottomCoverBody().assertDisplayed()
36+
onBottomCoverEverything().assertDisplayed()
37+
38+
onTopCoverBody().perform(click())
39+
onView(withText("Close")).perform(click())
40+
onTopCoverEverything().perform(click())
41+
onView(withText("Close")).perform(click())
42+
43+
onView(withText("Hide Top Bar")).perform(click())
44+
onTopCoverBody().assertNotDisplayed()
45+
onTopCoverEverything().assertNotDisplayed()
46+
onBottomCoverBody().assertDisplayed()
47+
onBottomCoverEverything().assertDisplayed()
48+
49+
onView(withText("Hide Bottom Bar")).perform(click())
50+
onTopCoverBody().assertNotDisplayed()
51+
onTopCoverEverything().assertNotDisplayed()
52+
onBottomCoverBody().assertNotDisplayed()
53+
onBottomCoverEverything().assertNotDisplayed()
54+
}
55+
56+
// https://github.com/square/workflow-kotlin/issues/966
57+
@Test fun canInsertDialog() {
58+
onTopCoverEverything().perform(click())
59+
onView(withText("Hide Top Bar")).check(doesNotExist())
60+
onView(withText("Cover Body")).perform(click())
61+
62+
// This line fails due to https://github.com/square/workflow-kotlin/issues/966
63+
// onView(withText("Hide Top Bar")).check(doesNotExist())
64+
65+
// Should continue to close the top sheet and assert that the inner sheet is visible.
66+
}
67+
68+
// So far can't express this in Espresso. Considering move to Maestro
69+
// @Test fun canClickPastInnerWindow() {
70+
// onView(allOf(withText("Cover Everything"), withParent(withParentIndex(0))))
71+
// .perform(click())
72+
//
73+
// scenario.onActivity { activity ->
74+
// onView(allOf(withText("Cover Everything"), withParent(withParentIndex(0))))
75+
// .inRoot(withDecorView(not(`is`(activity.window.decorView))))
76+
// .perform(click())
77+
// }
78+
// }
79+
80+
private fun ViewInteraction.assertNotDisplayed() {
81+
check(matches(not(isDisplayed())))
82+
}
83+
84+
private fun ViewInteraction.assertDisplayed() {
85+
check(matches(isDisplayed()))
86+
}
87+
88+
private fun onBottomCoverEverything() =
89+
onView(allOf(withText("Cover Everything"), withParent(withParentIndex(2))))
90+
91+
private fun onBottomCoverBody() =
92+
onView(allOf(withText("Cover Body"), withParent(withParentIndex(2))))
93+
94+
private fun onTopCoverBody() =
95+
onView(allOf(withText("Cover Body"), withParent(withParentIndex(0))))
96+
97+
private fun onTopCoverEverything() =
98+
onView(allOf(withText("Cover Everything"), withParent(withParentIndex(0))))
99+
}

0 commit comments

Comments
 (0)