package com.kickstarter.viewmodels;
import android.support.annotation.NonNull;
import com.kickstarter.KSRobolectricTestCase;
import com.kickstarter.factories.ActivityFactory;
import com.kickstarter.factories.ConfigFactory;
import com.kickstarter.factories.SurveyResponseFactory;
import com.kickstarter.factories.UserFactory;
import com.kickstarter.libs.Config;
import com.kickstarter.libs.CurrentConfigType;
import com.kickstarter.libs.CurrentUserType;
import com.kickstarter.libs.Environment;
import com.kickstarter.libs.FeatureKey;
import com.kickstarter.libs.KoalaEvent;
import com.kickstarter.libs.MockCurrentConfig;
import com.kickstarter.libs.MockCurrentUser;
import com.kickstarter.models.Activity;
import com.kickstarter.models.Project;
import com.kickstarter.models.SurveyResponse;
import com.kickstarter.services.ApiClientType;
import com.kickstarter.services.MockApiClient;
import com.kickstarter.viewmodels.ActivityFeedViewModel.ViewModel;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import rx.Observable;
import rx.observers.TestSubscriber;
import rx.schedulers.TestScheduler;
public class ActivityFeedViewModelTest extends KSRobolectricTestCase {
private ViewModel vm;
final TestSubscriber<List<Activity>> activities = new TestSubscriber<>();
final TestSubscriber<Void> goToDiscovery = new TestSubscriber<>();
final TestSubscriber<Void> goToLogin = new TestSubscriber<>();
final TestSubscriber<Project> goToProject = new TestSubscriber<>();
final TestSubscriber<Activity> goToProjectUpdate = new TestSubscriber<>();
final TestSubscriber<SurveyResponse> goToSurvey = new TestSubscriber<>();
final TestSubscriber<Boolean> loggedOutEmptyStateIsVisible = new TestSubscriber<>();
final TestSubscriber<Boolean> loggedInEmptyStateIsVisible = new TestSubscriber<>();
final TestSubscriber<List<SurveyResponse>> surveys = new TestSubscriber<>();
private void setUpEnvironment(final @NonNull Environment environment) {
this.vm = new ViewModel(environment);
this.vm.outputs.activities().subscribe(this.activities);
this.vm.outputs.goToDiscovery().subscribe(this.goToDiscovery);
this.vm.outputs.goToLogin().subscribe(this.goToLogin);
this.vm.outputs.goToProject().subscribe(this.goToProject);
this.vm.outputs.goToProjectUpdate().subscribe(this.goToProjectUpdate);
this.vm.outputs.goToSurvey().subscribe(this.goToSurvey);
this.vm.outputs.loggedOutEmptyStateIsVisible().subscribe(this.loggedOutEmptyStateIsVisible);
this.vm.outputs.loggedInEmptyStateIsVisible().subscribe(this.loggedInEmptyStateIsVisible);
this.vm.outputs.surveys().subscribe(this.surveys);
}
@Test
public void testActivitiesEmit() {
setUpEnvironment(environment());
// Initialize the paginator.
this.vm.inputs.refresh();
// Activities should emit.
this.activities.assertValueCount(1);
this.koalaTest.assertValue(KoalaEvent.ACTIVITY_VIEW);
// Paginate.
this.vm.inputs.nextPage();
this.activities.assertValueCount(1);
this.koalaTest.assertValues(KoalaEvent.ACTIVITY_VIEW, KoalaEvent.ACTIVITY_LOAD_MORE);
}
@Test
public void testClickingInterfaceElements() {
this.setUpEnvironment(this.environment());
this.goToDiscovery.assertNoValues();
this.goToLogin.assertNoValues();
this.goToProject.assertNoValues();
this.goToProjectUpdate.assertNoValues();
this.koalaTest.assertValues(KoalaEvent.ACTIVITY_VIEW);
// Empty activity feed clicks do not trigger events yet.
this.vm.inputs.emptyActivityFeedDiscoverProjectsClicked(null);
this.goToDiscovery.assertValueCount(1);
this.vm.inputs.emptyActivityFeedLoginClicked(null);
this.goToLogin.assertValueCount(1);
this.vm.inputs.friendBackingClicked(null, ActivityFactory.friendBackingActivity());
this.vm.inputs.projectStateChangedClicked(null, ActivityFactory.projectStateChangedActivity());
this.vm.inputs.projectStateChangedPositiveClicked(null, ActivityFactory.projectStateChangedPositiveActivity());
this.vm.inputs.projectUpdateProjectClicked(null, ActivityFactory.updateActivity());
this.koalaTest.assertValues(
KoalaEvent.ACTIVITY_VIEW, KoalaEvent.ACTIVITY_VIEW_ITEM, KoalaEvent.ACTIVITY_VIEW_ITEM, KoalaEvent.ACTIVITY_VIEW_ITEM,
KoalaEvent.ACTIVITY_VIEW_ITEM
);
this.goToProject.assertValueCount(4);
this.vm.inputs.projectUpdateClicked(null, ActivityFactory.activity());
this.goToProjectUpdate.assertValueCount(1);
this.koalaTest.assertValues(
KoalaEvent.ACTIVITY_VIEW, KoalaEvent.ACTIVITY_VIEW_ITEM, KoalaEvent.ACTIVITY_VIEW_ITEM, KoalaEvent.ACTIVITY_VIEW_ITEM,
KoalaEvent.ACTIVITY_VIEW_ITEM, KoalaEvent.VIEWED_UPDATE
);
}
@Test
public void testLoginFlow() {
final ApiClientType apiClient = new MockApiClient();
final CurrentUserType currentUser = new MockCurrentUser();
final Environment environment = this.environment().toBuilder()
.apiClient(apiClient)
.currentUser(currentUser)
.build();
setUpEnvironment(environment);
// Empty activity feed with login button should be shown.
this.loggedOutEmptyStateIsVisible.assertValue(true);
// Login.
this.vm.inputs.emptyActivityFeedLoginClicked(null);
this.goToLogin.assertValueCount(1);
currentUser.refresh(UserFactory.user());
// Empty states are not shown when activities emit on successful login.
this.activities.assertValueCount(1);
this.loggedOutEmptyStateIsVisible.assertValues(true, false);
this.loggedInEmptyStateIsVisible.assertValue(false);
}
@Test
public void testSurveyClick() {
final SurveyResponse surveyResponse = SurveyResponseFactory.surveyResponse();
setUpEnvironment(environment());
this.vm.inputs.surveyClicked(null, surveyResponse);
this.goToSurvey.assertValue(surveyResponse);
}
@Test
public void testNoSurveyFeatureFlag() {
final ApiClientType apiClient = new MockApiClient();
final CurrentUserType currentUser = new MockCurrentUser();
currentUser.login(UserFactory.user(), "deadbeef");
final Config config = ConfigFactory.config().toBuilder()
.features(Collections.EMPTY_MAP).build();
final CurrentConfigType currentConfig = new MockCurrentConfig();
currentConfig.config(config);
final Environment environment = this.environment().toBuilder()
.apiClient(apiClient)
.currentUser(currentUser)
.currentConfig(currentConfig)
.build();
setUpEnvironment(environment);
this.vm.inputs.resume();
this.surveys.assertValue(Collections.emptyList());
}
@Test
public void testSurveyFeatureFlagFalse() {
final TestScheduler scheduler = new TestScheduler();
final List<SurveyResponse> surveyResponses = Arrays.asList(
SurveyResponseFactory.surveyResponse(),
SurveyResponseFactory.surveyResponse()
);
final MockApiClient apiClient = new MockApiClient() {
@Override
public @NonNull Observable<List<SurveyResponse>> fetchUnansweredSurveys() {
return Observable.just(surveyResponses);
}
};
final CurrentUserType currentUser = new MockCurrentUser();
currentUser.login(UserFactory.user(), "deadbeef");
final Map<String, Boolean> featureMap = new HashMap<>();
featureMap.put(FeatureKey.ANDROID_SURVEYS, false);
final Config config = ConfigFactory.config().toBuilder()
.features(featureMap).build();
final CurrentConfigType currentConfig = new MockCurrentConfig();
currentConfig.config(config);
final Environment environment = this.environment().toBuilder()
.scheduler(scheduler)
.apiClient(apiClient)
.currentUser(currentUser)
.currentConfig(currentConfig)
.build();
setUpEnvironment(environment);
this.vm.inputs.resume();
this.surveys.assertValues(Collections.emptyList());
}
@Test
public void testSurveyFeatureFlagTrue() {
final TestScheduler scheduler = new TestScheduler();
final List<SurveyResponse> surveyResponses = Arrays.asList(
SurveyResponseFactory.surveyResponse(),
SurveyResponseFactory.surveyResponse()
);
final MockApiClient apiClient = new MockApiClient() {
@Override
public @NonNull Observable<List<SurveyResponse>> fetchUnansweredSurveys() {
return Observable.just(surveyResponses);
}
};
final CurrentUserType currentUser = new MockCurrentUser();
currentUser.login(UserFactory.user(), "deadbeef");
final Map<String, Boolean> featureMap = new HashMap<>();
featureMap.put(FeatureKey.ANDROID_SURVEYS, true);
final Config config = ConfigFactory.config().toBuilder()
.features(featureMap).build();
final CurrentConfigType currentConfig = new MockCurrentConfig();
currentConfig.config(config);
final Environment environment = this.environment().toBuilder()
.scheduler(scheduler)
.apiClient(apiClient)
.currentUser(currentUser)
.currentConfig(currentConfig)
.build();
setUpEnvironment(environment);
this.vm.inputs.resume();
this.surveys.assertValues(surveyResponses);
}
@Test
public void testSurveyFeatureFlagUserLoggedOut() {
final TestScheduler scheduler = new TestScheduler();
final List<SurveyResponse> surveyResponses = Arrays.asList(
SurveyResponseFactory.surveyResponse(),
SurveyResponseFactory.surveyResponse()
);
final MockApiClient apiClient = new MockApiClient() {
@Override
public @NonNull Observable<List<SurveyResponse>> fetchUnansweredSurveys() {
return Observable.just(surveyResponses);
}
};
final CurrentUserType currentUser = new MockCurrentUser();
currentUser.logout();
final Map<String, Boolean> featureMap = new HashMap<>();
featureMap.put(FeatureKey.ANDROID_SURVEYS, true);
final Config config = ConfigFactory.config().toBuilder()
.features(featureMap).build();
final CurrentConfigType currentConfig = new MockCurrentConfig();
currentConfig.config(config);
final Environment environment = this.environment().toBuilder()
.scheduler(scheduler)
.apiClient(apiClient)
.currentUser(currentUser)
.currentConfig(currentConfig)
.build();
setUpEnvironment(environment);
this.vm.inputs.resume();
this.surveys.assertNoValues();
}
@Test
public void testSurveyFeatureFlagTrueLoggedInButNotResumed() {
final TestScheduler scheduler = new TestScheduler();
final List<SurveyResponse> surveyResponses = Arrays.asList(
SurveyResponseFactory.surveyResponse(),
SurveyResponseFactory.surveyResponse()
);
final MockApiClient apiClient = new MockApiClient() {
@Override
public @NonNull Observable<List<SurveyResponse>> fetchUnansweredSurveys() {
return Observable.just(surveyResponses);
}
};
final CurrentUserType currentUser = new MockCurrentUser();
currentUser.login(UserFactory.user(), "deadbeef");
final Map<String, Boolean> featureMap = new HashMap<>();
featureMap.put(FeatureKey.ANDROID_SURVEYS, true);
final Config config = ConfigFactory.config().toBuilder()
.features(featureMap).build();
final CurrentConfigType currentConfig = new MockCurrentConfig();
currentConfig.config(config);
final Environment environment = this.environment().toBuilder()
.scheduler(scheduler)
.apiClient(apiClient)
.currentUser(currentUser)
.currentConfig(currentConfig)
.build();
setUpEnvironment(environment);
this.surveys.assertNoValues();
}
}