diff --git a/app/src/test/kotlin/com/andreolas/ui/details/DetailsContentTest.kt b/app/src/test/kotlin/com/andreolas/ui/details/DetailsContentTest.kt index 025e9a53..6fb016bc 100644 --- a/app/src/test/kotlin/com/andreolas/ui/details/DetailsContentTest.kt +++ b/app/src/test/kotlin/com/andreolas/ui/details/DetailsContentTest.kt @@ -2,6 +2,7 @@ package com.andreolas.ui.details import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsNotDisplayed import androidx.compose.ui.test.hasText import androidx.compose.ui.test.onAllNodesWithText import androidx.compose.ui.test.onNodeWithContentDescription @@ -13,6 +14,7 @@ import com.andreolas.factories.ReviewFactory import com.andreolas.factories.details.domain.model.account.AccountMediaDetailsFactory import com.andreolas.factories.details.domain.model.account.AccountMediaDetailsFactory.toWizard import com.andreolas.movierama.R +import com.divinelink.core.model.details.DetailActionItem import com.divinelink.core.model.details.DetailsMenuOptions import com.divinelink.core.model.details.video.Video import com.divinelink.core.model.details.video.VideoSite @@ -516,5 +518,79 @@ class DetailsContentTest : ComposeTest() { } } + @Test + fun `test open request dialog for tv show`() { + setContentWithTheme { + DetailsContent( + viewState = DetailsViewState( + mediaId = 0, + mediaType = MediaType.TV, + actionButtons = DetailActionItem.entries, + mediaDetails = MediaDetailsFactory.TheOffice(), + ), + onNavigateUp = {}, + onMarkAsFavoriteClicked = {}, + onSimilarMovieClicked = {}, + onConsumeSnackbar = {}, + onAddRateClicked = {}, + onAddToWatchlistClicked = {}, + requestMedia = {}, + viewAllCreditsClicked = {}, + onPersonClick = {}, + ) + } + composeTestRule + .onNodeWithText(getString(detailsR.string.feature_details_request)) + .assertIsNotDisplayed() + + composeTestRule + .onNodeWithTag(TestTags.Components.ExpandableFab.BUTTON) + .performClick() + + composeTestRule + .onNodeWithText(getString(detailsR.string.feature_details_request)) + .assertIsDisplayed() + .performClick() + + composeTestRule.onNodeWithTag(TestTags.Dialogs.SELECT_SEASONS_DIALOG).assertIsDisplayed() + } + + @Test + fun `test open request dialog for movie`() { + setContentWithTheme { + DetailsContent( + viewState = DetailsViewState( + mediaId = 0, + mediaType = MediaType.MOVIE, + actionButtons = DetailActionItem.entries, + mediaDetails = MediaDetailsFactory.FightClub(), + ), + onNavigateUp = {}, + onMarkAsFavoriteClicked = {}, + onSimilarMovieClicked = {}, + onConsumeSnackbar = {}, + onAddRateClicked = {}, + onAddToWatchlistClicked = {}, + requestMedia = {}, + viewAllCreditsClicked = {}, + onPersonClick = {}, + ) + } + composeTestRule + .onNodeWithText(getString(detailsR.string.feature_details_request)) + .assertIsNotDisplayed() + + composeTestRule + .onNodeWithTag(TestTags.Components.ExpandableFab.BUTTON) + .performClick() + + composeTestRule + .onNodeWithText(getString(detailsR.string.feature_details_request)) + .assertIsDisplayed() + .performClick() + + composeTestRule.onNodeWithTag(TestTags.Dialogs.REQUEST_MOVIE_DIALOG).assertIsDisplayed() + } + private val reviews = ReviewFactory.ReviewList() } diff --git a/core/domain/src/test/kotlin/com/divinelink/core/domain/GetDropdownMenuItemsUseCaseTest.kt b/core/domain/src/test/kotlin/com/divinelink/core/domain/GetDropdownMenuItemsUseCaseTest.kt index c1068029..be29da08 100644 --- a/core/domain/src/test/kotlin/com/divinelink/core/domain/GetDropdownMenuItemsUseCaseTest.kt +++ b/core/domain/src/test/kotlin/com/divinelink/core/domain/GetDropdownMenuItemsUseCaseTest.kt @@ -23,20 +23,4 @@ class GetDropdownMenuItemsUseCaseTest { assertThat(result.getOrNull()).isEqualTo(listOf(DetailsMenuOptions.SHARE)) } } -// -// @Test -// fun `test dropdown menu items with jellyseerr account`() = runTest { -// val preferenceStorage = FakePreferenceStorage(jellyseerrAccount = "jellyseerr_account") -// val useCase = GetDropdownMenuItemsUseCase(preferenceStorage, testDispatcher) -// -// useCase.invoke(Unit).first().let { result -> -// assertThat(result.isSuccess).isTrue() -// assertThat(result.getOrNull()).isEqualTo( -// listOf( -// DetailsMenuOptions.SHARE, -// DetailsMenuOptions.REQUEST, -// ), -// ) -// } -// } } diff --git a/core/ui/src/main/kotlin/com/divinelink/core/ui/TestTags.kt b/core/ui/src/main/kotlin/com/divinelink/core/ui/TestTags.kt index e8323a04..271842ee 100644 --- a/core/ui/src/main/kotlin/com/divinelink/core/ui/TestTags.kt +++ b/core/ui/src/main/kotlin/com/divinelink/core/ui/TestTags.kt @@ -12,6 +12,11 @@ object TestTags { const val TOP_APP_BAR = "Top App Bar" const val TOP_APP_BAR_TITLE = "Top App Bar Title" } + + object ExpandableFab { + const val BACKGROUND = "Floating Button Background" + const val BUTTON = "Expandable Floating Action Button" + } } const val LOADING_CONTENT = "LOADING_CONTENT" diff --git a/core/ui/src/main/kotlin/com/divinelink/core/ui/components/expandablefab/ExpandableFloatingActionButton.kt b/core/ui/src/main/kotlin/com/divinelink/core/ui/components/expandablefab/ExpandableFloatingActionButton.kt index 1ad499c4..37678a04 100644 --- a/core/ui/src/main/kotlin/com/divinelink/core/ui/components/expandablefab/ExpandableFloatingActionButton.kt +++ b/core/ui/src/main/kotlin/com/divinelink/core/ui/components/expandablefab/ExpandableFloatingActionButton.kt @@ -42,12 +42,14 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.IntOffset import com.divinelink.core.designsystem.theme.AppTheme import com.divinelink.core.designsystem.theme.dimensions import com.divinelink.core.ui.IconWrapper import com.divinelink.core.ui.Previews +import com.divinelink.core.ui.TestTags import com.divinelink.core.ui.UIText import com.divinelink.core.ui.getString import com.divinelink.core.ui.snackbar.controller.LocalSnackbarController @@ -95,6 +97,7 @@ fun ExpandableFloatActionButton( Box( modifier = Modifier .background(MaterialTheme.colorScheme.surface.copy(alpha = 0.9f)) + .testTag(TestTags.Components.ExpandableFab.BACKGROUND) .fillMaxSize() .clickable( interactionSource = null, @@ -121,9 +124,14 @@ fun ExpandableFloatActionButton( FloatingActionButton( onClick = { expanded = !expanded }, - modifier = Modifier.rotate(rotationState), + modifier = Modifier + .testTag(TestTags.Components.ExpandableFab.BUTTON) + .rotate(rotationState), ) { - Icon(Icons.Rounded.Add, contentDescription = "Expandable FAB") + Icon( + imageVector = Icons.Rounded.Add, + contentDescription = "Expandable FAB", + ) } } } diff --git a/core/ui/src/test/kotlin/com/divinelink/core/ui/DetailsDropDownMenuTest.kt b/core/ui/src/test/kotlin/com/divinelink/core/ui/DetailsDropDownMenuTest.kt index d862cf18..c53b21cb 100644 --- a/core/ui/src/test/kotlin/com/divinelink/core/ui/DetailsDropDownMenuTest.kt +++ b/core/ui/src/test/kotlin/com/divinelink/core/ui/DetailsDropDownMenuTest.kt @@ -25,44 +25,4 @@ class DetailsDropDownMenuTest : ComposeTest() { TestTags.Menu.MENU_ITEM.format(getString(R.string.core_ui_share)), ).assertIsDisplayed() } - -// @Test -// fun `test open request dialog for tv show`() { -// composeTestRule.setContent { -// DetailsDropdownMenu( -// mediaDetails = MediaDetailsFactory.TheOffice(), -// menuOptions = listOf(DetailsMenuOptions.SHARE, DetailsMenuOptions.REQUEST), -// expanded = true, -// requestMedia = {}, -// onDismissDropdown = {}, -// ) -// } -// composeTestRule.onNodeWithTag( -// TestTags.Menu.MENU_ITEM.format(getString(R.string.core_ui_dropdown_menu_request)), -// ) -// .assertIsDisplayed() -// .performClick() -// -// composeTestRule.onNodeWithTag(TestTags.Dialogs.SELECT_SEASONS_DIALOG).assertIsDisplayed() -// } - -// @Test -// fun `test open request dialog for movie`() { -// composeTestRule.setContent { -// DetailsDropdownMenu( -// mediaDetails = MediaDetailsFactory.FightClub(), -// menuOptions = listOf(DetailsMenuOptions.SHARE, DetailsMenuOptions.REQUEST), -// expanded = true, -// requestMedia = {}, -// onDismissDropdown = {}, -// ) -// } -// composeTestRule.onNodeWithTag( -// TestTags.Menu.MENU_ITEM.format(getString(R.string.core_ui_dropdown_menu_request)), -// ) -// .assertIsDisplayed() -// .performClick() -// -// composeTestRule.onNodeWithTag(TestTags.Dialogs.REQUEST_MOVIE_DIALOG).assertIsDisplayed() -// } } diff --git a/core/ui/src/test/kotlin/com/divinelink/core/ui/components/expandablefab/ExpandableFloatingActionButtonTest.kt b/core/ui/src/test/kotlin/com/divinelink/core/ui/components/expandablefab/ExpandableFloatingActionButtonTest.kt new file mode 100644 index 00000000..493e4a60 --- /dev/null +++ b/core/ui/src/test/kotlin/com/divinelink/core/ui/components/expandablefab/ExpandableFloatingActionButtonTest.kt @@ -0,0 +1,168 @@ +package com.divinelink.core.ui.components.expandablefab + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Add +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsNotDisplayed +import androidx.compose.ui.test.onNodeWithContentDescription +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.performClick +import com.divinelink.core.testing.ComposeTest +import com.divinelink.core.testing.setContentWithTheme +import com.divinelink.core.ui.IconWrapper +import com.divinelink.core.ui.R +import com.divinelink.core.ui.TestTags +import com.divinelink.core.ui.UIText +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test + +class ExpandableFloatingActionButtonTest : ComposeTest() { + + @Test + fun `test buttons are shown when fab button is clicked`() { + var extraActionIsClicked = false + + val actionButtons = listOf( + FloatingActionButtonItem( + icon = IconWrapper.Vector(Icons.Rounded.Add), + label = UIText.StringText("Add"), + contentDescription = UIText.StringText("Add Button"), + onClick = { extraActionIsClicked = true }, + ), + FloatingActionButtonItem( + icon = IconWrapper.Image(R.drawable.core_ui_ic_jellyseerr), + label = UIText.StringText("Delete"), + contentDescription = UIText.StringText("Delete Button"), + onClick = { extraActionIsClicked = true }, + ), + FloatingActionButtonItem( + icon = IconWrapper.Icon(R.drawable.core_ui_ic_error_64), + label = UIText.StringText("Close"), + contentDescription = UIText.StringText("Close Button"), + onClick = { extraActionIsClicked = true }, + ), + ) + + setContentWithTheme { + ExpandableFloatActionButton( + buttons = actionButtons, + ) + } + + with(composeTestRule) { + onNodeWithTag(TestTags.Components.ExpandableFab.BUTTON).assertIsDisplayed() + onNodeWithContentDescription("Add Button").assertIsNotDisplayed() + onNodeWithContentDescription("Delete Button").assertIsNotDisplayed() + onNodeWithContentDescription("Close Button").assertIsNotDisplayed() + + onNodeWithTag(TestTags.Components.ExpandableFab.BUTTON).performClick() + + onNodeWithContentDescription("Add Button").assertIsDisplayed() + onNodeWithContentDescription("Delete Button").assertIsDisplayed() + onNodeWithContentDescription("Close Button").assertIsDisplayed() + + assertThat(extraActionIsClicked).isFalse() + + onNodeWithContentDescription("Add Button").performClick() + + onNodeWithTag(TestTags.Components.ExpandableFab.BUTTON).assertIsDisplayed() + + onNodeWithContentDescription("Add Button").assertIsNotDisplayed() + onNodeWithContentDescription("Delete Button").assertIsNotDisplayed() + onNodeWithContentDescription("Close Button").assertIsNotDisplayed() + assertThat(extraActionIsClicked).isTrue() + } + } + + @Test + fun `test icons are displayed`() { + val actionButtons = listOf( + FloatingActionButtonItem( + icon = IconWrapper.Vector(Icons.Rounded.Add), + label = UIText.StringText("Add"), + contentDescription = UIText.StringText("Add Button"), + onClick = { }, + ), + FloatingActionButtonItem( + icon = IconWrapper.Image(R.drawable.core_ui_ic_jellyseerr), + label = UIText.StringText("Delete"), + contentDescription = UIText.StringText("Delete Button"), + onClick = { }, + ), + FloatingActionButtonItem( + icon = IconWrapper.Icon(R.drawable.core_ui_ic_error_64), + label = UIText.StringText("Close"), + contentDescription = UIText.StringText("Close Button"), + onClick = { }, + ), + ) + + setContentWithTheme { + ExpandableFloatActionButton( + buttons = actionButtons, + ) + } + + with(composeTestRule) { + onNodeWithTag(TestTags.Components.ExpandableFab.BUTTON).assertIsDisplayed() + + onNodeWithContentDescription("Add Button").assertIsNotDisplayed() + onNodeWithContentDescription("Delete Button").assertIsNotDisplayed() + onNodeWithContentDescription("Close Button").assertIsNotDisplayed() + + onNodeWithTag(TestTags.Components.ExpandableFab.BUTTON).performClick() + + onNodeWithContentDescription("Add Button").assertIsDisplayed() + onNodeWithContentDescription("Delete Button").assertIsDisplayed() + onNodeWithContentDescription("Close Button").assertIsDisplayed() + } + } + + @Test + fun `test clicking on background dismisses actions`() { + val actionButtons = listOf( + FloatingActionButtonItem( + icon = IconWrapper.Vector(Icons.Rounded.Add), + label = UIText.StringText("Add"), + contentDescription = UIText.StringText("Add Button"), + onClick = { }, + ), + FloatingActionButtonItem( + icon = IconWrapper.Image(R.drawable.core_ui_ic_jellyseerr), + label = UIText.StringText("Delete"), + contentDescription = UIText.StringText("Delete Button"), + onClick = { }, + ), + FloatingActionButtonItem( + icon = IconWrapper.Icon(R.drawable.core_ui_ic_error_64), + label = UIText.StringText("Close"), + contentDescription = UIText.StringText("Close Button"), + onClick = { }, + ), + ) + + setContentWithTheme { + ExpandableFloatActionButton( + buttons = actionButtons, + ) + } + + with(composeTestRule) { + onNodeWithTag(TestTags.Components.ExpandableFab.BUTTON).assertIsDisplayed() + onNodeWithContentDescription("Add Button").assertIsNotDisplayed() + onNodeWithContentDescription("Delete Button").assertIsNotDisplayed() + onNodeWithContentDescription("Close Button").assertIsNotDisplayed() + + onNodeWithTag(TestTags.Components.ExpandableFab.BUTTON).performClick() + + onNodeWithContentDescription("Add Button").assertIsDisplayed() + onNodeWithContentDescription("Delete Button").assertIsDisplayed() + onNodeWithContentDescription("Close Button").assertIsDisplayed() + + onNodeWithTag(TestTags.Components.ExpandableFab.BACKGROUND).performClick() + onNodeWithContentDescription("Add Button").assertIsNotDisplayed() + onNodeWithContentDescription("Delete Button").assertIsNotDisplayed() + onNodeWithContentDescription("Close Button").assertIsNotDisplayed() + } + } +} diff --git a/feature/details/src/main/kotlin/com/divinelink/feature/details/media/ui/DetailsContent.kt b/feature/details/src/main/kotlin/com/divinelink/feature/details/media/ui/DetailsContent.kt index 6c187311..f91acba0 100644 --- a/feature/details/src/main/kotlin/com/divinelink/feature/details/media/ui/DetailsContent.kt +++ b/feature/details/src/main/kotlin/com/divinelink/feature/details/media/ui/DetailsContent.kt @@ -117,7 +117,7 @@ fun DetailsContent( SnackbarMessageHandler( snackbarMessage = viewState.snackbarMessage, - onDismissSnackbar = { onConsumeSnackbar() }, + onDismissSnackbar = onConsumeSnackbar, ) var showRequestDialog by remember { mutableStateOf(false) }