package co.smartreceipts.android.identity.widget.login; import android.content.Context; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import co.smartreceipts.android.R; import co.smartreceipts.android.identity.IdentityManager; import co.smartreceipts.android.identity.apis.login.LoginResponse; import co.smartreceipts.android.identity.apis.login.SmartReceiptsUserLogin; import co.smartreceipts.android.identity.apis.login.SmartReceiptsUserSignUp; import co.smartreceipts.android.identity.apis.login.UserCredentialsPayload; import co.smartreceipts.android.widget.model.UiIndicator; import io.reactivex.Observable; import io.reactivex.observers.TestObserver; import okhttp3.ResponseBody; import retrofit2.HttpException; import retrofit2.Response; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) public class LoginInteractorTest { // Class under test LoginInteractor interactor; Context context = RuntimeEnvironment.application; @Mock IdentityManager identityManager; SmartReceiptsUserLogin loginPayload = new SmartReceiptsUserLogin("email", "password"); SmartReceiptsUserSignUp signUpPayload = new SmartReceiptsUserSignUp("email", "password"); @Mock LoginResponse loginResponse; @Mock ResponseBody responseBody; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); interactor = new LoginInteractor(context, identityManager); } @Test public void getLastUserCredentialsPayloadDefaultsAsEmpty() { final TestObserver<UserCredentialsPayload> testObserver = interactor.getLastUserCredentialsPayload().test(); testObserver.assertNoValues(); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void loginSuccess() { when(identityManager.logInOrSignUp(loginPayload)).thenReturn(Observable.just(loginResponse)); final TestObserver<UiIndicator> testObserver = interactor.loginOrSignUp(loginPayload).test(); testObserver.assertValues(UiIndicator.loading(), UiIndicator.success(context.getString(R.string.login_success_toast))); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void signUpSuccess() { when(identityManager.logInOrSignUp(signUpPayload)).thenReturn(Observable.just(loginResponse)); final TestObserver<UiIndicator> testObserver = interactor.loginOrSignUp(signUpPayload).test(); testObserver.assertValues(UiIndicator.loading(), UiIndicator.success(context.getString(R.string.sign_up_success_toast))); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void loginErrorGeneric() { when(identityManager.logInOrSignUp(loginPayload)).thenReturn(Observable.error(new Exception())); final TestObserver<UiIndicator> testObserver = interactor.loginOrSignUp(loginPayload).test(); testObserver.assertValues(UiIndicator.loading(), UiIndicator.error(context.getString(R.string.login_failure_toast))); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void signUpErrorGeneric() { when(identityManager.logInOrSignUp(signUpPayload)).thenReturn(Observable.error(new Exception())); final TestObserver<UiIndicator> testObserver = interactor.loginOrSignUp(signUpPayload).test(); testObserver.assertValues(UiIndicator.loading(), UiIndicator.error(context.getString(R.string.sign_up_failure_toast))); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void loginErrorBadCredentials() { when(identityManager.logInOrSignUp(loginPayload)).thenReturn(Observable.error(new HttpException(Response.error(401, responseBody)))); final TestObserver<UiIndicator> testObserver = interactor.loginOrSignUp(loginPayload).test(); testObserver.assertValues(UiIndicator.loading(), UiIndicator.error(context.getString(R.string.login_failure_credentials_toast))); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void signUpErrorExistingAccount() { when(identityManager.logInOrSignUp(signUpPayload)).thenReturn(Observable.error(new HttpException(Response.error(420, responseBody)))); final TestObserver<UiIndicator> testObserver = interactor.loginOrSignUp(signUpPayload).test(); testObserver.assertValues(UiIndicator.loading(), UiIndicator.error(context.getString(R.string.sign_up_failure_account_exists_toast))); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void requestsGetCachedUntilConsumed() { when(identityManager.logInOrSignUp(loginPayload)).thenReturn(Observable.just(loginResponse)); final TestObserver<UiIndicator> preTestObserver = interactor.loginOrSignUp(loginPayload).test(); preTestObserver.assertValues(UiIndicator.loading(), UiIndicator.success(context.getString(R.string.login_success_toast))); preTestObserver.assertComplete(); preTestObserver.assertNoErrors(); final TestObserver<UserCredentialsPayload> preMaybeTestObserver = interactor.getLastUserCredentialsPayload().test(); preMaybeTestObserver.assertValues(loginPayload); preMaybeTestObserver.assertComplete(); preMaybeTestObserver.assertNoErrors(); final TestObserver<UiIndicator> postTestObserver = interactor.getLastUserCredentialsPayload().flatMapObservable(interactor::loginOrSignUp).test(); postTestObserver.assertValues(UiIndicator.loading(), UiIndicator.success(context.getString(R.string.login_success_toast))); postTestObserver.assertComplete(); postTestObserver.assertNoErrors(); // Consume interactor.onLoginResultsConsumed(); final TestObserver<UserCredentialsPayload> postMaybeTestObserver = interactor.getLastUserCredentialsPayload().test(); postMaybeTestObserver.assertNoValues(); postMaybeTestObserver.assertComplete(); postMaybeTestObserver.assertNoErrors(); // And confirm we only made the actual API call once verify(identityManager).logInOrSignUp(loginPayload); } }