package com.kickstarter.viewmodels; import android.content.Intent; import android.support.annotation.NonNull; import com.kickstarter.KSRobolectricTestCase; import com.kickstarter.factories.ApiExceptionFactory; import com.kickstarter.libs.Environment; import com.kickstarter.services.ApiClientType; import com.kickstarter.services.MockApiClient; import com.kickstarter.services.apiresponses.AccessTokenEnvelope; import com.kickstarter.ui.IntentKey; import org.junit.Test; import rx.Observable; import rx.observers.TestSubscriber; public class LoginViewModelTest extends KSRobolectricTestCase { @Test public void testLoginButtonEnabled() { final LoginViewModel vm = new LoginViewModel(environment()); final TestSubscriber<Boolean> setLoginButtonIsEnabled = new TestSubscriber<>(); vm.outputs.setLoginButtonIsEnabled().subscribe(setLoginButtonIsEnabled); // Button should not be enabled until both a valid email and password are entered. vm.inputs.email("hello"); setLoginButtonIsEnabled.assertNoValues(); vm.inputs.email("hello@kickstarter.com"); setLoginButtonIsEnabled.assertNoValues(); vm.inputs.password(""); setLoginButtonIsEnabled.assertValues(false); vm.inputs.password("danisawesome"); setLoginButtonIsEnabled.assertValues(false, true); } @Test public void testLoginApiError() { final ApiClientType apiClient = new MockApiClient() { @Override public @NonNull Observable<AccessTokenEnvelope> login(final @NonNull String email, final @NonNull String password) { return Observable.error(ApiExceptionFactory.badRequestException()); } }; final Environment environment = environment().toBuilder().apiClient(apiClient).build(); final LoginViewModel vm = new LoginViewModel(environment); final TestSubscriber<Void> loginSuccess = new TestSubscriber<>(); vm.outputs.loginSuccess().subscribe(loginSuccess); final TestSubscriber<String> genericLoginError = new TestSubscriber<>(); vm.errors.genericLoginError().subscribe(genericLoginError); vm.inputs.email("incorrect@kickstarter.com"); vm.inputs.password("danisawesome"); vm.inputs.loginClick(); loginSuccess.assertNoValues(); genericLoginError.assertValueCount(1); } @Test public void testLoginApiValidationError() { final ApiClientType apiClient = new MockApiClient() { @Override public @NonNull Observable<AccessTokenEnvelope> login(final @NonNull String email, final @NonNull String password) { return Observable.error(ApiExceptionFactory.invalidLoginException()); } }; final Environment environment = environment().toBuilder().apiClient(apiClient).build(); final LoginViewModel vm = new LoginViewModel(environment); final TestSubscriber<String> invalidLoginError = new TestSubscriber<>(); vm.errors.invalidLoginError().subscribe(invalidLoginError); final TestSubscriber<Void> loginSuccess = new TestSubscriber<>(); vm.outputs.loginSuccess().subscribe(loginSuccess); vm.inputs.email("typo@kickstartr.com"); vm.inputs.password("danisawesome"); vm.inputs.loginClick(); loginSuccess.assertNoValues(); invalidLoginError.assertValueCount(1); } @Test public void testLoginTfaChallenge() { final ApiClientType apiClient = new MockApiClient() { @Override public @NonNull Observable<AccessTokenEnvelope> login(final @NonNull String email, final @NonNull String password) { return Observable.error(ApiExceptionFactory.tfaRequired()); } }; final Environment environment = environment().toBuilder().apiClient(apiClient).build(); final LoginViewModel vm = new LoginViewModel(environment); final TestSubscriber<Void> tfaChallenge = new TestSubscriber<>(); vm.errors.tfaChallenge().subscribe(tfaChallenge); final TestSubscriber<Void> loginSuccess = new TestSubscriber<>(); vm.outputs.loginSuccess().subscribe(loginSuccess); vm.inputs.email("hello@kickstarter.com"); vm.inputs.password("danisawesome"); vm.inputs.loginClick(); loginSuccess.assertNoValues(); tfaChallenge.assertValueCount(1); } @Test public void testPrefillEmailAndDialog() { final String email = "hello@kickstarter.com"; final LoginViewModel vm = new LoginViewModel(environment()); final TestSubscriber<String> prefillEmailFromPasswordReset = new TestSubscriber<>(); vm.outputs.prefillEmailFromPasswordReset().subscribe(prefillEmailFromPasswordReset); final TestSubscriber<Boolean> showResetPasswordSuccessDialog = new TestSubscriber<>(); vm.outputs.showResetPasswordSuccessDialog() .map(showAndEmail -> showAndEmail.first) .subscribe(showResetPasswordSuccessDialog); prefillEmailFromPasswordReset.assertNoValues(); showResetPasswordSuccessDialog.assertNoValues(); // Start the view model with an email to prefill. vm.intent(new Intent().putExtra(IntentKey.EMAIL, email)); prefillEmailFromPasswordReset.assertValue(email); showResetPasswordSuccessDialog.assertValue(true); // Dismiss the confirmation dialog. vm.inputs.resetPasswordConfirmationDialogDismissed(); // Simulate rotating the device. final TestSubscriber<String> rotatedPrefillEmailFromPasswordReset = new TestSubscriber<>(); vm.outputs.prefillEmailFromPasswordReset().subscribe(rotatedPrefillEmailFromPasswordReset); final TestSubscriber<Boolean> rotatedShowResetPasswordSuccessDialog = new TestSubscriber<>(); vm.outputs.showResetPasswordSuccessDialog() .map(showAndEmail -> showAndEmail.first) .subscribe(rotatedShowResetPasswordSuccessDialog); // Email should still be filled. Dialog should not be shown again. rotatedPrefillEmailFromPasswordReset.assertValue(email); rotatedShowResetPasswordSuccessDialog.assertValue(false); } @Test public void testSuccessfulLogin() { final LoginViewModel vm = new LoginViewModel(environment()); final TestSubscriber<Void> loginSuccess = new TestSubscriber<>(); vm.outputs.loginSuccess().subscribe(loginSuccess); vm.inputs.email("hello@kickstarter.com"); vm.inputs.password("danisawesome"); vm.inputs.loginClick(); loginSuccess.assertValueCount(1); koalaTest.assertValues("Login"); } }