diff --git a/src/main/kotlin/org/briarproject/briar/desktop/Main.kt b/src/main/kotlin/org/briarproject/briar/desktop/Main.kt
index c922146d59965f19569f421f3847039e27688cc4..5b1f9a998c6f19ef555c3e95cc0f111f62b16cd2 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/Main.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/Main.kt
@@ -1,6 +1,7 @@
 package org.briarproject.briar.desktop
 
 import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.window.application
 import com.github.ajalt.clikt.core.CliktCommand
 import com.github.ajalt.clikt.parameters.options.counted
 import com.github.ajalt.clikt.parameters.options.default
@@ -63,7 +64,9 @@ private class Main : CliktCommand(
         BrambleCoreEagerSingletons.Helper.injectEagerSingletons(app)
         BriarCoreEagerSingletons.Helper.injectEagerSingletons(app)
 
-        app.getBriarUi().start()
+        application {
+            app.getBriarUi().start(this)
+        }
     }
 
     private fun getDataDir(): Path {
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt b/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt
index 3d46cd5d7ce2685ec0e1dd18e9f64131bcedff7d..b2bbafbf3c5a4967bced65d401983f34db2bf44c 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt
@@ -1,11 +1,12 @@
 package org.briarproject.briar.desktop.ui
 
+import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
+import androidx.compose.ui.window.ApplicationScope
 import androidx.compose.ui.window.Window
-import androidx.compose.ui.window.application
 import org.briarproject.bramble.api.account.AccountManager
 import org.briarproject.bramble.api.lifecycle.LifecycleManager
 import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING
@@ -34,7 +35,8 @@ enum class Screen {
 
 interface BriarUi {
 
-    fun start()
+    @Composable
+    fun start(applicationScope: ApplicationScope)
 
     fun stop()
 }
@@ -67,51 +69,51 @@ constructor(
         }
     }
 
-    override fun start() {
-        application {
-            val (isDark, setDark) = remember { mutableStateOf(true) }
-            val title = i18n("main.title")
-            var screenState by remember {
-                mutableStateOf(
-                    if (accountManager.hasDatabaseKey()) {
-                        // this should only happen during testing when we launch the main UI directly
-                        // without a need to enter the password.
-                        contactListViewModel.loadContacts()
-                        Screen.MAIN
-                    } else if (accountManager.accountExists()) {
-                        Screen.LOGIN
-                    } else {
-                        Screen.REGISTRATION
-                    }
-                )
-            }
-            Window(
-                title = title,
-                onCloseRequest = { stop(); exitApplication() },
-            ) {
-                window.minimumSize = Dimension(800, 600)
-                BriarTheme(isDarkTheme = isDark) {
-                    when (screenState) {
-                        Screen.REGISTRATION ->
-                            Registration(registrationViewModel) {
-                                screenState = Screen.MAIN
-                            }
-                        Screen.LOGIN ->
-                            Login(loginViewModel) {
-                                contactListViewModel.loadContacts()
-                                screenState = Screen.MAIN
-                            }
-                        else ->
-                            MainScreen(
-                                contactListViewModel,
-                                conversationViewModel,
-                                addContactViewModel,
-                                introductionViewModel,
-                                sidebarViewModel,
-                                isDark,
-                                setDark
-                            )
-                    }
+    @Composable
+    override fun start(applicationScope: ApplicationScope) {
+        val (isDark, setDark) = remember { mutableStateOf(true) }
+        val title = i18n("main.title")
+        var screenState by remember {
+            mutableStateOf(
+                if (accountManager.hasDatabaseKey()) {
+                    // this should only happen during testing when we launch the main UI directly
+                    // without a need to enter the password.
+                    contactListViewModel.loadContacts()
+                    Screen.MAIN
+                } else if (accountManager.accountExists()) {
+                    Screen.LOGIN
+                } else {
+                    Screen.REGISTRATION
+                }
+            )
+        }
+        Window(
+            title = title,
+            onCloseRequest = { stop(); applicationScope.exitApplication() },
+        ) {
+            window.minimumSize = Dimension(800, 600)
+            BriarTheme(isDarkTheme = isDark) {
+                when (screenState) {
+                    Screen.REGISTRATION ->
+                        Registration(registrationViewModel) {
+                            contactListViewModel.loadContacts()
+                            screenState = Screen.MAIN
+                        }
+                    Screen.LOGIN ->
+                        Login(loginViewModel) {
+                            contactListViewModel.loadContacts()
+                            screenState = Screen.MAIN
+                        }
+                    else ->
+                        MainScreen(
+                            contactListViewModel,
+                            conversationViewModel,
+                            addContactViewModel,
+                            introductionViewModel,
+                            sidebarViewModel,
+                            isDark,
+                            setDark
+                        )
                 }
             }
         }
diff --git a/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt b/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt
index 280dcef78d68238ac474d73059ef31aa23c2bb4b..13370267c3eab041ee2a993963da627fa5b85560 100644
--- a/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt
+++ b/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt
@@ -1,6 +1,7 @@
 package org.briarproject.briar.desktop
 
 import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.window.application
 import org.briarproject.bramble.BrambleCoreEagerSingletons
 import org.briarproject.briar.BriarCoreEagerSingletons
 import org.briarproject.briar.desktop.utils.FileUtils
@@ -56,7 +57,9 @@ internal class RunWithTemporaryAccount(val customization: BriarDesktopTestApp.()
         // list yet, we need to wait a moment in order for that to finish (hopefully).
         Thread.sleep(1000)
 
-        app.getBriarUi().start()
+        application {
+            app.getBriarUi().start(this)
+        }
     }
 
     private fun getDataDir(): Path {
diff --git a/src/test/kotlin/org/briarproject/briar/desktop/TestWithTwoTemporaryAccounts.kt b/src/test/kotlin/org/briarproject/briar/desktop/TestWithTwoTemporaryAccounts.kt
new file mode 100644
index 0000000000000000000000000000000000000000..88a3ab6770f3aed3a2136e04f4bf98112151e55f
--- /dev/null
+++ b/src/test/kotlin/org/briarproject/briar/desktop/TestWithTwoTemporaryAccounts.kt
@@ -0,0 +1,85 @@
+package org.briarproject.briar.desktop
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.window.ApplicationScope
+import androidx.compose.ui.window.application
+import org.briarproject.bramble.BrambleCoreEagerSingletons
+import org.briarproject.briar.BriarCoreEagerSingletons
+import org.briarproject.briar.desktop.utils.FileUtils
+import java.io.IOException
+import java.nio.file.Files
+import java.nio.file.Path
+import java.util.logging.Level.INFO
+import java.util.logging.LogManager
+import java.util.logging.Logger
+import kotlin.io.path.absolute
+
+fun main(args: Array<String>) = TestWithTwoTemporaryAccounts().run()
+
+internal class TestWithTwoTemporaryAccounts() {
+
+    companion object {
+        private val LOG = Logger.getLogger(TestWithTwoTemporaryAccounts::class.java.name)
+    }
+
+    @OptIn(ExperimentalComposeUiApi::class)
+    fun run() {
+        LogManager.getLogManager().getLogger("").level = INFO
+
+        application {
+            app(this, "alice")
+            app(this, "bob")
+        }
+    }
+
+    @Composable
+    private fun app(applicationScope: ApplicationScope, name: String) {
+        val dataDir = getDataDir()
+        LOG.info("Using data directory '$dataDir'")
+
+        val app =
+            DaggerBriarDesktopTestApp.builder().desktopTestModule(
+                DesktopTestModule(dataDir.toFile())
+            ).build()
+
+        app.getShutdownManager().addShutdownHook {
+            LOG.info("deleting temporary account at $dataDir")
+            org.apache.commons.io.FileUtils.deleteDirectory(dataDir.toFile())
+        }
+
+        // We need to load the eager singletons directly after making the
+        // dependency graphs
+        BrambleCoreEagerSingletons.Helper.injectEagerSingletons(app)
+        BriarCoreEagerSingletons.Helper.injectEagerSingletons(app)
+
+        val lifecycleManager = app.getLifecycleManager()
+        val accountManager = app.getAccountManager()
+
+        val password = "verySecret123!"
+        accountManager.createAccount(name, password)
+
+        val dbKey = accountManager.databaseKey ?: throw AssertionError()
+        lifecycleManager.startServices(dbKey)
+        lifecycleManager.waitForStartup()
+
+        app.getDeterministicTestDataCreator().createTestData(5, 20, 50)
+
+        // Creating test data happens on a background thread. As we do not get notified about updates to the conact
+        // list yet, we need to wait a moment in order for that to finish (hopefully).
+        Thread.sleep(1000)
+
+        app.getBriarUi().start(applicationScope)
+    }
+
+    private fun getDataDir(): Path {
+        val dataDir = Files.createTempDirectory("briar")
+        if (!Files.exists(dataDir)) {
+            throw IOException("Could not create directory: ${dataDir.absolute()}")
+        } else if (!Files.isDirectory(dataDir)) {
+            throw IOException("Data dir is not a directory: ${dataDir.absolute()}")
+        }
+        FileUtils.setRWX(dataDir)
+        return dataDir
+    }
+}