diff --git a/toolkit/utilitynetworks/build.gradle.kts b/toolkit/utilitynetworks/build.gradle.kts index d70e98f58..3876b014c 100644 --- a/toolkit/utilitynetworks/build.gradle.kts +++ b/toolkit/utilitynetworks/build.gradle.kts @@ -16,14 +16,19 @@ * */ - plugins { - alias(libs.plugins.binary.compatibility.validator) apply true id("com.android.library") id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.plugin.compose") id("artifact-deploy") + id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") + alias(libs.plugins.binary.compatibility.validator) apply true +} + +secrets { + defaultPropertiesFileName = "secrets.defaults.properties" } + android { namespace = "com.arcgismaps.toolkit.utilitynetworks" compileSdk = libs.versions.compileSdk.get().toInt() @@ -50,14 +55,15 @@ android { } buildFeatures { compose = true + buildConfig = true } - - kotlin { - compilerOptions { - if ("Test" !in this.moduleName.get()) { - freeCompilerArgs.add("-Xexplicit-api=strict") - } - + + // If this were not an android project, we would just write `explicitApi()` in the Kotlin scope. + // but as an android project could write `freeCompilerArgs = listOf("-Xexplicit-api=strict")` + // in the kotlinOptions above, but that would enforce api rules on the test code, which we don't want. + tasks.withType { + if ("Test" !in name) { + kotlinOptions.freeCompilerArgs += "-Xexplicit-api=strict" } } @@ -100,6 +106,8 @@ dependencies { implementation(libs.androidx.activity.compose) implementation(libs.androidx.compose.navigation) testImplementation(libs.bundles.unitTest) + androidTestImplementation(libs.truth) + androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.bundles.composeTest) debugImplementation(libs.bundles.debug) } diff --git a/toolkit/utilitynetworks/src/androidTest/java/com/arcgismaps/toolkit/utilitynetworks/ExampleInstrumentedTest.kt b/toolkit/utilitynetworks/src/androidTest/java/com/arcgismaps/toolkit/utilitynetworks/ExampleInstrumentedTest.kt deleted file mode 100644 index 9249a33de..000000000 --- a/toolkit/utilitynetworks/src/androidTest/java/com/arcgismaps/toolkit/utilitynetworks/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Copyright 2024 Esri - * - * 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 com.arcgismaps.toolkit.utilitynetworks - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import org.junit.Assert.* -import org.junit.Test -import org.junit.runner.RunWith - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.arcgismaps.toolkit.utilitynetwork.test", appContext.packageName) - } -} diff --git a/toolkit/utilitynetworks/src/androidTest/java/com/arcgismaps/toolkit/utilitynetworks/TraceToolTestRunner.kt b/toolkit/utilitynetworks/src/androidTest/java/com/arcgismaps/toolkit/utilitynetworks/TraceToolTestRunner.kt new file mode 100644 index 000000000..15c597f66 --- /dev/null +++ b/toolkit/utilitynetworks/src/androidTest/java/com/arcgismaps/toolkit/utilitynetworks/TraceToolTestRunner.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2024 Esri + * + * 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 com.arcgismaps.toolkit.utilitynetworks + +import com.arcgismaps.ArcGISEnvironment +import com.arcgismaps.httpcore.authentication.TokenCredential +import com.arcgismaps.mapping.ArcGISMap +import com.arcgismaps.mapping.PortalItem +import com.arcgismaps.portal.Portal +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Before + +/** + * A test runner for utility network tests. This class is responsible for loading the map with the + * given [url] and the first UtilityNetwork + * If the map fails to load or the UtilityNetwork is not found, the test will fail. + * + * @property url The URL of the web map. + * @property itemId the item id on agol to load as a webmap + * @since 200.6.0 + */ +open class TraceToolTestRunner( + private val url: String, + private val itemId: String +) { + /** + * The trace tool TraceState object + */ + private var _traceState: TraceState? = null + internal val traceState: TraceState + get() = _traceState ?: throw IllegalStateException("trace state is not initialized") + + @Before + fun setup(): Unit = runTest { + // If the utility network is already initialized, return + if (_traceState != null) return@runTest + // Set the authentication challenge handler + val tokenCred = + TokenCredential.create( + url, + username = BuildConfig.traceToolUser, + password = BuildConfig.traceToolPassword + ).getOrThrow() + + ArcGISEnvironment.authenticationManager.arcGISCredentialStore.add(tokenCred) + + val map = ArcGISMap( + PortalItem( + Portal.arcGISOnline(connection = Portal.Connection.Anonymous), + itemId + ) + ) + _traceState = TraceState(map, coroutineScope = TestScope()) + } +} diff --git a/toolkit/utilitynetworks/src/androidTest/java/com/arcgismaps/toolkit/utilitynetworks/TraceToolTests.kt b/toolkit/utilitynetworks/src/androidTest/java/com/arcgismaps/toolkit/utilitynetworks/TraceToolTests.kt new file mode 100644 index 000000000..802472ec0 --- /dev/null +++ b/toolkit/utilitynetworks/src/androidTest/java/com/arcgismaps/toolkit/utilitynetworks/TraceToolTests.kt @@ -0,0 +1,65 @@ +/* + * + * Copyright 2024 Esri + * + * 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 com.arcgismaps.toolkit.utilitynetworks + +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithContentDescription +import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class TraceToolTests : TraceToolTestRunner( + url = "https://sampleserver7.arcgisonline.com/portal/sharing/rest", + itemId = "471eb0bf37074b1fbb972b1da70fb310" +) { + + @get:Rule + val composeTestRule = createComposeRule() + + @Before + fun setContent() = runTest { + composeTestRule.setContent { + Trace( + traceState = traceState + ) + } + } + + /** + * Given a Trace composable + * When it is rendered + * Then the top level Surface exists + * + * @since 200.6.0 + */ + @Test + fun testTraceToolSurface() { + val surface = composeTestRule.onNodeWithContentDescription(traceSurfaceContentDescription) + surface.assertExists("the base surface of the Trace tool composable does not exist") + } +} diff --git a/toolkit/utilitynetworks/src/main/AndroidManifest.xml b/toolkit/utilitynetworks/src/main/AndroidManifest.xml index 73e6dbaf1..12e88bf3d 100644 --- a/toolkit/utilitynetworks/src/main/AndroidManifest.xml +++ b/toolkit/utilitynetworks/src/main/AndroidManifest.xml @@ -18,5 +18,5 @@ --> - + diff --git a/toolkit/utilitynetworks/src/main/java/com/arcgismaps/toolkit/utilitynetworks/Trace.kt b/toolkit/utilitynetworks/src/main/java/com/arcgismaps/toolkit/utilitynetworks/Trace.kt index 92b34e293..a75e293d7 100644 --- a/toolkit/utilitynetworks/src/main/java/com/arcgismaps/toolkit/utilitynetworks/Trace.kt +++ b/toolkit/utilitynetworks/src/main/java/com/arcgismaps/toolkit/utilitynetworks/Trace.kt @@ -25,11 +25,15 @@ import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.compose.rememberNavController import com.arcgismaps.toolkit.utilitynetworks.ui.TraceNavHost +internal const val traceSurfaceContentDescription: String = "trace component surface" + /** * A composable UI component to set up and run a [com.arcgismaps.utilitynetworks.UtilityNetwork.trace] * on a [com.arcgismaps.toolkit.geoviewcompose.MapView]. @@ -40,12 +44,17 @@ import com.arcgismaps.toolkit.utilitynetworks.ui.TraceNavHost public fun Trace( traceState: TraceState, @Suppress("unused_parameter") - modifier: Modifier = Modifier, + modifier: Modifier = Modifier ) { val configs = traceState.traceConfigurations.collectAsStateWithLifecycle() - // if the traceConfigurations are not available, that means the traceState is not ready so return - if (configs.value == null) { - Surface(modifier = Modifier.fillMaxSize()) { + + Surface( + color = MaterialTheme.colorScheme.surface, + modifier = Modifier + .fillMaxSize() + .semantics { contentDescription = traceSurfaceContentDescription } + ) { + if (configs.value == null) { Box( modifier = Modifier .size(100.dp), @@ -53,16 +62,8 @@ public fun Trace( ) { CircularProgressIndicator() } - } - } else { - - val navController = rememberNavController() - - Surface( - color = MaterialTheme.colorScheme.surface, - modifier = Modifier - .fillMaxSize() - ) { + } else { + val navController = rememberNavController() TraceNavHost(navController, traceState) } } diff --git a/toolkit/utilitynetworks/src/test/java/com/arcgismaps/toolkit/utilitynetworks/ExampleUnitTest.kt b/toolkit/utilitynetworks/src/test/java/com/arcgismaps/toolkit/utilitynetworks/ExampleUnitTest.kt deleted file mode 100644 index f3bbb6b23..000000000 --- a/toolkit/utilitynetworks/src/test/java/com/arcgismaps/toolkit/utilitynetworks/ExampleUnitTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Copyright 2024 Esri - * - * 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 com.arcgismaps.toolkit.utilitynetworks - -import org.junit.Assert.assertEquals -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -}