kakaocup / kakao Goto Github PK
View Code? Open in Web Editor NEWNice and simple DSL for Espresso in Kotlin
Home Page: https://kakaocup.github.io/Kakao/
License: Apache License 2.0
Nice and simple DSL for Espresso in Kotlin
Home Page: https://kakaocup.github.io/Kakao/
License: Apache License 2.0
private val header = KTextView { withText(R.string.text) }
private val recyclerView = KRecyclerView({ withId(R.id.recyclerView) }, itemTypeBuilder = {})
fun scrollToTextView() {
// I want to do something like this
recyclerView.scrollTo(header.getViewMatchers())
// Potentially to have an extension func to do this
recyclerView.scrollTo(header)
// As it currently stands, it seems like I have to redefine my matchers.
recyclerView.scrollTo { withText(R.string.text) }
}
In short I would like access to the matchers all KBaseView was initialized with.
I'll raise a PR shortly
Hi Team,
First thanks for this great UI Testing framework.
Currently i am trying to check drawable with imageview but i am getting below error, as follows,
androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: 'with drawable id -1 or provided instance' doesn't match the selected view.
Expected: with drawable id -1 or provided instance
Got: "AppCompatImageView{id=2131230883, res-name=factImage, visibility=VISIBLE, width=180, height=220, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@df6814a, tag=null, root-is-layout-requested=false, has-input-connection=false, x=508.0, y=65.0}"
Test Name: imageViewDrawableComparison
Looking forward for a solution.
Regards,
Vikram Singh
withElement(Locator.LINK_TEXT, "My Home") {
click()
}
in WebTest
Same as:
onWebView().withElement(findElement(Locator.LINK_TEXT, "My Home")).perform(webClick())
WebView content:
val webView = findViewById<WebView>(R.id.webView).apply {
settings.javaScriptEnabled = true
}
webView.loadData(
"""
<html>
<body>
<p id="text">Hello</p>
<a href="#">My Home</a>
</body>
</html>
""", "text/html", "utf-8"
)
java.lang.RuntimeException: java.lang.RuntimeException: Atom evaluation returned null!
at androidx.test.espresso.web.sugar.Web$WebInteraction$ExceptionPropagator.<init>(Web.java:4)
at androidx.test.espresso.web.sugar.Web$WebInteraction.doEval(Web.java:31)
at androidx.test.espresso.web.sugar.Web$WebInteraction.withElement(Web.java:46)
at io.github.kakaocup.kakao.delegate.WebInteractionDelegate.withElement(WebInteractionDelegate.kt:58)
at io.github.kakaocup.kakao.web.WebActions$DefaultImpls.perform(WebActions.kt:55)
at io.github.kakaocup.kakao.web.WebActions$DefaultImpls.click(WebActions.kt:23)
at io.github.kakaocup.kakao.web.WebElementBuilder$KWebInteraction.click(WebElementBuilder.kt:34)
at io.github.kakaocup.sample.WebTest$testWebViewHasTextHelloAndClickLink$1$1$2.invoke(WebTest.kt:27)
TODO:
Replace .gradle
build files with .kts
java.lang.NoSuchMethodError: No static method registerDefaultInstance(Ljava/lang/Class;Lcom/google/protobuf/GeneratedMessageLite;)V in class Lcom/google/protobuf/GeneratedMessageLite; or its super classes (declaration of 'com.google.protobuf.GeneratedMessageLite' appears in /data/app/~~4sKIYTcsfYQtc9JM7hBNvA==/me.mydomain.myapp.test-Im1U7Kqsm8hvB13qvO5VGA==/base.apk)
at com.google.firebase.perf.v1.ApplicationInfo.<clinit>(ApplicationInfo.java:1085)
at com.google.firebase.perf.v1.ApplicationInfo.newBuilder(ApplicationInfo.java:533)
at com.google.firebase.perf.transport.TransportManager.finishInitialization(TransportManager.java:227)
at com.google.firebase.perf.transport.TransportManager.syncInit(TransportManager.java:221)
at com.google.firebase.perf.transport.TransportManager.$r8$lambda$LuAwHBxy50Yf-ziHqcD54KjEPtk(Unknown Source:0)
at com.google.firebase.perf.transport.TransportManager$$ExternalSyntheticLambda1.run(Unknown Source:2)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:920)
This Fix works for me:
Exclude protobuf-lite dependency from Kakao
androidTestImplementation ("io.github.kakaocup:kakao:3.2.3")
{
exclude module: "protobuf-lite"
}
(It's hard to reproduce. We are having like 1 flaky test in 10k runs)
Current page of ViewPager is not fully settled after end of SwipeableActions
Assertions can be made immediately after swipe action
viewPager.swipeLeft()
someChild.isCompletelyDisplayed()
--
Since TextInputLayout.hint
and TextInputLayout.error
are CharSequence
, the KTextInputLayout.hasHint()
and KTextInputLayout.hasError()
checks may fail if we assign a Spannable
instance to this attributes.
fun hasHint(hint: String) {
view.check(ViewAssertion { view, notFoundException ->
if (view is TextInputLayout) {
if (hint != view.hint) {
scrollToEnd()
in a UI testThe code
val lastView = view.findViewHolderForLayoutPosition(position)!!.itemView
view.scrollBy(0, lastView.height)
throws a NullPointerException
because lastView
is null
.
I expected the RecyclerView just to scroll down to have the last item fully visible.
override fun scrollToEnd() {
view.perform(object : ViewAction {
override fun getDescription() = "Scroll RecyclerView to the bottom"
override fun getConstraints() = ViewMatchers.isAssignableFrom(RecyclerView::class.java)
override fun perform(controller: UiController, view: View) {
if (view is RecyclerView) {
val position = view.adapter!!.itemCount - 1
view.scrollToPosition(position)
controller.loopMainThreadUntilIdle()
val lastView = view.findViewHolderForLayoutPosition(position)!!.itemView
view.scrollBy(0, lastView.height)
controller.loopMainThreadUntilIdle()
}
}
})
}
I've created an extension function to still be able to do what I'd like to do:
fun KRecyclerView.scrollToEndRepeatedly(repetitions: Int) {
view.perform(
object : ViewAction {
override fun getDescription() =
"Scroll RecyclerView to the bottom"
override fun getConstraints() =
ViewMatchers.isAssignableFrom(
RecyclerView::class.java
)
override fun perform(controller: UiController, view: View) {
if (view is RecyclerView) {
var lastViewFound = false
var tryCount = 0
do {
tryCount++
val position = view.adapter!!.itemCount - 1
view.scrollToPosition(position)
controller.loopMainThreadUntilIdle()
val lastView =
view.findViewHolderForLayoutPosition(
position
)
lastView?.let {
view.scrollBy(0, lastView.itemView.height)
lastViewFound = false
}
controller.loopMainThreadUntilIdle()
} while ((!lastViewFound) && (tryCount < repetitions))
}
}
}
)
}
While this does what it's supposed to do, I think, there must be a better solution using interceptors which fit's more naturally into Kakaos concepts, i.e. making the repetions
parameter superfluous.
The test is passing 90 percent of the time but failing randomly with below exception, as follows,
android.support.test.espresso.PerformException: Error performing 'fast swipe'
on view 'with id: my.app.package:id/my_refresh_layout'.
...
Caused by: java.lang.RuntimeException: Action will not be performed because the target view
does not match one or more of the following constraints:
at least 90 percent of the view's area is displayed to the user.
Target view: "SwipeRefreshLayout{id=2131689751, res-name=my_refresh_layout, visibility=VISIBLE,
width=480, height=672, has-focus=false, has-focusable=true, has-window-focus=true,
is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false,
is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0,
child-count=2}"
TestName: swipeToRefresh
Regards,
Vikram Singh
We haven't instrument for use TextSwitcher, please add support.
The images are considered different although they are the same
The images should be the same
withId<KImageView>(R.id.criticalErrorImage) {
hasDrawable(R.drawable.error_graphic)
}
I've tried also to create a CustomMatcher trying to compare the constantState but it fails anyway unfortunately.
I would like to have more extension to use because right now the codebase is not consistent.
We use the ext method getResourceString
to access the string, but if we would like to access the string with args or a quantity string, we have to either have our own ext or invoke InstrumentationRegistry directly.
fun getQuantityString(@PluralsRes resId: Int, quantity: Int) =
InstrumentationRegistry.getInstrumentation().targetContext.resources.getQuantityString(
resId,
quantity,
)
fun getResourceString(@StringRes resId: Int, vararg args: Any) =
InstrumentationRegistry.getInstrumentation().targetContext.resources.getString(
resId,
args,
)
Master:
io.github.kakaocup.sample.AutoCompleteTest > testContentItemsListView[emulator(AVD) - 10] FAILED
androidx.test.espresso.NoMatchingRootException: Matcher '(with decor view of type PopupWindow$PopupViewContainer)' did not match any of the following roots: [Root{application-window-token=android.view.ViewRootImpl$W@df914cb, window-token=android.view.ViewRootImpl$W@df914cb, has-window-focus=true, layout-params-type=1, layout-params-string={(0,0)(fillxfill) ty=BASE_APPLICATION wanim=0x10302fe
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
Reproduced only on 29 API
1.Edit io.github.kakaocup.sample.NestedRecyclerTest#testSingleItemTypeRecyclerView like that:
java.lang.RuntimeException: Action will not be performed because the target view does not match one or more of the following constraints:
(view has effective visibility <VISIBLE> and is descendant of a view matching (is assignable from class <class android.widget.ScrollView> or is assignable from class <class android.widget.HorizontalScrollView> or is assignable from class <class androidx.core.widget.NestedScrollView> or is assignable from class <class android.widget.ListView>))
Test doesn't fail
Hi,
This a question, rather than a bug. Is there some way I could extend Kakao (+Kakao Compose) to implement the Awaitility library ? At the moment, I need to add code like this below which pollutes my test code somewhat. I'd like to hide the await.atMost statements from the test code.
The app I'm testing needs a hybrid of Espresso, Compose and UIAutomator and I use different Page Object implementations depending on the view I'm automating.
await.atMost(TEN_SECONDS).untilAsserted {
filesCheckedTitle {
assertIsDisplayed()
assertTextEquals(title.value)
}
}
Thanks,
Pentti
Hi Team,
Actually i am trying to test the initial state of app, where app is in loading state but whenever i run the test in throws me following error, as follows,
Exception:
junit.framework.AssertionFailedError: 'is displayed on the screen to the user' doesn't match the selected view.
Expected: is displayed on the screen to the user
Got: "ProgressBar{id=2131230934, res-name=lee_progress, visibility=GONE, width=96, height=96, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@f29348d, tag=null, root-is-layout-requested=false, has-input-connection=false, x=312.0, y=676.0}"
at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:1720)
at com.kaspersky.kaspresso.failure.FailureLoggingProviderImpl.describedWith(FailureLoggingProviderImpl.kt:91)
at com.kaspersky.kaspresso.failure.FailureLoggingProviderImpl.logDescriptionAndThrow(FailureLoggingProviderImpl.kt:69)
at com.kaspersky.kaspresso.failure.LoggingFailureHandler.logDescriptionAndThrow(Unknown Source:2)
at com.kaspersky.kaspresso.failure.LoggingFailureHandler.handle(LoggingFailureHandler.kt:21)
at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:103)
at androidx.test.espresso.ViewInteraction.check(ViewInteraction.java:31)
at com.kaspersky.kaspresso.interceptors.tolibrary.kakao.KakaoViewInterceptor$interceptCheck$1.invoke(KakaoViewInterceptor.kt:29)
at com.kaspersky.kaspresso.interceptors.tolibrary.kakao.KakaoViewInterceptor$interceptCheck$1.invoke(KakaoViewInterceptor.kt:16)
at com.kaspersky.kaspresso.autoscroll.AutoScrollProviderImpl.withAutoScroll(AutoScrollProviderImpl.kt:30)
at com.kaspersky.kaspresso.interceptors.behavior.impl.autoscroll.AutoScrollViewBehaviorInterceptor.withAutoScroll(Unknown Source:12)
at com.kaspersky.kaspresso.interceptors.behavior.impl.autoscroll.AutoScrollViewBehaviorInterceptor.intercept(AutoScrollViewBehaviorInterceptor.kt:26)
at com.kaspersky.kaspresso.interceptors.behavior.impl.autoscroll.AutoScrollViewBehaviorInterceptor.intercept(AutoScrollViewBehaviorInterceptor.kt:14)
at com.kaspersky.kaspresso.interceptors.tolibrary.kakao.KakaoViewInterceptor$interceptCheck$$inlined$fold$lambda$1.invoke(KakaoViewInterceptor.kt:34)
at com.kaspersky.kaspresso.interceptors.tolibrary.kakao.KakaoViewInterceptor$interceptCheck$$inlined$fold$lambda$1.invoke(KakaoViewInterceptor.kt:16)
at com.kaspersky.kaspresso.systemsafety.SystemDialogSafetyProviderImpl.passSystemDialogs(SystemDialogSafetyProviderImpl.kt:51)
at com.kaspersky.kaspresso.interceptors.behavior.impl.systemsafety.SystemDialogSafetyViewBehaviorInterceptor.passSystemDialogs(Unknown Source:7)
at com.kaspersky.kaspresso.interceptors.behavior.impl.systemsafety.SystemDialogSafetyViewBehaviorInterceptor.intercept(SystemDialogSafetyViewBehaviorInterceptor.kt:28)
at com.kaspersky.kaspresso.interceptors.behavior.impl.systemsafety.SystemDialogSafetyViewBehaviorInterceptor.intercept(SystemDialogSafetyViewBehaviorInterceptor.kt:15)
at com.kaspersky.kaspresso.interceptors.tolibrary.kakao.KakaoViewInterceptor$interceptCheck$$inlined$fold$lambda$1.invoke(KakaoViewInterceptor.kt:34)
at com.kaspersky.kaspresso.interceptors.tolibrary.kakao.KakaoViewInterceptor$interceptCheck$$inlined$fold$lambda$1.invoke(KakaoViewInterceptor.kt:16)
at com.kaspersky.kaspresso.flakysafety.algorithm.FlakySafetyAlgorithm.invokeFlakySafely(FlakySafetyAlgorithm.kt:32)
at com.kaspersky.kaspresso.flakysafety.algorithm.FlakySafetyAlgorithm.invokeFlakySafely$default(FlakySafetyAlgorithm.kt:24)
at com.kaspersky.kaspresso.flakysafety.FlakySafetyProviderSimpleImpl.flakySafely(FlakySafetyProviderSimpleImpl.kt:27)
at com.kaspersky.kaspresso.interceptors.behavior.impl.flakysafety.FlakySafeViewBehaviorInterceptor.flakySafely(Unknown Source:7)
at com.kaspersky.kaspresso.interceptors.behavior.impl.flakysafety.FlakySafeViewBehaviorInterceptor.intercept(FlakySafeViewBehaviorInterceptor.kt:26)
at com.kaspersky.kaspresso.interceptors.behavior.impl.flakysafety.FlakySafeViewBehaviorInterceptor.intercept(FlakySafeViewBehaviorInterceptor.kt:14)
at com.kaspersky.kaspresso.interceptors.tolibrary.kakao.KakaoViewInterceptor$interceptCheck$$inlined$fold$lambda$1.invoke(KakaoViewInterceptor.kt:34)
at com.kaspersky.kaspresso.interceptors.tolibrary.kakao.KakaoViewInterceptor$interceptCheck$$inlined$fold$lambda$1.invoke(KakaoViewInterceptor.kt:16)
at com.kaspersky.kaspresso.interceptors.tolibrary.kakao.KakaoViewInterceptor.interceptCheck(KakaoViewInterceptor.kt:36)
at com.kaspersky.kaspresso.interceptors.tolibrary.LibraryInterceptorsInjector$injectKaspressoInKakao$1$1$1.invoke(LibraryInterceptorsInjector.kt:54)
at com.kaspersky.kaspresso.interceptors.tolibrary.LibraryInterceptorsInjector$injectKaspressoInKakao$1$1$1.invoke(LibraryInterceptorsInjector.kt:22)
at io.github.kakaocup.kakao.delegate.Delegate$DefaultImpls.interceptOnCheck(Delegate.kt:61)
at io.github.kakaocup.kakao.delegate.Delegate$DefaultImpls.access$interceptOnCheck(Delegate.kt:13)
at io.github.kakaocup.kakao.delegate.Delegate$interceptCheck$1.invoke(Delegate.kt:28)
at io.github.kakaocup.kakao.delegate.Delegate$DefaultImpls.interceptCheck(Delegate.kt:33)
at io.github.kakaocup.kakao.delegate.ViewInteractionDelegate.interceptCheck(ViewInteractionDelegate.kt:21)
at io.github.kakaocup.kakao.delegate.ViewInteractionDelegate.interceptCheck(ViewInteractionDelegate.kt:21)
at io.github.kakaocup.kakao.delegate.ViewInteractionDelegate.check(ViewInteractionDelegate.kt:26)
at io.github.kakaocup.kakao.common.assertions.BaseAssertions$DefaultImpls.isDisplayed(BaseAssertions.kt:36)
at io.github.kakaocup.kakao.common.views.KBaseView.isDisplayed(KBaseView.kt:34)
at reprator.wipro.factlist.test.FactListKaspressoTest$initialScreenTest$3$1$1$1.invoke(FactListKaspressoTest.kt:62)
at reprator.wipro.factlist.test.FactListKaspressoTest$initialScreenTest$3$1$1$1.invoke(FactListKaspressoTest.kt:20)
at io.github.kakaocup.kakao.common.views.KBaseView.invoke(KBaseView.kt:83)
at reprator.wipro.factlist.test.FactListKaspressoTest$initialScreenTest$3$1$1.invoke(FactListKaspressoTest.kt:61)
at reprator.wipro.factlist.test.FactListKaspressoTest$initialScreenTest$3$1$1.invoke(FactListKaspressoTest.kt:20)
at io.github.kakaocup.kakao.screen.Screen.invoke(Screen.kt:119)
at reprator.wipro.factlist.test.FactListKaspressoTest$initialScreenTest$3$1.invoke(FactListKaspressoTest.kt:59)
at reprator.wipro.factlist.test.FactListKaspressoTest$initialScreenTest$3$1.invoke(FactListKaspressoTest.kt:20)
at com.kaspersky.kaspresso.testcases.core.testcontext.TestContext.step(TestContext.kt:39)
at reprator.wipro.factlist.test.FactListKaspressoTest$initialScreenTest$3.invoke(FactListKaspressoTest.kt:56)
at reprator.wipro.factlist.test.FactListKaspressoTest$initialScreenTest$3.invoke(FactListKaspressoTest.kt:20)
at com.kaspersky.kaspresso.testcases.core.TestRunner.runMainTestSection(TestRunner.kt:144)
at com.kaspersky.kaspresso.testcases.core.TestRunner.run(TestRunner.kt:58)
at com.kaspersky.kaspresso.testcases.core.sections.MainTestSection.run(MainTestSection.kt:29)
at reprator.wipro.factlist.test.FactListKaspressoTest.initialScreenTest(FactListKaspressoTest.kt:55)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)
at androidx.test.internal.runner.junit4.statement.RunAfters.evaluate(RunAfters.java:61)
at dagger.hilt.android.internal.testing.MarkThatRulesRanRule$1.evaluate(MarkThatRulesRanRule.java:106)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:395)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2198)
Caused by: junit.framework.AssertionFailedError: 'is displayed on the screen to the user' doesn't match the selected view.
Expected: is displayed on the screen to the user
Got: "ProgressBar{id=2131230934, res-name=lee_progress, visibility=GONE, width=96, height=96, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, layout-params=android.widget.FrameLayout$LayoutParams@f29348d, tag=null, root-is-layout-requested=false, has-input-connection=false, x=312.0, y=676.0}"
at androidx.test.espresso.matcher.ViewMatchers.assertThat(ViewMatchers.java:17)
at androidx.test.espresso.assertion.ViewAssertions$MatchesViewAssertion.check(ViewAssertions.java:15)
at com.kaspersky.kaspresso.proxy.ViewAssertionProxy.check(ViewAssertionProxy.kt:26)
at androidx.test.espresso.ViewInteraction$SingleExecutionViewAssertion.check(ViewInteraction.java:10)
at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:11)
at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:2)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.Handler.handleCallback(Handler.java:914)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:225)
at android.app.ActivityThread.main(ActivityThread.java:7563)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:994)
Test Name: initialScreenTest
Kindly assist.
Regards,
Vikram Singh
%
. Ex. <string name="recording_scaling">Scaling (%%)</string>
hasText
on the KTextView with the resource idExpected: with string from resource id: <2131821564>[recording_scaling] value: Scaling (%%)
Got: "AppCompatTextView{id=2131362820, res-name=titleTextView, visibility=VISIBLE, width=220, height=48, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=androidx.constraintlayout.widget.ConstraintLayout$LayoutParams@e829a5e, tag=null, root-is-layout-requested=false, has-input-connection=false, x=16.0, y=0.0, text=Scaling (%), input-type=0, ime-target=false, has-links=false}"
<string name="recording_scaling">Scaling (%%)</string>
title.hasText(R.string.recording_scaling) // Fails
androidx.test.espresso.matcher.ViewMatchers.WithCharSequenceMatcher#matchesSafely caches text
@Override
protected boolean matchesSafely(TextView textView, Description mismatchDescription) {
if (null == expectedText) {
try {
expectedText = textView.getResources().getString(resourceId);
} catch (Resources.NotFoundException ignored) {
/* view could be from a context unaware of the resource id. */
}
resourceName = safeGetResourceEntryName(textView.getResources(), resourceId);
}
...
}
class UrlValidationScreen : Screen<UrlValidationScreen>() {
val urlInputLayout = KTextInputLayout { withId(R.id.urlInputLayout) }
}
// Assert
urlInputLayout {
hasError(null) // Will not work
}
Null cannot be passed to hasText
The hasText(String)
function allows null values.
See above
tagTextInputEditText
) and for EditText inside the TextInputEditText (tagEditText
). add to Hint any text (e.x. "hint")KTextInputLayout { withTag(tagEditText) }.hasHint("any text _"+ UUID.randomUUID())
The Test will pass
The Test should fail!
Expected an AssertionError
that EditText is not TextInputLayout
The problem is that methods check instances and do not throw an exception if it is different than expected
fun hasHint(hint: String) {
view.check(ViewAssertion { view, notFoundException ->
if (view is TextInputLayout) {
if (hint != view.hint.toString()) {
throw AssertionError(
"Expected hint is $hint," +
" but actual is ${view.hint}"
)
}
} else {
notFoundException?.let { throw AssertionError(it) } // here code should throw AssertionError("expected TextInputLayout, but got $view") if notFoundException is null
}
})
// code here
Add KImageView
test class with following:
Hi Team,
whenever i am checking for particular position in a recyclerview, it's throwing me below error, as follows,
Exception:
androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching: (is descendant of a: (view holder at 7 position of recycler view: (with id is reprator.wipro.factlist.test:id/factListRecyclerView)) and with id is <2131230883>)
View Hierarchy:
+>DecorView{id=-1, visibility=VISIBLE, width=720, height=1600, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) blurRatio=1.0 blurMode=0 ty=BASE_APPLICATION wanim=0x10302fe
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=3}
Although, i am using kaspresso but internally it's using kakao for uI testing, and even for simple kakao testing, it will fail. So need your assistance.
Test Name: childAtPosition7
Looking forward for a solution.
Regards,
Vikram Singh
withIndex(1) { withId(R.id.recyclerView) }
androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching: view holder at 0 position of recycler view: (1th view with: (view.getId() is <2131363464/com.package.name.debug:id/recyclerView>))
I am expecting it to match the children of the RecyclerView inside the second tab.
Note that matching child items of the RecyclerView inside the first tab (withIndex(0)
) works properly.
This is how I match my RecyclerViews.
// First tab RecyclerView
KRecyclerView(
builder = {
withIndex(0) {
withId(R.id.recyclerView)
}
},
itemTypeBuilder = {
itemType(::Item)
}
)
// Second tab RecyclerView
KRecyclerView(
builder = {
withIndex(1) {
withId(R.id.recyclerView)
}
},
itemTypeBuilder = {
itemType(::Item)
}
)
// Item
private class Item(parent: Matcher<View>) : KRecyclerItem<Item>(parent) {
val moreOptionsIcon = KImageView(parent) { withId(R.id.moreIcon) }
}
Is there something wrong with how it is set up? Please help.
The `kotlin-dsl` plugin applied to project ':buildSrc' enables experimental Kotlin compiler features. For more information see https://docs.gradle.org/6.7.1/userguide/kotlin_dsl.html#sec:kotlin-dsl_plugin
w: Runtime JAR files in the classpath should have the same version. These files were found in the classpath:
/Users/vacxe/.gradle/wrapper/dists/gradle-6.7.1-all/2moa8rlfac5eqlcfgk98k0deb/gradle-6.7.1/lib/kotlin-stdlib-1.3.72.jar (version 1.3)
/Users/vacxe/.gradle/wrapper/dists/gradle-6.7.1-all/2moa8rlfac5eqlcfgk98k0deb/gradle-6.7.1/lib/kotlin-stdlib-common-1.3.72.jar (version 1.3)
/Users/vacxe/.gradle/wrapper/dists/gradle-6.7.1-all/2moa8rlfac5eqlcfgk98k0deb/gradle-6.7.1/lib/kotlin-stdlib-jdk7-1.3.72.jar (version 1.3)
/Users/vacxe/.gradle/wrapper/dists/gradle-6.7.1-all/2moa8rlfac5eqlcfgk98k0deb/gradle-6.7.1/lib/kotlin-stdlib-jdk8-1.3.72.jar (version 1.3)
/Users/vacxe/.gradle/wrapper/dists/gradle-6.7.1-all/2moa8rlfac5eqlcfgk98k0deb/gradle-6.7.1/lib/kotlin-reflect-1.3.72.jar (version 1.3)
/Users/vacxe/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.4.32/3302f9ec8a5c1ed220781dbd37770072549bd333/kotlin-stdlib-jdk8-1.4.32.jar (version 1.4)
/Users/vacxe/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-reflect/1.4.31/63db9d66c3d20f7b8f66196e7ba86969daae8b8a/kotlin-reflect-1.4.31.jar (version 1.4)
/Users/vacxe/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.4.32/3546900a3ebff0c43f31190baf87a9220e37b7ea/kotlin-stdlib-jdk7-1.4.32.jar (version 1.4)
/Users/vacxe/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.4.32/461367948840adbb0839c51d91ed74ef4a9ccb52/kotlin-stdlib-1.4.32.jar (version 1.4)
/Users/vacxe/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.4.32/ef50bfa2c0491a11dcc35d9822edbfd6170e1ea2/kotlin-stdlib-common-1.4.32.jar (version 1.4)
Version 3.0.0
There is a difference between the JDK being used to build the library vs the "target" it is set to. The best practice is to set the JDK to the most up to date to get compiler benefits. But the target is better to be set at a minimum level to increase compatibility. This is similar to libraries setting Android minSdk to 21 or 23. Most Kotlin libraries are set to 11.
I see in this PR from before that 2 things are updated together:
2nd one is not needed and it creates the below incompatibility.
The following error is observed
e: ScreenExtensions.kt:33:12 Cannot inline bytecode built with JVM target 17 into bytecode that is being built with JVM target 11. Please specify proper '-jvm-target' option
Compile just fine when the host app targets JVM 11
Hi. We use Ui tests for memory leaks detektion. But we've found leak at IndexMatcher that was added in https://github.com/agoda-com/Kakao/pull/200/files
The IndexMatcher
contains link on a View
and create memory leak when we leave Activity/Fragment in test step.
screen
with using of ViewBuilder.withIndex
class TestScreen : Screen<TestScreen>() {
val testView = KView {
withIndex(0) {
...
}
}
}
testView
in test step.E/TestRunner: ----- begin exception -----
E/TestRunner: leakcanary.NoLeakAssertionFailedError: Application memory leaks were detected:
E/TestRunner: ====================================
E/TestRunner: HEAP ANALYSIS RESULT
E/TestRunner: ====================================
E/TestRunner: 1 APPLICATION LEAKS
E/TestRunner: References underlined with "~~~" are likely causes.
E/TestRunner: Learn more at https://squ.re/leaks.
E/TestRunner: 12136 bytes retained by leaking objects
E/TestRunner: Displaying only 1 leak trace out of 3 with the same signature
E/TestRunner: Signature: c7099d19e12c64f391b6157a00d3e14c2eed18a7
E/TestRunner: ┬──�
E/TestRunner: ��
E/TestRunner: │ GC Root: Input or output parameters in native code
E/TestRunner: │
E/TestRunner: ├─ com.project.android.test.mock.valuation.FlatValuationUiTest instance
E/TestRunner: │ Leaking: UNKNOWN
E/TestRunner: │ Retaining 1,5 MB in 24968 objects
E/TestRunner: │ ↓ FlatValuationUiTest.valuationScreen
E/TestRunner: │ ~~~~~~~~~~~~~~~
E/TestRunner: ├─ com.project.android.screens.FlatValuationScreen instance
E/TestRunner: │ Leaking: UNKNOWN
E/TestRunner: │ Retaining 1,5 MB in 24965 objects
E/TestRunner: │ ↓ FlatValuationScreen.salePriceView
E/TestRunner: │ ~~~~~~~~~~~~~
E/TestRunner: ├─ io.github.kakaocup.kakao.text.KTextView instance
E/TestRunner: │ Leaking: UNKNOWN
E/TestRunner: │ Retaining 1,4 MB in 24432 objects
E/TestRunner: │ ↓ KBaseView.view
E/TestRunner: │ ~~~~
E/TestRunner: ├─ io.github.kakaocup.kakao.delegate.ViewInteractionDelegate instance
E/TestRunner: │ Leaking: UNKNOWN
E/TestRunner: │ Retaining 1,4 MB in 24431 objects
E/TestRunner: │ ↓ ViewInteractionDelegate.interaction
E/TestRunner: │ ~~~~~~~~~~~
E/TestRunner: ├─ androidx.test.espresso.ViewInteraction instance
E/TestRunner: │ Leaking: UNKNOWN
E/TestRunner: │ Retaining 1,4 MB in 24430 objects
E/TestRunner: │ ↓ ViewInteraction.viewMatcher
E/TestRunner: │ ~~~~~~~~~~~
E/TestRunner: ├─ org.hamcrest.core.AllOf instance
E/TestRunner: │ Leaking: UNKNOWN
E/TestRunner: │ Retaining 1,4 MB in 24418 objects
E/TestRunner: │ ↓ AllOf.matchers
E/TestRunner: │ ~~~~~~~~
E/TestRunner: ├─ java.util.ArrayList instance
E/TestRunner: │ Leaking: UNKNOWN
E/TestRunner: │ Retaining 1,4 MB in 24417 objects
E/TestRunner: │ ↓ ArrayList[0]
E/TestRunner: │ ~~~
E/TestRunner: ├─ io.github.kakaocup.kakao.common.matchers.IndexMatcher instance
E/TestRunner: │ Leaking: UNKNOWN
E/TestRunner: │ Retaining 1,4 MB in 24415 objects
E/TestRunner: │ ↓ IndexMatcher.seen
E/TestRunner: │ ~~~~
E/TestRunner: ├─ java.util.LinkedHashSet instance
E/TestRunner: │ Leaking: UNKNOWN
E/TestRunner: │ Retaining 1,4 MB in 24407 objects
E/TestRunner: │ ↓ LinkedHashSet[element()]
E/TestRunner: │ ~~~~~~~~~~~
E/TestRunner: ╰→ android.widget.LinearLayout instance
E/TestRunner: ​ Leaking: YES (ObjectWatcher was watching this because com.project.valuation.ui.screen.flat.FlatValuationFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks) and View.mContext references a destroyed activity)
E/TestRunner: ​ Retaining 2,1 kB in 52 objects
E/TestRunner: ​ key = ea5d88bb-8313-47b4-b590-24555ab2b30a
E/TestRunner: ​ watchDurationMillis = 6078
E/TestRunner: ​ retainedDurationMillis = 1078
E/TestRunner: ​ View not part of a window view hierarchy
E/TestRunner: ​ View.mAttachInfo is null (view detached)
E/TestRunner: ​ View.mWindowAttachCount = 1
E/TestRunner: ​ mContext instance of com.project.valuation.ui.screen.flat.FlatValuationActivity with mDestroyed = true
KTabLayout.getSelectedItem
during test.Caused by: java.lang.RuntimeException: Action will not be performed because the target view does not match one or more of the following constraints:
is assignable from class: class com.google.android.material.bottomnavigation.BottomNavigationView
Target view: "TabLayout{id=2131362763, res-name=tab_layout, visibility=VISIBLE, width=1080, height=154, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=com.google.android.material.appbar.CollapsingToolbarLayout$LayoutParams@79c30d1, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=776.0, child-count=1}"
class MyScreen : Screen<MyScreen>() {
val tabs = KTabLayout { withId(R.id.tab_layout) }
}
// During test.
onScreen<MyScreen> {
val selected = tabs.getSelectedItem()
}
TabLayout
as the constraint, and cast the view to TabLayout
during iside perform
.getResourceDrawable
it will buildfunction is not found
function should be accessible, visibility hasn't changed
// code here
Tl;dr: It's possible that Kakao could be more performant by reordering matchers to apply faster matchers first.
Since Kakao wraps Espresso, Espresso's view finding mechanism is used for actions and assertions. This mechanism will always iterate through entire view hierarchy looking for all views matching the requested predicate (source).
Most matchers should be pretty fast, however some of them will also iterate some part of view hierarchy as part of their check. For example HasDescendantMatcher
or IsDescendantOfAMatcher
will both go up or down the view hierarchy looking for views that match the requested descendant/ancestor. This means complexity of those matchers is not constant, contrary to simple matchers like WithIdMatcher
. Moreover, when these matchers are nested, the overall performance decreases dramatically — for nested isDescendantOfA
matchers, Espresso will go through every view in hierarchy, first matcher will go up in hierarchy and execute the nested matcher, which will also go up the hierarchy — I believe the complexity is non-linear in that case.
This is all unavoidable to an extent, but if those slow matchers are used within composite matchers like allOf()
or anyOf()
, the developer can easily improve Espresso performance by simply putting the expensive, view-traversing matchers later on the list. That way Espresso will short-circuit as soon as it can, potentially not invoking the expensive matcher at all.
If I read the code correctly, Kakao will sometimes put the slow matcher first on the list that is effectively transformed into an allOf()
with same ordering, for example
This might look like a small change, but especially with nested matchers the performance impact can be significant — in one project with ~270 UI tests, simply putting isDescendantOfA
and hasDescendant
matchers last in allOf
calls cut total test run time in half (the project doesn't use Kakao).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.