package com.kickstarter.viewmodels; import android.content.Intent; import com.kickstarter.KSRobolectricTestCase; import com.kickstarter.factories.CategoryFactory; import com.kickstarter.factories.InternalBuildEnvelopeFactory; import com.kickstarter.factories.UserFactory; import com.kickstarter.libs.Environment; import com.kickstarter.libs.MockCurrentUser; import com.kickstarter.libs.rx.transformers.Transformers; import com.kickstarter.libs.utils.DiscoveryUtils; import com.kickstarter.models.Category; import com.kickstarter.services.DiscoveryParams; import com.kickstarter.services.apiresponses.InternalBuildEnvelope; import com.kickstarter.ui.adapters.data.NavigationDrawerData; import org.junit.Test; import java.util.Arrays; import java.util.List; import rx.observers.TestSubscriber; public class DiscoveryViewModelTest extends KSRobolectricTestCase { @Test public void testBuildCheck() { final DiscoveryViewModel vm = new DiscoveryViewModel(environment()); final InternalBuildEnvelope buildEnvelope = InternalBuildEnvelopeFactory.newerBuildAvailable(); final TestSubscriber<InternalBuildEnvelope> showBuildCheckAlert = new TestSubscriber<>(); vm.outputs.showBuildCheckAlert().subscribe(showBuildCheckAlert); // Build check should not be shown. showBuildCheckAlert.assertNoValues(); // Build check should be shown when newer build is available. vm.inputs.newerBuildIsAvailable(buildEnvelope); showBuildCheckAlert.assertValue(buildEnvelope); } @Test public void testDrawerData() { final MockCurrentUser currentUser = new MockCurrentUser(); final Environment env = environment().toBuilder().currentUser(currentUser).build(); final DiscoveryViewModel vm = new DiscoveryViewModel(env); final TestSubscriber<Void> navigationDrawerDataEmitted = new TestSubscriber<>(); vm.outputs.navigationDrawerData().compose(Transformers.ignoreValues()).subscribe(navigationDrawerDataEmitted); final TestSubscriber<Boolean> drawerIsOpen = new TestSubscriber<>(); vm.outputs.drawerIsOpen().subscribe(drawerIsOpen); // Initialize activity. final Intent intent = new Intent(Intent.ACTION_MAIN); vm.intent(intent); // Drawer data should emit. Drawer should be closed. navigationDrawerDataEmitted.assertValueCount(1); drawerIsOpen.assertNoValues(); koalaTest.assertNoValues(); // Open drawer and click the top PWL filter. vm.inputs.openDrawer(true); vm.inputs.topFilterViewHolderRowClick(null, NavigationDrawerData.Section.Row .builder() .params(DiscoveryParams.builder().staffPicks(true).build()) .build() ); // Drawer data should emit. Drawer should open, then close upon selection. navigationDrawerDataEmitted.assertValueCount(2); drawerIsOpen.assertValues(true, false); koalaTest.assertValues("Discover Switch Modal", "Discover Modal Selected Filter"); // Open drawer and click a child filter. vm.inputs.openDrawer(true); vm.inputs.childFilterViewHolderRowClick(null, NavigationDrawerData.Section.Row .builder() .params(DiscoveryParams .builder() .category(CategoryFactory.artCategory()) .build() ) .build() ); // Drawer data should emit. Drawer should open, then close upon selection. navigationDrawerDataEmitted.assertValueCount(3); drawerIsOpen.assertValues(true, false, true, false); koalaTest.assertValues("Discover Switch Modal", "Discover Modal Selected Filter", "Discover Switch Modal", "Discover Modal Selected Filter"); } @Test public void testUpdateInterfaceElementsWithParams() { final DiscoveryViewModel vm = new DiscoveryViewModel(environment()); final TestSubscriber<DiscoveryParams> updateToolbarWithParams = new TestSubscriber<>(); vm.outputs.updateToolbarWithParams().subscribe(updateToolbarWithParams); final TestSubscriber<Boolean> expandSortTabLayout = new TestSubscriber<>(); vm.outputs.expandSortTabLayout().subscribe(expandSortTabLayout); // Initialize activity. final Intent intent = new Intent(Intent.ACTION_MAIN); vm.intent(intent); // Initial HOME page selected. vm.inputs.discoveryPagerAdapterSetPrimaryPage(null, 0); // Sort tab should be expanded. expandSortTabLayout.assertValues(true); // Toolbar params should be loaded with initial params. updateToolbarWithParams.assertValues(DiscoveryParams.builder().build()); // Select POPULAR sort. vm.inputs.discoveryPagerAdapterSetPrimaryPage(null, 1); // Sort tab should be expanded. expandSortTabLayout.assertValues(true, true); // Unchanged toolbar params should not emit. updateToolbarWithParams.assertValues(DiscoveryParams.builder().build()); // Select ALL PROJECTS filter from drawer. vm.inputs.topFilterViewHolderRowClick(null, NavigationDrawerData.Section.Row.builder().params(DiscoveryParams.builder().build()).build() ); // Sort tab should be expanded. expandSortTabLayout.assertValues(true, true, true); koalaTest.assertValues("Discover Modal Selected Filter"); // Select ART category from drawer. vm.inputs.childFilterViewHolderRowClick(null, NavigationDrawerData.Section.Row.builder() .params(DiscoveryParams.builder().category(CategoryFactory.artCategory()).build()) .build() ); // Sort tab should be expanded. expandSortTabLayout.assertValues(true, true, true, true); koalaTest.assertValues("Discover Modal Selected Filter", "Discover Modal Selected Filter"); // Simulate rotating the device and hitting initial inputs again. final TestSubscriber<DiscoveryParams> rotatedUpdateToolbarWithParams = new TestSubscriber<>(); vm.outputs.updateToolbarWithParams().subscribe(rotatedUpdateToolbarWithParams); final TestSubscriber<Boolean> rotatedExpandSortTabLayout = new TestSubscriber<>(); vm.outputs.expandSortTabLayout().subscribe(rotatedExpandSortTabLayout); // Simulate recreating and setting POPULAR fragment, the previous position before rotation. vm.inputs.discoveryPagerAdapterSetPrimaryPage(null, 1); // Sort tab and toolbar params should emit again with same params. rotatedExpandSortTabLayout.assertValues(true); rotatedUpdateToolbarWithParams.assertValues( DiscoveryParams.builder().category(CategoryFactory.artCategory()).build() ); } @Test public void testClickingInterfaceElements() { final DiscoveryViewModel vm = new DiscoveryViewModel(environment()); final TestSubscriber<Void> showInternalTools = new TestSubscriber<>(); vm.outputs.showInternalTools().subscribe(showInternalTools); final TestSubscriber<Void> showLoginTout = new TestSubscriber<>(); vm.outputs.showLoginTout().subscribe(showLoginTout); final TestSubscriber<Void> showProfile = new TestSubscriber<>(); vm.outputs.showProfile().subscribe(showProfile); final TestSubscriber<Void> showSettings = new TestSubscriber<>(); vm.outputs.showSettings().subscribe(showSettings); showInternalTools.assertNoValues(); showLoginTout.assertNoValues(); showProfile.assertNoValues(); showSettings.assertNoValues(); vm.inputs.loggedInViewHolderInternalToolsClick(null); vm.inputs.loggedOutViewHolderLoginToutClick(null); vm.inputs.loggedInViewHolderProfileClick(null, UserFactory.user()); vm.inputs.loggedInViewHolderSettingsClick(null, UserFactory.user()); showInternalTools.assertValueCount(1); showLoginTout.assertValueCount(1); showProfile.assertValueCount(1); showSettings.assertValueCount(1); } @Test public void testInteractionBetweenParamsAndPageAdapter() { final DiscoveryViewModel vm = new DiscoveryViewModel(environment()); final TestSubscriber<DiscoveryParams> updateParams= new TestSubscriber<>(); vm.outputs.updateParamsForPage().subscribe(updateParams); final TestSubscriber<Integer> updatePage = new TestSubscriber<>(); vm.outputs.updateParamsForPage().map(params -> DiscoveryUtils.positionFromSort(params.sort())).subscribe(updatePage); // Start initial activity. final Intent intent = new Intent(Intent.ACTION_MAIN); vm.intent(intent); // Initial HOME page selected. vm.inputs.discoveryPagerAdapterSetPrimaryPage(null, 0); // Initial params should emit. Page should not be updated yet. updateParams.assertValues( DiscoveryParams.builder().sort(DiscoveryParams.Sort.HOME).build() ); updatePage.assertValues(0); // Select POPULAR sort position. vm.inputs.discoveryPagerAdapterSetPrimaryPage(null, 1); // Params and page should update with new POPULAR sort values. updateParams.assertValues( DiscoveryParams.builder().sort(DiscoveryParams.Sort.HOME).build(), DiscoveryParams.builder().sort(DiscoveryParams.Sort.POPULAR).build() ); updatePage.assertValues(0, 1); // Select ART category from the drawer. vm.inputs.childFilterViewHolderRowClick(null, NavigationDrawerData.Section.Row.builder() .params(DiscoveryParams.builder().category(CategoryFactory.artCategory()).build()) .build() ); // Params should update with new category; page should remain the same. updateParams.assertValues( DiscoveryParams.builder().sort(DiscoveryParams.Sort.HOME).build(), DiscoveryParams.builder().sort(DiscoveryParams.Sort.POPULAR).build(), DiscoveryParams.builder().sort(DiscoveryParams.Sort.POPULAR).category(CategoryFactory.artCategory()).build() ); updatePage.assertValues(0, 1, 1); koalaTest.assertValues("Discover Modal Selected Filter"); // Select HOME sort position. vm.inputs.discoveryPagerAdapterSetPrimaryPage(null, 0); // Params and page should update with new HOME sort value. updateParams.assertValues( DiscoveryParams.builder().sort(DiscoveryParams.Sort.HOME).build(), DiscoveryParams.builder().sort(DiscoveryParams.Sort.POPULAR).build(), DiscoveryParams.builder().sort(DiscoveryParams.Sort.POPULAR).category(CategoryFactory.artCategory()).build(), DiscoveryParams.builder().sort(DiscoveryParams.Sort.HOME).category(CategoryFactory.artCategory()).build() ); updatePage.assertValues(0, 1, 1, 0); // Simulate rotating the device and hitting initial inputs again. final TestSubscriber<DiscoveryParams> rotatedUpdateParams= new TestSubscriber<>(); vm.outputs.updateParamsForPage().subscribe(rotatedUpdateParams); final TestSubscriber<Integer> rotatedUpdatePage = new TestSubscriber<>(); vm.outputs.updateParamsForPage().map(params -> DiscoveryUtils.positionFromSort(params.sort())).subscribe(rotatedUpdatePage); // Should emit again with same params. rotatedUpdateParams.assertValues( DiscoveryParams.builder().sort(DiscoveryParams.Sort.HOME).category(CategoryFactory.artCategory()).build() ); rotatedUpdatePage.assertValues(0); } @Test public void testClearingPages() { final DiscoveryViewModel vm = new DiscoveryViewModel(environment()); final TestSubscriber<List<Integer>> clearPages = new TestSubscriber<>(); vm.outputs.clearPages().subscribe(clearPages); // Start initial activity. final Intent intent = new Intent(Intent.ACTION_MAIN); vm.intent(intent); clearPages.assertNoValues(); vm.inputs.discoveryPagerAdapterSetPrimaryPage(null, 1); clearPages.assertNoValues(); vm.inputs.discoveryPagerAdapterSetPrimaryPage(null, 4); clearPages.assertNoValues(); // Select ART category from the drawer. vm.inputs.childFilterViewHolderRowClick(null, NavigationDrawerData.Section.Row.builder() .params(DiscoveryParams.builder().category(CategoryFactory.artCategory()).build()) .build() ); clearPages.assertValues(Arrays.asList(0, 1, 2, 3)); vm.inputs.discoveryPagerAdapterSetPrimaryPage(null, 1); // Select MUSIC category from the drawer. vm.inputs.childFilterViewHolderRowClick(null, NavigationDrawerData.Section.Row.builder() .params(DiscoveryParams.builder().category(CategoryFactory.musicCategory()).build()) .build() ); clearPages.assertValues(Arrays.asList(0, 1, 2, 3), Arrays.asList(0, 2, 3, 4)); } @Test public void testRootCategoriesEmitWithPosition() { final DiscoveryViewModel vm = new DiscoveryViewModel(environment()); final TestSubscriber<List<Category>> rootCategories = new TestSubscriber<>(); final TestSubscriber<Integer> position = new TestSubscriber<>(); vm.outputs.rootCategoriesAndPosition().map(cp -> cp.first).subscribe(rootCategories); vm.outputs.rootCategoriesAndPosition().map(cp -> cp.second).subscribe(position); // Start initial activity. vm.intent(new Intent(Intent.ACTION_MAIN)); // Initial HOME page selected. vm.inputs.discoveryPagerAdapterSetPrimaryPage(null, 0); // Root categories should emit for the initial HOME sort position. rootCategories.assertValueCount(1); position.assertValues(0); // Select POPULAR sort position. vm.inputs.discoveryPagerAdapterSetPrimaryPage(null, 1); // Root categories should emit for the POPULAR sort position. rootCategories.assertValueCount(2); position.assertValues(0, 1); // Select ART category from the drawer. vm.inputs.childFilterViewHolderRowClick(null, NavigationDrawerData.Section.Row.builder() .params(DiscoveryParams.builder().category(CategoryFactory.artCategory()).build()) .build() ); // Root categories should not emit again for the same position. rootCategories.assertValueCount(2); position.assertValues(0, 1); } }