TestOwner.kt
/*
* Copyright 2020 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
*
* http://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.compose.ui.test
import androidx.compose.ui.node.Owner
import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.semantics.getAllSemanticsNodes
import androidx.compose.ui.test.PersistingInputDispatcher.InputDispatcherState
import androidx.compose.ui.text.input.EditOperation
import androidx.compose.ui.text.input.ImeAction
/**
* Provides necessary services to facilitate testing.
*
* This is typically implemented by entities like test rule.
*/
@InternalTestingApi
interface TestOwner {
/**
* Sends the given list of text commands to the given semantics node.
*/
fun sendTextInputCommand(node: SemanticsNode, command: List<EditOperation>)
/**
* Sends the given IME action to the given semantics node.
*/
fun sendImeAction(node: SemanticsNode, actionSpecified: ImeAction)
/**
* Runs the given [action] on the ui thread.
*
* This is a blocking call.
*/
// TODO: Does ui-test really need it? Can it use coroutine context on Owner?
fun <T> runOnUiThread(action: () -> T): T
/**
* Collects all [Owner]s from all compose hierarchies.
*
* This is a blocking call. Returns only after compose is idle.
*
* Can crash in case it hits time out. This is not supposed to be handled as it
* surfaces only in incorrect tests.
*/
fun getOwners(): Set<Owner>
}
/**
* Collects all [SemanticsNode]s from all compose hierarchies.
*
* This is a blocking call. Returns only after compose is idle.
*
* Can crash in case it hits time out. This is not supposed to be handled as it
* surfaces only in incorrect tests.
*/
@OptIn(InternalTestingApi::class)
internal fun TestOwner.getAllSemanticsNodes(useUnmergedTree: Boolean): List<SemanticsNode> {
return getOwners().flatMap { it.semanticsOwner.getAllSemanticsNodes(useUnmergedTree) }
}
@InternalTestingApi
fun createTestContext(owner: TestOwner): TestContext {
return TestContext(owner)
}
@OptIn(InternalTestingApi::class)
class TestContext internal constructor(internal val testOwner: TestOwner) {
/**
* Stores the [InputDispatcherState] of each [Owner]. The state will be restored in an
* [InputDispatcher] when it is created for an owner that has a state stored.
*/
internal val states = mutableMapOf<Owner, InputDispatcherState>()
internal fun getAllSemanticsNodes(mergingEnabled: Boolean) =
testOwner.getAllSemanticsNodes(mergingEnabled)
}