From 2242b8a1dc8a825860b0f3ccf0c56aee7a10d057 Mon Sep 17 00:00:00 2001 From: mlykotom Date: Mon, 21 Nov 2022 10:48:12 +0100 Subject: [PATCH] Fix waiting for content --- .../test/uiautomator/UiAutomatorHelpers.kt | 48 +++++++++++++++++++ .../apps/nowinandroid/foryou/ForYouActions.kt | 9 ++-- .../feature/foryou/ForYouScreen.kt | 16 +++---- 3 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 benchmarks/src/main/java/androidx/test/uiautomator/UiAutomatorHelpers.kt diff --git a/benchmarks/src/main/java/androidx/test/uiautomator/UiAutomatorHelpers.kt b/benchmarks/src/main/java/androidx/test/uiautomator/UiAutomatorHelpers.kt new file mode 100644 index 000000000..e0bd3ff4a --- /dev/null +++ b/benchmarks/src/main/java/androidx/test/uiautomator/UiAutomatorHelpers.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.test.uiautomator + +import androidx.test.uiautomator.HasChildrenOp.AT_LEAST +import androidx.test.uiautomator.HasChildrenOp.AT_MOST +import androidx.test.uiautomator.HasChildrenOp.EXACTLY + +// These helpers need to be in the androidx.test.uiautomator package, +// because the abstract class has package local method that needs to be implemented. + +/** + * Condition will be satisfied if given element has specified count of children + */ +fun untilHasChildren( + childCount: Int = 1, + op: HasChildrenOp = AT_LEAST +): UiObject2Condition { + return object : UiObject2Condition() { + override fun apply(element: UiObject2): Boolean { + return when (op) { + AT_LEAST -> element.childCount >= childCount + EXACTLY -> element.childCount == childCount + AT_MOST -> element.childCount < childCount + } + } + } +} + +enum class HasChildrenOp { + AT_LEAST, + EXACTLY, + AT_MOST +} diff --git a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt index abdf9e6be..9fd9b76b1 100644 --- a/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt +++ b/benchmarks/src/main/java/com/google/samples/apps/nowinandroid/foryou/ForYouActions.kt @@ -18,12 +18,15 @@ package com.google.samples.apps.nowinandroid.foryou import androidx.benchmark.macro.MacrobenchmarkScope import androidx.test.uiautomator.By -import androidx.test.uiautomator.Until +import androidx.test.uiautomator.Direction.RIGHT +import androidx.test.uiautomator.untilHasChildren import com.google.samples.apps.nowinandroid.flingElementDownUp +import kotlin.random.Random.Default.nextInt fun MacrobenchmarkScope.forYouWaitForContent() { - // Wait until content is loaded - device.wait(Until.hasObject(By.text("What are you interested in?")), 30_000) + // Wait until content is loaded by checking if authors are loaded + val obj = device.findObject(By.res("forYou:authors")) + obj.wait(untilHasChildren(), 30_000) } fun MacrobenchmarkScope.forYouSelectAuthors() { diff --git a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index 34325ae93..ae722b8ef 100644 --- a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -126,15 +126,13 @@ internal fun ForYouScreen( onNewsResourcesCheckedChanged: (String, Boolean) -> Unit, modifier: Modifier = Modifier, ) { + val onboardingLoading = onboardingUiState is OnboardingUiState.Loading + val feedLoading = feedState is NewsFeedUiState.Loading // Workaround to call Activity.reportFullyDrawn from Jetpack Compose. // This code should be called when the UI is ready for use // and relates to Time To Full Display. - val onboardingLoaded = - onboardingUiState !is OnboardingUiState.Loading - val feedLoaded = feedState !is NewsFeedUiState.Loading - - if (onboardingLoaded && feedLoaded) { + if (!isSyncing && !onboardingLoading && !feedLoading) { val localView = LocalView.current // We use Unit to call reportFullyDrawn only on the first recomposition, // however it will be called again if this composable goes out of scope. @@ -196,9 +194,7 @@ internal fun ForYouScreen( } } AnimatedVisibility( - visible = isSyncing || - feedState is NewsFeedUiState.Loading || - onboardingUiState is OnboardingUiState.Loading, + visible = isSyncing || feedLoading || onboardingLoading, enter = slideInVertically( initialOffsetY = { fullHeight -> -fullHeight }, ) + fadeIn(), @@ -211,7 +207,9 @@ internal fun ForYouScreen( modifier = Modifier.fillMaxWidth() ) { NiaOverlayLoadingWheel( - modifier = Modifier.align(Alignment.Center), + modifier = Modifier + .align(Alignment.Center) + .testTag("forYou:loadingWheel"), contentDesc = loadingContentDescription ) }