package com.kickstarter.viewmodels;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.util.Pair;
import com.kickstarter.KSRobolectricTestCase;
import com.kickstarter.factories.ApiExceptionFactory;
import com.kickstarter.factories.BackingFactory;
import com.kickstarter.factories.MessageFactory;
import com.kickstarter.factories.MessageThreadEnvelopeFactory;
import com.kickstarter.factories.MessageThreadFactory;
import com.kickstarter.libs.Environment;
import com.kickstarter.models.Backing;
import com.kickstarter.models.Message;
import com.kickstarter.models.MessageThread;
import com.kickstarter.models.Project;
import com.kickstarter.models.User;
import com.kickstarter.services.MockApiClient;
import com.kickstarter.services.apiresponses.MessageThreadEnvelope;
import com.kickstarter.ui.IntentKey;
import org.junit.Test;
import java.util.Collections;
import java.util.List;
import rx.Observable;
import rx.observers.TestSubscriber;
public final class MessagesViewModelTest extends KSRobolectricTestCase {
private MessagesViewModel.ViewModel vm;
private final TestSubscriber<Pair<Backing, Project>> backingAndProject = new TestSubscriber<>();
private final TestSubscriber<Boolean> backingInfoViewHidden = new TestSubscriber<>();
private final TestSubscriber<String> participantNameTextViewText = new TestSubscriber<>();
private final TestSubscriber<List<Message>> messages = new TestSubscriber<>();
private final TestSubscriber<String> projectNameTextViewText = new TestSubscriber<>();
private final TestSubscriber<String> setMessageEditText = new TestSubscriber<>();
private final TestSubscriber<String> showMessageErrorToast = new TestSubscriber<>();
protected void setUpEnvironment(final @NonNull Environment environment) {
this.vm = new MessagesViewModel.ViewModel(environment);
this.vm.outputs.backingAndProject().subscribe(this.backingAndProject);
this.vm.outputs.backingInfoViewHidden().subscribe(this.backingInfoViewHidden);
this.vm.outputs.participantNameTextViewText().subscribe(this.participantNameTextViewText);
this.vm.outputs.messages().subscribe(this.messages);
this.vm.outputs.projectNameTextViewText().subscribe(this.projectNameTextViewText);
this.vm.outputs.setMessageEditText().subscribe(this.setMessageEditText);
this.vm.outputs.showMessageErrorToast().subscribe(this.showMessageErrorToast);
}
@Test
public void testBackingInfo_Backing() {
final MessageThread messageThread = MessageThreadFactory.messageThread().toBuilder()
.backing(BackingFactory.backing())
.build();
setUpEnvironment(environment());
// Start the view model with a message thread.
this.vm.intent(new Intent().putExtra(IntentKey.MESSAGE_THREAD, messageThread));
this.backingAndProject.assertValues(Pair.create(messageThread.backing(), messageThread.project()));
this.backingInfoViewHidden.assertValues(false);
}
@Test
public void testBackingInfo_NoBacking() {
final MessageThread messageThread = MessageThreadFactory.messageThread().toBuilder().backing(null).build();
final MockApiClient apiClient = new MockApiClient() {
@Override
public @NonNull Observable<Backing> fetchProjectBacking(final @NonNull Project project, final @NonNull User user) {
return Observable.just(null);
}
};
setUpEnvironment(environment().toBuilder().apiClient(apiClient).build());
// Start the view model with a message thread.
this.vm.intent(new Intent().putExtra(IntentKey.MESSAGE_THREAD, messageThread));
this.backingAndProject.assertNoValues();
this.backingInfoViewHidden.assertValues(true);
}
@Test
public void testProjectData() {
final MessageThread messageThread = MessageThreadFactory.messageThread();
setUpEnvironment(environment());
// Start the view model with a message thread.
this.vm.intent(new Intent().putExtra(IntentKey.MESSAGE_THREAD, messageThread));
this.participantNameTextViewText.assertValues(messageThread.project().creator().name());
this.projectNameTextViewText.assertValues(messageThread.project().name());
}
@Test
public void testMessagesEmit() {
final MessageThreadEnvelope envelope = MessageThreadEnvelopeFactory.messageThreadEnvelope()
.toBuilder()
.messages(Collections.singletonList(MessageFactory.message()))
.build();
final MockApiClient apiClient = new MockApiClient() {
@Override public @NonNull Observable<MessageThreadEnvelope> fetchMessagesForThread(final @NonNull MessageThread messageThread) {
return Observable.just(envelope);
}
};
setUpEnvironment(environment().toBuilder().apiClient(apiClient).build());
// Start the view model with a message thread.
this.vm.intent(new Intent().putExtra(IntentKey.MESSAGE_THREAD, MessageThreadFactory.messageThread()));
// Messages emit.
this.messages.assertValueCount(1);
}
@Test
public void testSendMessage_Error() {
final MockApiClient apiClient = new MockApiClient() {
@Override
public @NonNull Observable<Message> sendMessageToThread(final @NonNull MessageThread thread, final @NonNull String body) {
return Observable.error(ApiExceptionFactory.badRequestException());
}
};
setUpEnvironment(environment().toBuilder().apiClient(apiClient).build());
// Start the view model with a message thread.
this.vm.intent(new Intent().putExtra(IntentKey.MESSAGE_THREAD, MessageThreadFactory.messageThread()));
// Send a message unsuccessfully.
this.vm.inputs.messageEditTextChanged("Hello there");
this.vm.inputs.sendMessageButtonClicked();
// Error toast is displayed, errored message body remains in edit text.
this.showMessageErrorToast.assertValueCount(1);
this.setMessageEditText.assertNoValues();
}
@Test
public void testSendMessage_Success() {
final Message sentMessage = MessageFactory.message();
final MockApiClient apiClient = new MockApiClient() {
@Override
public @NonNull Observable<Message> sendMessageToThread(final @NonNull MessageThread thread, final @NonNull String body) {
return Observable.just(sentMessage);
}
};
setUpEnvironment(environment().toBuilder().apiClient(apiClient).build());
// Start the view model with a message thread.
this.vm.intent(new Intent().putExtra(IntentKey.MESSAGE_THREAD, MessageThreadFactory.messageThread()));
// Send a message successfully.
this.vm.inputs.messageEditTextChanged("Salutations friend!");
this.vm.inputs.sendMessageButtonClicked();
// Reply edit text should be cleared.
this.setMessageEditText.assertValueCount(1);
}
}