package io.github.hidroh.materialistic; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.support.annotation.NonNull; import android.support.design.widget.TabLayout; import android.support.v7.widget.RecyclerView; import android.view.KeyEvent; import android.widget.TextView; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowToast; import org.robolectric.util.ActivityController; import javax.inject.Inject; import javax.inject.Named; import io.github.hidroh.materialistic.data.Item; import io.github.hidroh.materialistic.data.ItemManager; import io.github.hidroh.materialistic.data.ResponseListener; import io.github.hidroh.materialistic.data.TestHnItem; import io.github.hidroh.materialistic.data.UserManager; import io.github.hidroh.materialistic.test.TestRunner; import io.github.hidroh.materialistic.test.shadow.ShadowRecyclerView; import io.github.hidroh.materialistic.test.shadow.ShadowRecyclerViewAdapter; import static io.github.hidroh.materialistic.test.shadow.CustomShadows.customShadowOf; import static junit.framework.Assert.assertEquals; import static org.assertj.android.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; @Config(shadows = ShadowRecyclerViewAdapter.class) @RunWith(TestRunner.class) public class UserActivityTest { private ActivityController<UserActivity> controller; private UserActivity activity; @Inject UserManager userManager; @Inject @Named(ActivityModule.HN) ItemManager itemManager; @Inject KeyDelegate keyDelegate; @Captor ArgumentCaptor<ResponseListener<UserManager.User>> userCaptor; @Captor ArgumentCaptor<ResponseListener<Item>> itemCaptor; private UserManager.User user; @Before public void setUp() { MockitoAnnotations.initMocks(this); TestApplication.applicationGraph.inject(this); reset(userManager); reset(itemManager); reset(keyDelegate); controller = Robolectric.buildActivity(UserActivity.class); Intent intent = new Intent(); intent.putExtra(UserActivity.EXTRA_USERNAME, "username"); activity = controller.withIntent(intent).create().start().resume().visible().get(); user = mock(UserManager.User.class); when(user.getId()).thenReturn("username"); when(user.getCreated(any(Context.class))).thenReturn("May 01 2015"); when(user.getKarma()).thenReturn(2016L); when(user.getAbout()).thenReturn("about"); when(user.getItems()).thenReturn(new Item[]{ new TestHnItem(1L){ @NonNull @Override public String getType() { return COMMENT_TYPE; } }, new TestHnItem(2L) { @NonNull @Override public String getType() { return STORY_TYPE; } } }); } @Test public void testBinding() { verify(userManager).getUser(eq("username"), userCaptor.capture()); userCaptor.getValue().onResponse(user); assertThat((TextView) activity.findViewById(R.id.title)).hasTextString("username (2,016)"); assertThat((TextView) activity.findViewById(R.id.about)).hasTextString("about"); assertEquals(activity.getResources().getQuantityString(R.plurals.submissions_count, 2, 2), ((TabLayout) activity.findViewById(R.id.tab_layout)).getTabAt(0).getText()); assertEquals(2, (((RecyclerView) activity.findViewById(R.id.recycler_view)).getAdapter()) .getItemCount()); shadowOf(activity).recreate(); assertThat((TextView) activity.findViewById(R.id.title)).hasTextString("username (2,016)"); } @Test public void testBindingNoAbout() { when(user.getAbout()).thenReturn(null); verify(userManager).getUser(eq("username"), userCaptor.capture()); userCaptor.getValue().onResponse(user); assertThat((TextView) activity.findViewById(R.id.about)).isNotVisible(); } @Test public void testEmpty() { verify(userManager).getUser(eq("username"), userCaptor.capture()); userCaptor.getValue().onResponse(null); assertThat(activity.findViewById(R.id.empty)).isVisible(); } @Test public void testFailed() { verify(userManager).getUser(eq("username"), userCaptor.capture()); userCaptor.getValue().onError(null); assertEquals(activity.getString(R.string.user_failed), ShadowToast.getTextOfLatestToast()); } @Config(shadows = ShadowRecyclerView.class) @Test public void testScrollToTop() { verify(userManager).getUser(eq("username"), userCaptor.capture()); userCaptor.getValue().onResponse(user); RecyclerView recyclerView = (RecyclerView) activity.findViewById(R.id.recycler_view); recyclerView.smoothScrollToPosition(1); assertThat(customShadowOf(recyclerView).getScrollPosition()).isEqualTo(1); TabLayout.Tab tab = ((TabLayout) activity.findViewById(R.id.tab_layout)).getTabAt(0); tab.select(); tab.select(); assertThat(customShadowOf(recyclerView).getScrollPosition()).isEqualTo(0); } @Test public void testNoId() { controller = Robolectric.buildActivity(UserActivity.class); activity = controller.create().get(); assertThat(activity).isFinishing(); } @Test public void testNoDataId() { controller = Robolectric.buildActivity(UserActivity.class); Intent intent = new Intent(); intent.setData(Uri.parse(BuildConfig.APPLICATION_ID + "://user/")); activity = controller.withIntent(intent).create().get(); assertThat(activity).isFinishing(); } @Test public void testWithDataId() { controller = Robolectric.buildActivity(UserActivity.class); Intent intent = new Intent(); intent.setData(Uri.parse(BuildConfig.APPLICATION_ID + "://user/123")); activity = controller.withIntent(intent).create().get(); assertThat(activity).isNotFinishing(); } @Test public void testDeepLink() { controller = Robolectric.buildActivity(UserActivity.class); Intent intent = new Intent(); intent.setData(Uri.parse("https://news.ycombinator.com/user?id=123")); activity = controller.withIntent(intent).create().get(); assertThat(activity).isNotFinishing(); } @Test public void testCommentBinding() { verify(userManager).getUser(eq("username"), userCaptor.capture()); userCaptor.getValue().onResponse(user); RecyclerView recyclerView = (RecyclerView) activity.findViewById(R.id.recycler_view); verify(itemManager).getItem(eq("1"), eq(ItemManager.MODE_DEFAULT), itemCaptor.capture()); itemCaptor.getValue().onResponse(new TestHnItem(1L) { @Override public String getText() { return "content"; } @Override public String getParent() { return "2"; } }); RecyclerView.ViewHolder viewHolder = customShadowOf(recyclerView.getAdapter()).getViewHolder(0); assertThat(viewHolder.itemView.findViewById(R.id.title)).isNotVisible(); assertThat((TextView) viewHolder.itemView.findViewById(R.id.text)) .isVisible() .hasTextString("content"); viewHolder.itemView.findViewById(R.id.comment).performClick(); assertThat(shadowOf(activity).getNextStartedActivity()) .hasComponent(activity, ThreadPreviewActivity.class) .hasExtra(ThreadPreviewActivity.EXTRA_ITEM); } @Test public void testStoryBinding() { verify(userManager).getUser(eq("username"), userCaptor.capture()); userCaptor.getValue().onResponse(user); RecyclerView recyclerView = (RecyclerView) activity.findViewById(R.id.recycler_view); verify(itemManager).getItem(eq("2"), eq(ItemManager.MODE_DEFAULT), itemCaptor.capture()); itemCaptor.getValue().onResponse(new TestHnItem(2L) { @Override public String getTitle() { return "title"; } @Override public String getText() { return "content"; } @Override public int getScore() { return 46; } }); RecyclerView.ViewHolder viewHolder = customShadowOf(recyclerView.getAdapter()).getViewHolder(1); assertThat((TextView) viewHolder.itemView.findViewById(R.id.posted)) .containsText(activity.getResources().getQuantityString(R.plurals.score, 46, 46)); assertThat((TextView) viewHolder.itemView.findViewById(R.id.title)) .isVisible() .hasTextString("title"); assertThat((TextView) viewHolder.itemView.findViewById(R.id.text)) .isVisible() .hasTextString("content"); viewHolder.itemView.findViewById(R.id.comment).performClick(); assertThat(shadowOf(activity).getNextStartedActivity()) .hasComponent(activity, ItemActivity.class) .hasExtra(ItemActivity.EXTRA_ITEM); } @Test public void testDeletedItemBinding() { verify(userManager).getUser(eq("username"), userCaptor.capture()); userCaptor.getValue().onResponse(user); RecyclerView recyclerView = (RecyclerView) activity.findViewById(R.id.recycler_view); verify(itemManager).getItem(eq("1"), eq(ItemManager.MODE_DEFAULT), itemCaptor.capture()); itemCaptor.getValue().onResponse(new TestHnItem(1L) { @Override public boolean isDeleted() { return true; } }); RecyclerView.ViewHolder viewHolder = customShadowOf(recyclerView.getAdapter()).getViewHolder(0); assertThat(viewHolder.itemView.findViewById(R.id.comment)).isNotVisible(); } @Test public void testVolumeNavigation() { activity.onKeyDown(KeyEvent.KEYCODE_VOLUME_UP, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)); verify(keyDelegate).setScrollable(any(Scrollable.class), any()); verify(keyDelegate).onKeyDown(anyInt(), any(KeyEvent.class)); activity.onKeyUp(KeyEvent.KEYCODE_VOLUME_UP, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_VOLUME_UP)); verify(keyDelegate).onKeyUp(anyInt(), any(KeyEvent.class)); activity.onKeyLongPress(KeyEvent.KEYCODE_VOLUME_UP, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)); verify(keyDelegate).onKeyLongPress(anyInt(), any(KeyEvent.class)); } @After public void tearDown() { controller.pause().stop().destroy(); } }