From 445f68a6ec30617d4038562768784c9c979fb7ff Mon Sep 17 00:00:00 2001 From: "babichev.a" Date: Wed, 6 Nov 2024 22:23:22 +0400 Subject: [PATCH] fixing paging, TODO fix MainViewModelTest --- .../com/softartdev/notedelight/MainPreview.kt | 9 ++--- .../softartdev/notedelight/ui/MainScreen.kt | 15 +++++++-- .../com/softartdev/notedelight/ui/NoteList.kt | 13 ++++++-- .../presentation/main/MainViewModelTest.kt | 33 ++++++++++--------- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/android-compose-app/src/main/java/com/softartdev/notedelight/MainPreview.kt b/android-compose-app/src/main/java/com/softartdev/notedelight/MainPreview.kt index 748f4807..ba3bb912 100644 --- a/android-compose-app/src/main/java/com/softartdev/notedelight/MainPreview.kt +++ b/android-compose-app/src/main/java/com/softartdev/notedelight/MainPreview.kt @@ -4,6 +4,7 @@ import android.content.res.Configuration.UI_MODE_NIGHT_YES import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import com.softartdev.notedelight.ui.NoteDetailBody +import com.softartdev.notedelight.ui.PreviewMainScreen import com.softartdev.notedelight.ui.SignInScreenBody import com.softartdev.notedelight.ui.SplashScreenBody import com.softartdev.theme.material3.PreferableMaterialTheme @@ -11,11 +12,11 @@ import com.softartdev.theme.material3.PreferableMaterialTheme @Preview(showBackground = true, showSystemUi = true) @Composable fun PreviewNoteDetailBodyLight() = PreferableMaterialTheme { NoteDetailBody() } -/*TODO + @Preview(showBackground = true, showSystemUi = true) @Composable fun DefaultPreviewLight() = PreferableMaterialTheme { PreviewMainScreen() } -*/ + @Preview(showBackground = true, showSystemUi = true) @Composable fun PreviewSignInScreenLight() = PreferableMaterialTheme { SignInScreenBody() } @@ -27,11 +28,11 @@ fun PreviewSplashScreenLight() = PreferableMaterialTheme { SplashScreenBody(true @Preview(showBackground = true, showSystemUi = true, uiMode = UI_MODE_NIGHT_YES) @Composable fun PreviewNoteDetailBodyDark() = PreferableMaterialTheme { NoteDetailBody() } -/*TODO + @Preview(showBackground = true, showSystemUi = true, uiMode = UI_MODE_NIGHT_YES) @Composable fun DefaultPreviewDark() = PreferableMaterialTheme { PreviewMainScreen() } -*/ + @Preview(showBackground = true, showSystemUi = true, uiMode = UI_MODE_NIGHT_YES) @Composable fun PreviewSignInScreenDark() = PreferableMaterialTheme { SignInScreenBody() } diff --git a/shared-compose-ui/src/commonMain/kotlin/com/softartdev/notedelight/ui/MainScreen.kt b/shared-compose-ui/src/commonMain/kotlin/com/softartdev/notedelight/ui/MainScreen.kt index 22b0be45..207e56f6 100644 --- a/shared-compose-ui/src/commonMain/kotlin/com/softartdev/notedelight/ui/MainScreen.kt +++ b/shared-compose-ui/src/commonMain/kotlin/com/softartdev/notedelight/ui/MainScreen.kt @@ -2,6 +2,7 @@ package com.softartdev.notedelight.ui +import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding @@ -19,18 +20,24 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.contentDescription +import androidx.paging.PagingData import app.cash.paging.compose.LazyPagingItems import app.cash.paging.compose.collectAsLazyPagingItems import com.softartdev.notedelight.shared.db.Note +import com.softartdev.notedelight.shared.db.TestSchema import com.softartdev.notedelight.shared.presentation.main.MainViewModel import com.softartdev.notedelight.shared.presentation.main.NoteListResult +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf import notedelight.shared_compose_ui.generated.resources.Res import notedelight.shared_compose_ui.generated.resources.app_name import notedelight.shared_compose_ui.generated.resources.create_note @@ -100,13 +107,15 @@ fun MainScreen( }, snackbarHost = { SnackbarHost(snackbarHostState) }, ) -/*TODO + @Preview @Composable fun PreviewMainScreen() { val testNotes = listOf(TestSchema.firstNote, TestSchema.secondNote, TestSchema.thirdNote) + val pagingData: PagingData = PagingData.from(testNotes) + val pagingFlow: Flow> = flowOf(pagingData) val noteListState: MutableState = remember { - mutableStateOf(NoteListResult.Success(testNotes)) + mutableStateOf(NoteListResult.Success(pagingFlow)) } MainScreen(noteListState) -}*/ \ No newline at end of file +} diff --git a/shared-compose-ui/src/commonMain/kotlin/com/softartdev/notedelight/ui/NoteList.kt b/shared-compose-ui/src/commonMain/kotlin/com/softartdev/notedelight/ui/NoteList.kt index 20445025..3d5bd44a 100644 --- a/shared-compose-ui/src/commonMain/kotlin/com/softartdev/notedelight/ui/NoteList.kt +++ b/shared-compose-ui/src/commonMain/kotlin/com/softartdev/notedelight/ui/NoteList.kt @@ -1,13 +1,20 @@ package com.softartdev.notedelight.ui +import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.LinearProgressIndicator import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.paging.PagingData import app.cash.paging.compose.LazyPagingItems +import app.cash.paging.compose.collectAsLazyPagingItems import com.softartdev.notedelight.shared.db.Note +import com.softartdev.notedelight.shared.db.TestSchema.firstNote +import com.softartdev.notedelight.shared.db.TestSchema.secondNote +import com.softartdev.notedelight.shared.db.TestSchema.thirdNote +import kotlinx.coroutines.flow.flowOf @Composable fun NoteList( @@ -24,14 +31,14 @@ fun NoteList( } } } -/*TODO + @Preview @Composable fun PreviewNoteList() { val lorem = StringBuilder().apply { repeat(100) { append("lorem ipsum ") } }.toString() val longTitleNote = secondNote.copy(title = lorem) val testNotes: List = listOf(firstNote, secondNote, thirdNote, longTitleNote) + val pagingItems = flowOf(PagingData.from(testNotes)).collectAsLazyPagingItems() val onItemClicked: (id: Long) -> Unit = {} - NoteList(testNotes, onItemClicked) + NoteList(pagingItems, onItemClicked) } -*/ \ No newline at end of file diff --git a/shared/src/androidUnitTest/kotlin/com/softartdev/notedelight/shared/presentation/main/MainViewModelTest.kt b/shared/src/androidUnitTest/kotlin/com/softartdev/notedelight/shared/presentation/main/MainViewModelTest.kt index df0644a3..72dc76b9 100644 --- a/shared/src/androidUnitTest/kotlin/com/softartdev/notedelight/shared/presentation/main/MainViewModelTest.kt +++ b/shared/src/androidUnitTest/kotlin/com/softartdev/notedelight/shared/presentation/main/MainViewModelTest.kt @@ -2,6 +2,8 @@ package com.softartdev.notedelight.shared.presentation.main import android.database.sqlite.SQLiteException import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import app.cash.paging.PagingSource +import app.cash.paging.PagingState import app.cash.turbine.test import com.softartdev.notedelight.shared.CoroutineDispatchersStub import com.softartdev.notedelight.shared.db.Note @@ -11,10 +13,9 @@ import com.softartdev.notedelight.shared.navigation.AppNavGraph import com.softartdev.notedelight.shared.navigation.Router import com.softartdev.notedelight.shared.presentation.MainDispatcherRule import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test @@ -22,7 +23,6 @@ import org.mockito.Mockito @ExperimentalCoroutinesApi class MainViewModelTest { - @get:Rule var instantExecutorRule = InstantTaskExecutorRule() @@ -33,7 +33,7 @@ class MainViewModelTest { private val mockRouter = Mockito.mock(Router::class.java) private val mockNoteDAO = Mockito.mock(NoteDAO::class.java) private val coroutineDispatchers = CoroutineDispatchersStub(testDispatcher = mainDispatcherRule.testDispatcher) - private var mainViewModel: MainViewModel = MainViewModel(mockSafeRepo, mockRouter, coroutineDispatchers) + private lateinit var mainViewModel: MainViewModel @Before fun setUp() { @@ -46,10 +46,17 @@ class MainViewModelTest { mainViewModel.stateFlow.test { assertEquals(NoteListResult.Loading, awaitItem()) - val notes = emptyList() - Mockito.`when`(mockNoteDAO.listFlow).thenReturn(flowOf(notes)) + val pagingSource = object : PagingSource() { + override suspend fun load(params: LoadParams): LoadResult { + return LoadResult.Page(data = emptyList(), prevKey = null, nextKey = null) + } + override fun getRefreshKey(state: PagingState): Int? = null + } + Mockito.`when`(mockNoteDAO.pagingSource).thenReturn(pagingSource) + mainViewModel.updateNotes() - assertEquals(NoteListResult.Success(notes), awaitItem()) + + assertTrue(awaitItem() is NoteListResult.Success) cancelAndIgnoreRemainingEvents() } @@ -60,7 +67,7 @@ class MainViewModelTest { mainViewModel.stateFlow.test { assertEquals(NoteListResult.Loading, awaitItem()) - Mockito.`when`(mockNoteDAO.listFlow).thenReturn(flow { throw SQLiteException() }) + Mockito.`when`(mockNoteDAO.pagingSource).thenThrow(SQLiteException()) mainViewModel.updateNotes() assertEquals(NoteListResult.Error(null), awaitItem()) Mockito.verify(mockRouter).navigateClearingBackStack(route = AppNavGraph.SignIn) @@ -75,22 +82,16 @@ class MainViewModelTest { Mockito.verify(mockRouter).navigate(route = AppNavGraph.Details(noteId = 1)) } - @Test - fun onSettingsClicked() { - mainViewModel.onSettingsClicked() - Mockito.verify(mockRouter).navigate(route = AppNavGraph.Settings) - } - @Test fun error() = runTest { mainViewModel.stateFlow.test { assertEquals(NoteListResult.Loading, awaitItem()) - Mockito.`when`(mockNoteDAO.listFlow).thenReturn(flow { throw Throwable() }) + Mockito.`when`(mockNoteDAO.pagingSource).thenThrow(RuntimeException()) mainViewModel.updateNotes() assertEquals(NoteListResult.Error(null), awaitItem()) cancelAndIgnoreRemainingEvents() } } -} \ No newline at end of file +}