package com.kickstarter.viewmodels; import android.util.Pair; import com.kickstarter.KSRobolectricTestCase; import com.kickstarter.factories.ConfigFactory; import com.kickstarter.factories.ProjectFactory; import com.kickstarter.factories.RewardFactory; import com.kickstarter.libs.Config; import com.kickstarter.libs.CurrentConfigType; import com.kickstarter.libs.Environment; import com.kickstarter.models.Project; import com.kickstarter.models.Reward; import com.kickstarter.models.RewardsItem; import org.joda.time.DateTime; import org.junit.Test; import java.util.List; import rx.observers.TestSubscriber; import static java.util.Collections.emptyList; public final class RewardViewModelTest extends KSRobolectricTestCase { @Test public void testAllGoneTextViewIsHidden() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.backedProjectWithRewardLimitReached(); final TestSubscriber<Boolean> allGoneTextViewIsHidden = TestSubscriber.create(); vm.outputs.allGoneTextViewIsHidden().subscribe(allGoneTextViewIsHidden); // When an unlimited reward is not backed, hide the 'all gone' header. vm.inputs.projectAndReward(project, RewardFactory.reward()); allGoneTextViewIsHidden.assertValues(true); // When an unlimited reward is backed, hide the 'all gone' header (distinct until changed). final Reward backedReward = project.backing().reward(); vm.inputs.projectAndReward(project, backedReward); allGoneTextViewIsHidden.assertValues(true); // When a backed reward's limit has been reached, hide the 'all gone' header – the selected banner will be shown instead. final Reward backedRewardWithLimitReached = backedReward.toBuilder() .limit(1) .remaining(0) .build(); vm.inputs.projectAndReward(project, backedRewardWithLimitReached); allGoneTextViewIsHidden.assertValues(true); // When a reward's limit has been reached and it has not been backed, show the 'all gone' header. vm.inputs.projectAndReward(project, RewardFactory.limitReached()); allGoneTextViewIsHidden.assertValues(true, false); } @Test public void testBackersTextViewIsHidden() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final TestSubscriber<Boolean> backersTextViewIsHiddenTest = TestSubscriber.create(); vm.outputs.backersTextViewIsHidden().subscribe(backersTextViewIsHiddenTest); vm.inputs.projectAndReward(project, RewardFactory.noBackers()); backersTextViewIsHiddenTest.assertValues(true); vm.inputs.projectAndReward(project, RewardFactory.noReward()); backersTextViewIsHiddenTest.assertValues(true); vm.inputs.projectAndReward(project, RewardFactory.backers()); backersTextViewIsHiddenTest.assertValues(true, false); } @Test public void testBackersTextView() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final Reward rewardWithBackers = RewardFactory.reward().toBuilder().backersCount(100).build(); final TestSubscriber<Integer> backersTextViewTextTest = TestSubscriber.create(); vm.outputs.backersTextViewText().subscribe(backersTextViewTextTest); // Show reward backer count. vm.inputs.projectAndReward(project, rewardWithBackers); backersTextViewTextTest.assertValue(100); } @Test public void testDescriptionTextViewText() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final Reward reward = RewardFactory.reward(); final TestSubscriber<String> descriptionTextViewTextTest = TestSubscriber.create(); vm.outputs.descriptionTextViewText().subscribe(descriptionTextViewTextTest); vm.inputs.projectAndReward(project, reward); descriptionTextViewTextTest.assertValue(reward.description()); } @Test public void testEstimatedDeliveryDateTextViewText() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final Reward reward = RewardFactory.reward().toBuilder() .estimatedDeliveryOn(null) .build(); final TestSubscriber<DateTime> estimatedDeliveryDateTextViewTextTest = TestSubscriber.create(); vm.outputs.estimatedDeliveryDateTextViewText().subscribe(estimatedDeliveryDateTextViewTextTest); vm.inputs.projectAndReward(project, reward); // If reward has no estimated delivery, no value should be emitted. estimatedDeliveryDateTextViewTextTest.assertNoValues(); // Reward with estimated delivery should emit. final DateTime estimatedDelivery = DateTime.now(); vm.inputs.projectAndReward(project, reward.toBuilder().estimatedDeliveryOn(estimatedDelivery).build()); estimatedDeliveryDateTextViewTextTest.assertValue(estimatedDelivery); } @Test public void testEstimatedDeliveryDateSectionIsHidden() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final TestSubscriber<Boolean> estimatedDeliveryDateSectionIsHiddenTest = TestSubscriber.create(); vm.outputs.estimatedDeliveryDateSectionIsHidden().subscribe(estimatedDeliveryDateSectionIsHiddenTest); // Reward with no estimated delivery should not show estimated delivery label. vm.inputs.projectAndReward(project, RewardFactory.reward().toBuilder().estimatedDeliveryOn(null).build()); estimatedDeliveryDateSectionIsHiddenTest.assertValue(true); // Reward with estimated delivery should show estimated delivery label. vm.inputs.projectAndReward(project, RewardFactory.reward().toBuilder().estimatedDeliveryOn(DateTime.now()).build()); estimatedDeliveryDateSectionIsHiddenTest.assertValues(true, false); } @Test public void testGoToCheckoutWhenProjectIsSuccessful() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.successfulProject(); final Reward reward = RewardFactory.reward(); final TestSubscriber<Pair<Project, Reward>> goToCheckoutTest = TestSubscriber.create(); vm.outputs.goToCheckout().subscribe(goToCheckoutTest); vm.inputs.projectAndReward(project, reward); goToCheckoutTest.assertNoValues(); vm.inputs.rewardClicked(); goToCheckoutTest.assertNoValues(); } @Test public void testGoToCheckoutWhenProjectIsSuccessfulAndHasBeenBacked() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.backedProject().toBuilder() .state(Project.STATE_SUCCESSFUL) .build(); final Reward reward = project.backing().reward(); final TestSubscriber<Pair<Project, Reward>> goToCheckoutTest = TestSubscriber.create(); vm.outputs.goToCheckout().subscribe(goToCheckoutTest); vm.inputs.projectAndReward(project, reward); goToCheckoutTest.assertNoValues(); vm.inputs.rewardClicked(); goToCheckoutTest.assertNoValues(); } @Test public void testGoToCheckoutWhenProjectIsLive() { final RewardViewModel vm = new RewardViewModel(environment()); final Reward reward = RewardFactory.reward(); final TestSubscriber<Pair<Project, Reward>> startCheckoutTest = TestSubscriber.create(); vm.outputs.goToCheckout().subscribe(startCheckoutTest); final Project liveProject = ProjectFactory.project(); vm.inputs.projectAndReward(liveProject, reward); startCheckoutTest.assertNoValues(); // When a reward from a live project is clicked, start checkout. vm.inputs.rewardClicked(); startCheckoutTest.assertValue(Pair.create(liveProject, reward)); } @Test public void testGoToViewPledge() { final RewardViewModel vm = new RewardViewModel(environment()); final Project liveProject = ProjectFactory.backedProject(); final Project successfulProject = ProjectFactory.backedProject().toBuilder() .state(Project.STATE_SUCCESSFUL) .build(); final TestSubscriber<Project> goToViewPledgeTest = TestSubscriber.create(); vm.outputs.goToViewPledge().subscribe(goToViewPledgeTest); vm.inputs.projectAndReward(liveProject, liveProject.backing().reward()); goToViewPledgeTest.assertNoValues(); // When the project is still live, don't go to 'view pledge'. Should go to checkout instead. vm.inputs.rewardClicked(); goToViewPledgeTest.assertNoValues(); // When project is successful but not backed, don't go to view pledge. vm.inputs.projectAndReward(successfulProject, RewardFactory.reward()); vm.inputs.rewardClicked(); goToViewPledgeTest.assertNoValues(); // When project is successful and backed, go to view pledge. vm.inputs.projectAndReward(successfulProject, successfulProject.backing().reward()); goToViewPledgeTest.assertNoValues(); vm.inputs.rewardClicked(); goToViewPledgeTest.assertValues(successfulProject); } @Test public void testIsClickable() { final RewardViewModel vm = new RewardViewModel(environment()); final TestSubscriber<Boolean> isClickableTest = TestSubscriber.create(); vm.outputs.isClickable().subscribe(isClickableTest); // A reward from a live project should be clickable. vm.inputs.projectAndReward(ProjectFactory.project(), RewardFactory.reward()); isClickableTest.assertValue(true); // A reward from a successful project should not be clickable. vm.inputs.projectAndReward(ProjectFactory.successfulProject(), RewardFactory.reward()); isClickableTest.assertValues(true, false); // // A backed reward from a live project should be clickable. final Project backedLiveProject = ProjectFactory.backedProject(); vm.inputs.projectAndReward(backedLiveProject, backedLiveProject.backing().reward()); isClickableTest.assertValues(true, false, true); // A backed reward from a finished project should be clickable (distinct until changed). final Project backedSuccessfulProject = ProjectFactory.backedProject().toBuilder() .state(Project.STATE_SUCCESSFUL) .build(); vm.inputs.projectAndReward(backedSuccessfulProject, backedSuccessfulProject.backing().reward()); isClickableTest.assertValues(true, false, true); // A reward with its limit reached should not be clickable. vm.inputs.projectAndReward(ProjectFactory.project(), RewardFactory.limitReached()); isClickableTest.assertValues(true, false, true, false); } @Test public void testLimitAndBackersSeparatorIsHidden() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final TestSubscriber<Boolean> limitAndBackersSeparatorIsHiddenTest = TestSubscriber.create(); vm.outputs.limitAndBackersSeparatorIsHidden().subscribe(limitAndBackersSeparatorIsHiddenTest); // When reward has no limit or backers, separator should be hidden. vm.inputs.projectAndReward(project, RewardFactory.noBackers()); limitAndBackersSeparatorIsHiddenTest.assertValues(true); // When reward has no limit and backers, separator should be hidden. vm.inputs.projectAndReward(project, RewardFactory.reward()); limitAndBackersSeparatorIsHiddenTest.assertValues(true); // When reward has limit and no backers, separator should be hidden. vm.inputs.projectAndReward(project, RewardFactory.limited().toBuilder().backersCount(0).build()); limitAndBackersSeparatorIsHiddenTest.assertValues(true); // When reward has limit and backers, separator should be visible. vm.inputs.projectAndReward(project, RewardFactory.limited().toBuilder().build()); limitAndBackersSeparatorIsHiddenTest.assertValues(true, false); } @Test public void testLimitAndRemaining() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final TestSubscriber<Pair<String, String>> limitAndRemainingTextViewTextTest = TestSubscriber.create(); vm.outputs.limitAndRemainingTextViewText().subscribe(limitAndRemainingTextViewTextTest); final TestSubscriber<Boolean> limitAndRemainingTextViewIsHiddenTest = TestSubscriber.create(); vm.outputs.limitAndRemainingTextViewIsHidden().subscribe(limitAndRemainingTextViewIsHiddenTest); // When reward is limited, quantity should be shown. final Reward limitedReward = RewardFactory.reward().toBuilder() .limit(10) .remaining(5) .build(); vm.inputs.projectAndReward(project, limitedReward); limitAndRemainingTextViewTextTest.assertValue(Pair.create("10", "5")); limitAndRemainingTextViewIsHiddenTest.assertValue(false); // When reward's limit has been reached, don't show quantity. vm.inputs.projectAndReward(project, RewardFactory.limitReached()); limitAndRemainingTextViewIsHiddenTest.assertValues(false, true); // When reward has no limit, don't show quantity (distinct until changed). vm.inputs.projectAndReward(project, RewardFactory.reward()); limitAndRemainingTextViewIsHiddenTest.assertValues(false, true); } @Test public void testLimitHeaderIsHidden() { final RewardViewModel vm = new RewardViewModel(environment()); final TestSubscriber<Boolean> limitHeaderIsHiddenTest = TestSubscriber.create(); vm.outputs.limitHeaderIsHidden().subscribe(limitHeaderIsHiddenTest); // If the reward is limited and has not been backed, show the limit header. final Project backedProjectWithLimitedReward = ProjectFactory.backedProjectWithRewardLimited(); vm.inputs.projectAndReward(backedProjectWithLimitedReward, RewardFactory.limited()); limitHeaderIsHiddenTest.assertValues(false); // If the reward is limited and has been backed, don't show the limit header. vm.inputs.projectAndReward(backedProjectWithLimitedReward, backedProjectWithLimitedReward.backing().reward()); limitHeaderIsHiddenTest.assertValues(false, true); // If the reward is not limited, don't show the limit header. vm.inputs.projectAndReward(ProjectFactory.project(), RewardFactory.reward()); limitHeaderIsHiddenTest.assertValues(false, true); } @Test public void testMinimumTextViewText() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final Reward reward = RewardFactory.reward().toBuilder() .minimum(10) .build(); final TestSubscriber<String> minimumTextViewTextTest = TestSubscriber.create(); vm.outputs.minimumTextViewText().subscribe(minimumTextViewTextTest); vm.inputs.projectAndReward(project, reward); minimumTextViewTextTest.assertValue("$10"); } @Test public void testRewardsItems() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final TestSubscriber<Boolean> rewardsItemsAreHiddenTest = TestSubscriber.create(); vm.outputs.rewardsItemsAreHidden().subscribe(rewardsItemsAreHiddenTest); final TestSubscriber<List<RewardsItem>> rewardsItemsTest = TestSubscriber.create(); vm.outputs.rewardsItems().subscribe(rewardsItemsTest); // Items section should be hidden when there are no items. vm.inputs.projectAndReward(project, RewardFactory.reward()); rewardsItemsAreHiddenTest.assertValue(true); rewardsItemsTest.assertValue(emptyList()); final Reward itemizedReward = RewardFactory.itemized(); vm.inputs.projectAndReward(project, itemizedReward); rewardsItemsAreHiddenTest.assertValues(true, false); rewardsItemsTest.assertValues(emptyList(), itemizedReward.rewardsItems()); } @Test public void testTitleTextViewText() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final TestSubscriber<Boolean> titleTextViewIsHidden = TestSubscriber.create(); vm.outputs.titleTextViewIsHidden().subscribe(titleTextViewIsHidden); final TestSubscriber<String> titleTextViewTextTest = TestSubscriber.create(); vm.outputs.titleTextViewText().subscribe(titleTextViewTextTest); // Reward with no title should be hidden. final Reward rewardWithNoTitle = RewardFactory.reward().toBuilder() .title(null) .build(); vm.inputs.projectAndReward(project, rewardWithNoTitle); titleTextViewIsHidden.assertValues(true); titleTextViewTextTest.assertNoValues(); // Reward with title should be visible. final String title = "Digital bundle"; final Reward rewardWithTitle = RewardFactory.reward().toBuilder() .title(title) .build(); vm.inputs.projectAndReward(project, rewardWithTitle); titleTextViewIsHidden.assertValues(true, false); titleTextViewTextTest.assertValue(title); } @Test public void testSelectedHeaderAndOverlay() { final RewardViewModel vm = new RewardViewModel(environment()); final TestSubscriber<Boolean> selectedHeaderIsHidden = TestSubscriber.create(); vm.outputs.selectedHeaderIsHidden().subscribe(selectedHeaderIsHidden); final TestSubscriber<Boolean> selectedOverlayIsHidden = TestSubscriber.create(); vm.outputs.selectedOverlayIsHidden().subscribe(selectedOverlayIsHidden); final Project backedProject = ProjectFactory.backedProject(); vm.inputs.projectAndReward(backedProject, backedProject.backing().reward()); selectedHeaderIsHidden.assertValue(false); selectedOverlayIsHidden.assertValue(false); vm.inputs.projectAndReward(backedProject, RewardFactory.reward()); selectedHeaderIsHidden.assertValues(false, true); selectedOverlayIsHidden.assertValues(false, true); } @Test public void testShippingSummary() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final TestSubscriber<String> shippingSummaryTextViewTextTest = TestSubscriber.create(); vm.outputs.shippingSummaryTextViewText().subscribe(shippingSummaryTextViewTextTest); final TestSubscriber<Boolean> shippingSummarySectionIsHiddenTest = TestSubscriber.create(); vm.outputs.shippingSummarySectionIsHidden().subscribe(shippingSummarySectionIsHiddenTest); // Reward with no shipping should hide shipping summary section and not emit a shipping summary string. vm.inputs.projectAndReward(project, RewardFactory.reward()); shippingSummaryTextViewTextTest.assertNoValues(); shippingSummarySectionIsHiddenTest.assertValue(true); // Reward with shipping should show shipping summary section and emit a shipping summary string. final Reward rewardWithShipping = RewardFactory.rewardWithShipping(); vm.inputs.projectAndReward(project, rewardWithShipping); shippingSummaryTextViewTextTest.assertValue(rewardWithShipping.shippingSummary()); shippingSummarySectionIsHiddenTest.assertValues(true, false); } @Test public void testUsdConversionForNonUSProject() { // Set user's country to US. final Config config = ConfigFactory.configForUSUser(); final Environment environment = environment(); final CurrentConfigType currentConfig = environment.currentConfig(); environment.currentConfig().config(config); final RewardViewModel vm = new RewardViewModel(environment); // Set project's country to CA. final Project project = ProjectFactory.caProject(); final Reward reward = RewardFactory.reward(); final TestSubscriber<String> usdConversionTextViewText = TestSubscriber.create(); vm.outputs.usdConversionTextViewText().subscribe(usdConversionTextViewText); final TestSubscriber<Boolean> usdConversionSectionIsHidden = TestSubscriber.create(); vm.outputs.usdConversionTextViewIsHidden().subscribe(usdConversionSectionIsHidden); // USD conversion should be shown. vm.inputs.projectAndReward(project, reward); usdConversionTextViewText.assertValueCount(1); usdConversionSectionIsHidden.assertValue(false); // Set user's country to CA (any country except the US is fine). currentConfig.config(ConfigFactory.configForCAUser()); // USD conversion should now be hidden. usdConversionTextViewText.assertValueCount(1); usdConversionSectionIsHidden.assertValues(false, true); } @Test public void testUsdConversionNotShownForUSProject() { // Set user's country to US. final Config config = ConfigFactory.configForUSUser(); final Environment environment = environment(); final CurrentConfigType currentConfig = environment.currentConfig(); environment.currentConfig().config(config); final RewardViewModel vm = new RewardViewModel(environment); // Set project's country to US. final Project project = ProjectFactory.project().toBuilder().country("US").build(); final Reward reward = RewardFactory.reward(); final TestSubscriber<String> usdConversionTextViewText = TestSubscriber.create(); vm.outputs.usdConversionTextViewText().subscribe(usdConversionTextViewText); final TestSubscriber<Boolean> usdConversionSectionIsHidden = TestSubscriber.create(); vm.outputs.usdConversionTextViewIsHidden().subscribe(usdConversionSectionIsHidden); // USD conversion should not be shown. vm.inputs.projectAndReward(project, reward); usdConversionTextViewText.assertNoValues(); usdConversionSectionIsHidden.assertValue(true); // Set user's country to CA. currentConfig.config(ConfigFactory.configForCAUser()); // USD conversion should still not be shown (distinct until changed). usdConversionTextViewText.assertNoValues(); usdConversionSectionIsHidden.assertValues(true); } @Test public void testUsdConversionTextRoundsUp() { // Set user's country to US. final Config config = ConfigFactory.configForUSUser(); final Environment environment = environment(); environment.currentConfig().config(config); final RewardViewModel vm = new RewardViewModel(environment); // Set project's country to CA and reward minimum to $0.30. final Project project = ProjectFactory.caProject(); final Reward reward = RewardFactory.reward().toBuilder().minimum(0.3f).build(); final TestSubscriber<String> usdConversionTextViewText = TestSubscriber.create(); vm.outputs.usdConversionTextViewText().subscribe(usdConversionTextViewText); // USD conversion should be rounded up. vm.inputs.projectAndReward(project, reward); usdConversionTextViewText.assertValue("$1"); } @Test public void testWhiteOverlayIsHidden() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final TestSubscriber<Boolean> whiteOverlayIsHiddenTest = TestSubscriber.create(); vm.outputs.whiteOverlayIsHidden().subscribe(whiteOverlayIsHiddenTest); vm.inputs.projectAndReward(project, RewardFactory.reward()); whiteOverlayIsHiddenTest.assertValue(true); final Project backedProjectWithRewardLimitReached = ProjectFactory.backedProjectWithRewardLimitReached(); vm.inputs.projectAndReward(backedProjectWithRewardLimitReached, backedProjectWithRewardLimitReached.backing().reward()); whiteOverlayIsHiddenTest.assertValues(true); vm.inputs.projectAndReward(project, RewardFactory.limitReached()); whiteOverlayIsHiddenTest.assertValues(true, false); } @Test public void testNonEmptyRewardsDescriptionAreShown() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final TestSubscriber<Boolean> hideRewardDescriptionTest = TestSubscriber.create(); vm.outputs.rewardDescriptionIsHidden().subscribe(hideRewardDescriptionTest); vm.inputs.projectAndReward(project, RewardFactory.reward()); hideRewardDescriptionTest.assertValue(false); } @Test public void testEmptyRewardsDescriptionAreHidden() { final RewardViewModel vm = new RewardViewModel(environment()); final Project project = ProjectFactory.project(); final TestSubscriber<Boolean> hideRewardDescriptionTest = TestSubscriber.create(); vm.outputs.rewardDescriptionIsHidden().subscribe(hideRewardDescriptionTest); vm.inputs.projectAndReward(project, RewardFactory.noDescription()); hideRewardDescriptionTest.assertValue(true); } }