diff --git a/samples/containers/app-poetry/src/androidTest/java/com/squareup/sample/poetryapp/PoetryAppTest.kt b/samples/containers/app-poetry/src/androidTest/java/com/squareup/sample/poetryapp/PoetryAppTest.kt
index 6bc56540d7..5701642b4b 100644
--- a/samples/containers/app-poetry/src/androidTest/java/com/squareup/sample/poetryapp/PoetryAppTest.kt
+++ b/samples/containers/app-poetry/src/androidTest/java/com/squareup/sample/poetryapp/PoetryAppTest.kt
@@ -1,14 +1,13 @@
package com.squareup.sample.poetryapp
+import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.squareup.sample.container.poetryapp.R
-import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
-import com.squareup.workflow1.ui.internal.test.inAnyView
import leakcanary.DetectLeaksAfterTestSuccess
import org.junit.Rule
import org.junit.Test
@@ -16,17 +15,15 @@ import org.junit.rules.RuleChain
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-@OptIn(WorkflowUiExperimentalApi::class)
class PoetryAppTest {
private val scenarioRule = ActivityScenarioRule(PoetryActivity::class.java)
- @get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
+ @get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
.around(scenarioRule)
.around(IdlingDispatcherRule)
@Test fun launches() {
- inAnyView(withText(R.string.poems))
- .check(matches(isDisplayed()))
+ onView(withText(R.string.poems)).check(matches(isDisplayed()))
}
}
diff --git a/samples/containers/app-raven/src/androidTest/java/com/squareup/sample/ravenapp/RavenAppTest.kt b/samples/containers/app-raven/src/androidTest/java/com/squareup/sample/ravenapp/RavenAppTest.kt
index b1644b1e95..e7ad5d0822 100644
--- a/samples/containers/app-raven/src/androidTest/java/com/squareup/sample/ravenapp/RavenAppTest.kt
+++ b/samples/containers/app-raven/src/androidTest/java/com/squareup/sample/ravenapp/RavenAppTest.kt
@@ -1,13 +1,12 @@
package com.squareup.sample.ravenapp
+import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
-import com.squareup.workflow1.ui.internal.test.inAnyView
import leakcanary.DetectLeaksAfterTestSuccess
import org.junit.Rule
import org.junit.Test
@@ -15,17 +14,16 @@ import org.junit.rules.RuleChain
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-@OptIn(WorkflowUiExperimentalApi::class)
class RavenAppTest {
private val scenarioRule = ActivityScenarioRule(RavenActivity::class.java)
- @get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
+ @get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
.around(scenarioRule)
.around(IdlingDispatcherRule)
@Test fun launches() {
- inAnyView(withText("The Raven"))
+ onView(withText("The Raven"))
.check(matches(isDisplayed()))
}
}
diff --git a/samples/containers/hello-back-button/src/androidTest/java/com/squareup/sample/hellobackbutton/HelloBackButtonEspressoTest.kt b/samples/containers/hello-back-button/src/androidTest/java/com/squareup/sample/hellobackbutton/HelloBackButtonEspressoTest.kt
index c353358a50..9b4772a165 100644
--- a/samples/containers/hello-back-button/src/androidTest/java/com/squareup/sample/hellobackbutton/HelloBackButtonEspressoTest.kt
+++ b/samples/containers/hello-back-button/src/androidTest/java/com/squareup/sample/hellobackbutton/HelloBackButtonEspressoTest.kt
@@ -1,7 +1,10 @@
package com.squareup.sample.hellobackbutton
+import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.action.ViewActions.pressBack
import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.RootMatchers.isDialog
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
@@ -9,9 +12,6 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
-import com.squareup.workflow1.ui.internal.test.actuallyPressBack
-import com.squareup.workflow1.ui.internal.test.inAnyView
-import com.squareup.workflow1.ui.internal.test.retryBlocking
import leakcanary.DetectLeaksAfterTestSuccess
import org.junit.Rule
import org.junit.Test
@@ -24,29 +24,32 @@ class HelloBackButtonEspressoTest {
private val scenarioRule = ActivityScenarioRule(HelloBackButtonActivity::class.java)
- @get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
+ @get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
.around(scenarioRule)
.around(IdlingDispatcherRule)
- @Test fun wrappedTakesPrecedence() = retryBlocking {
- inAnyView(withId(R.id.hello_message)).apply {
+ @Test fun wrappedTakesPrecedence() {
+ onView(withId(R.id.hello_message)).apply {
check(matches(withText("Able")))
perform(click())
check(matches(withText("Baker")))
perform(click())
check(matches(withText("Charlie")))
- actuallyPressBack()
+ perform(pressBack())
check(matches(withText("Baker")))
- actuallyPressBack()
+ perform(pressBack())
check(matches(withText("Able")))
}
}
- @Test fun outerHandlerAppliesIfWrappedHandlerIsNull() = retryBlocking {
- inAnyView(withId(R.id.hello_message)).apply {
- actuallyPressBack()
- inAnyView(withText("Are you sure you want to do this thing?"))
- .check(matches(isDisplayed()))
+ @Test fun outerHandlerAppliesIfWrappedHandlerIsNull() {
+ onView(withId(R.id.hello_message)).apply {
+ check(matches(isDisplayed()))
+ perform(pressBack())
}
+
+ onView(withText("Are you sure you want to do this thing?"))
+ .inRoot(isDialog())
+ .check(matches(isDisplayed()))
}
}
diff --git a/samples/dungeon/app/src/androidTest/java/com/squareup/sample/dungeon/DungeonAppTest.kt b/samples/dungeon/app/src/androidTest/java/com/squareup/sample/dungeon/DungeonAppTest.kt
index c38a2e8e02..df39036a2f 100644
--- a/samples/dungeon/app/src/androidTest/java/com/squareup/sample/dungeon/DungeonAppTest.kt
+++ b/samples/dungeon/app/src/androidTest/java/com/squareup/sample/dungeon/DungeonAppTest.kt
@@ -1,13 +1,12 @@
package com.squareup.sample.dungeon
+import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
-import com.squareup.workflow1.ui.internal.test.inAnyView
import leakcanary.DetectLeaksAfterTestSuccess
import org.junit.Rule
import org.junit.Test
@@ -15,17 +14,16 @@ import org.junit.rules.RuleChain
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-@OptIn(WorkflowUiExperimentalApi::class)
class DungeonAppTest {
private val scenarioRule = ActivityScenarioRule(DungeonActivity::class.java)
- @get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
+ @get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
.around(scenarioRule)
.around(IdlingDispatcherRule)
@Test fun loadsBoardsList() {
- inAnyView(withText(R.string.boards_list_label))
+ onView(withText(R.string.boards_list_label))
.check(matches(isDisplayed()))
}
}
diff --git a/samples/hello-workflow-fragment/src/androidTest/java/com/squareup/sample/helloworkflowfragment/HelloWorkflowFragmentAppTest.kt b/samples/hello-workflow-fragment/src/androidTest/java/com/squareup/sample/helloworkflowfragment/HelloWorkflowFragmentAppTest.kt
index 78ad2d60ac..7ef655ea6a 100644
--- a/samples/hello-workflow-fragment/src/androidTest/java/com/squareup/sample/helloworkflowfragment/HelloWorkflowFragmentAppTest.kt
+++ b/samples/hello-workflow-fragment/src/androidTest/java/com/squareup/sample/helloworkflowfragment/HelloWorkflowFragmentAppTest.kt
@@ -1,14 +1,13 @@
package com.squareup.sample.helloworkflowfragment
+import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
-import com.squareup.workflow1.ui.internal.test.inAnyView
import leakcanary.DetectLeaksAfterTestSuccess
import org.hamcrest.Matchers.containsString
import org.junit.Rule
@@ -17,25 +16,24 @@ import org.junit.rules.RuleChain
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-@OptIn(WorkflowUiExperimentalApi::class)
class HelloWorkflowFragmentAppTest {
private val scenarioRule = ActivityScenarioRule(HelloWorkflowFragmentActivity::class.java)
- @get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
+ @get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
.around(scenarioRule)
.around(IdlingDispatcherRule)
@Test fun togglesHelloAndGoodbye() {
- inAnyView(withText(containsString("Hello")))
+ onView(withText(containsString("Hello")))
.check(matches(isDisplayed()))
.perform(click())
- inAnyView(withText(containsString("Goodbye")))
+ onView(withText(containsString("Goodbye")))
.check(matches(isDisplayed()))
.perform(click())
- inAnyView(withText(containsString("Hello")))
+ onView(withText(containsString("Hello")))
.check(matches(isDisplayed()))
}
}
diff --git a/samples/hello-workflow/src/androidTest/java/com/squareup/sample/helloworkflow/HelloWorkflowAppTest.kt b/samples/hello-workflow/src/androidTest/java/com/squareup/sample/helloworkflow/HelloWorkflowAppTest.kt
index 66dbdb8559..5f688422ea 100644
--- a/samples/hello-workflow/src/androidTest/java/com/squareup/sample/helloworkflow/HelloWorkflowAppTest.kt
+++ b/samples/hello-workflow/src/androidTest/java/com/squareup/sample/helloworkflow/HelloWorkflowAppTest.kt
@@ -1,14 +1,13 @@
package com.squareup.sample.helloworkflow
+import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
-import com.squareup.workflow1.ui.internal.test.inAnyView
import leakcanary.DetectLeaksAfterTestSuccess
import org.junit.Rule
import org.junit.Test
@@ -16,25 +15,24 @@ import org.junit.rules.RuleChain
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-@OptIn(WorkflowUiExperimentalApi::class)
class HelloWorkflowAppTest {
private val scenarioRule = ActivityScenarioRule(HelloWorkflowActivity::class.java)
- @get:Rule val rules = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
+ @get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
.around(scenarioRule)
.around(IdlingDispatcherRule)
@Test fun togglesHelloAndGoodbye() {
- inAnyView(withText("Hello"))
+ onView(withText("Hello"))
.check(matches(isDisplayed()))
.perform(click())
- inAnyView(withText("Goodbye"))
+ onView(withText("Goodbye"))
.check(matches(isDisplayed()))
.perform(click())
- inAnyView(withText("Hello"))
+ onView(withText("Hello"))
.check(matches(isDisplayed()))
}
}
diff --git a/samples/nested-overlays/build.gradle.kts b/samples/nested-overlays/build.gradle.kts
new file mode 100644
index 0000000000..7d31f7a461
--- /dev/null
+++ b/samples/nested-overlays/build.gradle.kts
@@ -0,0 +1,25 @@
+plugins {
+ id("com.android.application")
+ `kotlin-android`
+ `android-sample-app`
+ `android-ui-tests`
+}
+
+android {
+ defaultConfig {
+ applicationId = "com.squareup.sample.nestedoverlays"
+ }
+ namespace = "com.squareup.sample.nestedoverlays"
+}
+
+dependencies {
+ debugImplementation(libs.squareup.leakcanary.android)
+
+ implementation(libs.androidx.activity.ktx)
+ implementation(libs.androidx.lifecycle.viewmodel.ktx)
+ implementation(libs.androidx.lifecycle.viewmodel.savedstate)
+ implementation(libs.androidx.viewbinding)
+
+ implementation(project(":workflow-ui:core-android"))
+ implementation(project(":workflow-ui:core-common"))
+}
diff --git a/samples/nested-overlays/lint-baseline.xml b/samples/nested-overlays/lint-baseline.xml
new file mode 100644
index 0000000000..4aec7fcd50
--- /dev/null
+++ b/samples/nested-overlays/lint-baseline.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/samples/nested-overlays/src/androidTest/java/com/squareup/sample/nestedoverlays/NestedOverlaysAppTest.kt b/samples/nested-overlays/src/androidTest/java/com/squareup/sample/nestedoverlays/NestedOverlaysAppTest.kt
new file mode 100644
index 0000000000..c616d62a14
--- /dev/null
+++ b/samples/nested-overlays/src/androidTest/java/com/squareup/sample/nestedoverlays/NestedOverlaysAppTest.kt
@@ -0,0 +1,99 @@
+package com.squareup.sample.nestedoverlays
+
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.ViewInteraction
+import androidx.test.espresso.action.ViewActions.click
+import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
+import androidx.test.espresso.matcher.ViewMatchers.withParent
+import androidx.test.espresso.matcher.ViewMatchers.withParentIndex
+import androidx.test.espresso.matcher.ViewMatchers.withText
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
+import leakcanary.DetectLeaksAfterTestSuccess
+import org.hamcrest.core.AllOf.allOf
+import org.hamcrest.core.IsNot.not
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class NestedOverlaysAppTest {
+
+ private val scenarioRule = ActivityScenarioRule(NestedOverlaysActivity::class.java)
+
+ @get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
+ .around(scenarioRule)
+ .around(IdlingDispatcherRule)
+
+ @Test fun basics() {
+ onTopCoverBody().assertDisplayed()
+ onTopCoverEverything().assertDisplayed()
+ onBottomCoverBody().assertDisplayed()
+ onBottomCoverEverything().assertDisplayed()
+
+ onTopCoverBody().perform(click())
+ onView(withText("Close")).perform(click())
+ onTopCoverEverything().perform(click())
+ onView(withText("Close")).perform(click())
+
+ onView(withText("Hide Top Bar")).perform(click())
+ onTopCoverBody().assertNotDisplayed()
+ onTopCoverEverything().assertNotDisplayed()
+ onBottomCoverBody().assertDisplayed()
+ onBottomCoverEverything().assertDisplayed()
+
+ onView(withText("Hide Bottom Bar")).perform(click())
+ onTopCoverBody().assertNotDisplayed()
+ onTopCoverEverything().assertNotDisplayed()
+ onBottomCoverBody().assertNotDisplayed()
+ onBottomCoverEverything().assertNotDisplayed()
+ }
+
+ // https://github.com/square/workflow-kotlin/issues/966
+ @Test fun canInsertDialog() {
+ onTopCoverEverything().perform(click())
+ onView(withText("Hide Top Bar")).check(doesNotExist())
+ onView(withText("Cover Body")).perform(click())
+
+ // This line fails due to https://github.com/square/workflow-kotlin/issues/966
+ // onView(withText("Hide Top Bar")).check(doesNotExist())
+
+ // Should continue to close the top sheet and assert that the inner sheet is visible.
+ }
+
+ // So far can't express this in Espresso. Considering move to Maestro
+ // @Test fun canClickPastInnerWindow() {
+ // onView(allOf(withText("Cover Everything"), withParent(withParentIndex(0))))
+ // .perform(click())
+ //
+ // scenario.onActivity { activity ->
+ // onView(allOf(withText("Cover Everything"), withParent(withParentIndex(0))))
+ // .inRoot(withDecorView(not(`is`(activity.window.decorView))))
+ // .perform(click())
+ // }
+ // }
+
+ private fun ViewInteraction.assertNotDisplayed() {
+ check(matches(not(isDisplayed())))
+ }
+
+ private fun ViewInteraction.assertDisplayed() {
+ check(matches(isDisplayed()))
+ }
+
+ private fun onBottomCoverEverything() =
+ onView(allOf(withText("Cover Everything"), withParent(withParentIndex(2))))
+
+ private fun onBottomCoverBody() =
+ onView(allOf(withText("Cover Body"), withParent(withParentIndex(2))))
+
+ private fun onTopCoverBody() =
+ onView(allOf(withText("Cover Body"), withParent(withParentIndex(0))))
+
+ private fun onTopCoverEverything() =
+ onView(allOf(withText("Cover Everything"), withParent(withParentIndex(0))))
+}
diff --git a/samples/nested-overlays/src/main/AndroidManifest.xml b/samples/nested-overlays/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..594e1fde1d
--- /dev/null
+++ b/samples/nested-overlays/src/main/AndroidManifest.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/nested-overlays/src/main/java/com/squareup/sample/nestedoverlays/ButtonBar.kt b/samples/nested-overlays/src/main/java/com/squareup/sample/nestedoverlays/ButtonBar.kt
new file mode 100644
index 0000000000..37f9f7726f
--- /dev/null
+++ b/samples/nested-overlays/src/main/java/com/squareup/sample/nestedoverlays/ButtonBar.kt
@@ -0,0 +1,53 @@
+package com.squareup.sample.nestedoverlays
+
+import android.graphics.drawable.ColorDrawable
+import android.view.Gravity
+import android.widget.LinearLayout
+import androidx.annotation.ColorRes
+import androidx.annotation.StringRes
+import androidx.core.view.get
+import com.squareup.workflow1.ui.AndroidScreen
+import com.squareup.workflow1.ui.ScreenViewFactory
+import com.squareup.workflow1.ui.ScreenViewHolder
+import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
+import android.widget.Button as ButtonView
+
+data class Button(
+ @StringRes val name: Int,
+ val onClick: () -> Unit
+)
+
+@OptIn(WorkflowUiExperimentalApi::class)
+class ButtonBar(
+ vararg buttons: Button?,
+ @ColorRes val color: Int = -1,
+) : AndroidScreen {
+ private val buttons: List