diff --git a/briar-desktop/build.gradle.kts b/briar-desktop/build.gradle.kts index a556646720367fdcf0dcbf4793f66065d115bbbb..a02b157bf1622691ff1a455bdaf86feca0fea11e 100644 --- a/briar-desktop/build.gradle.kts +++ b/briar-desktop/build.gradle.kts @@ -122,6 +122,9 @@ dependencies { testImplementation(project(path = ":bramble-core", configuration = "testOutput")) testImplementation("commons-io:commons-io:2.11.0") kaptTest("com.google.dagger:dagger-compiler:$daggerVersion") + + @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class) + testImplementation(compose.uiTestJUnit4) } // hacky fix for upstream issue when selecting skiko in gradle @@ -134,7 +137,9 @@ configurations.all { } tasks.test { - useTestNG() + // todo: both cannot be used at once, we probably have to split tests into UI (Compose, JUnit) and Kotlin code (testNG) + useJUnit() + // useTestNG() } tasks.withType<KotlinCompile> { diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt index 78a179ea7829394a66f4b71d8c8bcb6ab7f99d69..b7502bb51928b511048c98061c17bde4168fd3f2 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt @@ -42,6 +42,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag import androidx.compose.ui.unit.dp import org.briarproject.briar.desktop.expiration.ExpirationUtils.periodicallyCheckIfExpired import org.briarproject.briar.desktop.theme.warningBackground @@ -112,7 +113,7 @@ fun ExpirationBanner( icon = Icons.Filled.Close, contentDescription = i18n("hide"), onClick = hide, - modifier = Modifier.padding(vertical = 4.dp) + modifier = Modifier.padding(vertical = 4.dp).testTag("close_expiration") ) } } diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt index e528ff6c69c61f72bd10be5f1191d047a4418abe..917d5f25595693a5be333b535c7b0e229208248f 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt @@ -83,6 +83,9 @@ interface BriarUi { fun start(onClose: () -> Unit) fun stop() + + @Composable + fun content() } val LocalWindowScope = staticCompositionLocalOf<FrameWindowScope?> { null } @@ -117,7 +120,6 @@ constructor( } } - @OptIn(ExperimentalFoundationApi::class) @Composable override fun start(onClose: () -> Unit) { val focusState = remember { WindowFocusState() } @@ -208,10 +210,6 @@ constructor( CompositionLocalProvider( LocalWindowScope provides this, LocalWindowFocusState provides focusState, - LocalViewModelProvider provides viewModelProvider, - LocalAvatarManager provides avatarManager, - LocalConfiguration provides configuration, - LocalTextContextMenu provides BriarTextContextMenu, ) { // invalidate whole application window in case the theme, language or UI scale // setting is changed @@ -222,16 +220,29 @@ constructor( window.minimumSize = DensityDimension(800, 600, configuration) window.preferredSize = DensityDimension(800, 600, configuration) - val isDarkTheme = configuration.theme == DARK || - (configuration.theme == AUTO && isSystemInDarkTheme()) - BriarTheme(isDarkTheme, configuration.uiScale) { - Column(Modifier.fillMaxSize()) { - ExpirationBanner { screenState = EXPIRED; stop() } - when (screenState) { - STARTUP -> StartupScreen() - MAIN -> MainScreen() - EXPIRED -> ErrorScreen(i18n("startup.failed.expired")) - } + content() + } + } + } + + @OptIn(ExperimentalFoundationApi::class) + @Composable + override fun content() { + CompositionLocalProvider( + LocalViewModelProvider provides viewModelProvider, + LocalConfiguration provides configuration, + LocalAvatarManager provides avatarManager, + LocalTextContextMenu provides BriarTextContextMenu, + ) { + val isDarkTheme = configuration.theme == DARK || + (configuration.theme == AUTO && isSystemInDarkTheme()) + BriarTheme(isDarkTheme) { + Column(Modifier.fillMaxSize()) { + ExpirationBanner { screenState = EXPIRED; stop() } + when (screenState) { + STARTUP -> StartupScreen() + MAIN -> MainScreen() + EXPIRED -> ErrorScreen(i18n("startup.failed.expired")) } } } diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/ScreenshotTest.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/ScreenshotTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..b24d4cb7fe4081fec4b86daebbc60981e49d5f66 --- /dev/null +++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/ScreenshotTest.kt @@ -0,0 +1,65 @@ +/* + * Briar Desktop + * Copyright (C) 2021-2022 The Briar Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package org.briarproject.briar.desktop + +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.runDesktopComposeUiTest +import org.briarproject.bramble.BrambleCoreEagerSingletons +import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT +import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT +import org.briarproject.briar.BriarCoreEagerSingletons +import org.briarproject.briar.desktop.TestUtils.getDataDir +import org.jetbrains.skia.Image +import org.junit.Test +import java.io.FileOutputStream + +@OptIn(ExperimentalTestApi::class) +class ScreenshotTest { + @Test + fun makeScreenshot() = runDesktopComposeUiTest(700, 500) { + val dataDir = getDataDir() + val app = + DaggerBriarDesktopTestApp.builder().desktopCoreModule( + DesktopCoreModule(dataDir, DEFAULT_SOCKS_PORT, DEFAULT_CONTROL_PORT) + ).build() + // We need to load the eager singletons directly after making the + // dependency graphs + BrambleCoreEagerSingletons.Helper.injectEagerSingletons(app) + BriarCoreEagerSingletons.Helper.injectEagerSingletons(app) + + val ui = app.getBriarUi() + + setContent { + ui.content() + } + captureToImage().save("before-click.png") + onNodeWithTag("close_expiration").performClick() + captureToImage().save("after-click.png") + } +} + +private fun Image.save(file: String) { + encodeToData()?.bytes?.let { bytes -> + FileOutputStream(file).use { out -> + out.write(bytes) + } + } +}