feat(app): 收藏与观看历史支持分页
This commit is contained in:
1 parent
ec15950851
commit
71b0c7315a
11 files changed
+672
-37
No files matched your search
+183
@@ -0,0 +1,183 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
package com.fruitshorts.app.controller;
|
||||
|
||||
import com.fruitshorts.app.service.AppCatalogService;
|
||||
import com.fruitshorts.app.support.ControllerContractSupport;
|
||||
import com.fruitshorts.app.vo.AppDramaCardVO;
|
||||
import com.fruitshorts.common.pojo.PageResult;
|
||||
import com.fruitshorts.content.dal.entity.Drama;
|
||||
import com.fruitshorts.framework.security.LoginUser;
|
||||
import com.fruitshorts.playback.service.FavoriteService;
|
||||
import com.fruitshorts.playback.service.WatchProgressService;
|
||||
import com.fruitshorts.playback.vo.ProgressRespVO;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/** 客户端收藏与观看历史分页契约。 */
|
||||
class AppLibraryPagingContractTest {
|
||||
|
||||
private static final long USER_ID = 1001L;
|
||||
|
||||
private FavoriteService favoriteService;
|
||||
private AppCatalogService catalogService;
|
||||
private WatchProgressService progressService;
|
||||
private MockMvc favoriteMvc;
|
||||
private MockMvc watchMvc;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
favoriteService = mock(FavoriteService.class);
|
||||
catalogService = mock(AppCatalogService.class);
|
||||
progressService = mock(WatchProgressService.class);
|
||||
favoriteMvc = ControllerContractSupport.mockMvcOf(
|
||||
new AppFavoriteController(favoriteService, catalogService));
|
||||
watchMvc = ControllerContractSupport.mockMvcOf(
|
||||
new AppWatchController(progressService));
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken(
|
||||
new LoginUser(USER_ID, "app-user", "APP_USER", List.of()),
|
||||
null,
|
||||
List.of()));
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_page_favorites_with_default_size_and_non_overlapping_second_page()
|
||||
throws Exception {
|
||||
Drama first = drama(101L, "收藏一");
|
||||
Drama second = drama(102L, "收藏二");
|
||||
Drama third = drama(103L, "收藏三");
|
||||
given(favoriteService.page(USER_ID, 1, 20))
|
||||
.willReturn(new PageResult<>(21L, List.of(first, second)));
|
||||
given(favoriteService.page(USER_ID, 2, 20))
|
||||
.willReturn(new PageResult<>(21L, List.of(third)));
|
||||
given(catalogService.toCards(List.of(first, second)))
|
||||
.willReturn(List.of(card(101L), card(102L)));
|
||||
given(catalogService.toCards(List.of(third)))
|
||||
.willReturn(List.of(card(103L)));
|
||||
|
||||
favoriteMvc.perform(get("/app/favorites"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.total").value("21"))
|
||||
.andExpect(jsonPath("$.data.list.length()").value(2))
|
||||
.andExpect(jsonPath("$.data.list[0].id").value("101"))
|
||||
.andExpect(jsonPath("$.data.list[1].id").value("102"));
|
||||
|
||||
favoriteMvc.perform(get("/app/favorites").param("pageIndex", "2"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data.total").value("21"))
|
||||
.andExpect(jsonPath("$.data.list.length()").value(1))
|
||||
.andExpect(jsonPath("$.data.list[0].id").value("103"));
|
||||
|
||||
verify(favoriteService).page(USER_ID, 1, 20);
|
||||
verify(favoriteService).page(USER_ID, 2, 20);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_page_recent_watch_with_display_fields() throws Exception {
|
||||
ProgressRespVO first = progress(12L, 88L, 6, "剧名一", 68);
|
||||
ProgressRespVO second = progress(13L, 99L, 2, "剧名二", 20);
|
||||
ProgressRespVO third = progress(14L, 100L, 1, "剧名三", 16);
|
||||
given(progressService.recentPage(USER_ID, 1, 20))
|
||||
.willReturn(new PageResult<>(23L, List.of(first, second)));
|
||||
given(progressService.recentPage(USER_ID, 2, 20))
|
||||
.willReturn(new PageResult<>(23L, List.of(third)));
|
||||
|
||||
watchMvc.perform(get("/app/watch/recent"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data.total").value("23"))
|
||||
.andExpect(jsonPath("$.data.list.length()").value(2))
|
||||
.andExpect(jsonPath("$.data.list[0].dramaTitle").value("剧名一"))
|
||||
.andExpect(jsonPath("$.data.list[0].episodeNumber").value(6))
|
||||
.andExpect(jsonPath("$.data.list[0].totalEpisodes").value(68))
|
||||
.andExpect(jsonPath("$.data.list[1].dramaTitle").value("剧名二"))
|
||||
.andExpect(jsonPath("$.data.list[1].episodeNumber").value(2));
|
||||
|
||||
watchMvc.perform(get("/app/watch/recent").param("pageIndex", "2"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data.total").value("23"))
|
||||
.andExpect(jsonPath("$.data.list.length()").value(1))
|
||||
.andExpect(jsonPath("$.data.list[0].dramaId").value("14"))
|
||||
.andExpect(jsonPath("$.data.list[0].dramaTitle").value("剧名三"));
|
||||
|
||||
verify(progressService).recentPage(USER_ID, 1, 20);
|
||||
verify(progressService).recentPage(USER_ID, 2, 20);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_keep_total_and_return_empty_list_when_watch_page_is_out_of_range()
|
||||
throws Exception {
|
||||
given(progressService.recentPage(USER_ID, 9, 20))
|
||||
.willReturn(new PageResult<>(23L, List.of()));
|
||||
|
||||
watchMvc.perform(get("/app/watch/recent").param("pageIndex", "9"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data.total").value("23"))
|
||||
.andExpect(jsonPath("$.data.list").isArray())
|
||||
.andExpect(jsonPath("$.data.list").isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_return_legacy_list_when_recent_limit_is_present() throws Exception {
|
||||
given(progressService.recent(USER_ID, 5))
|
||||
.willReturn(List.of(progress(12L, 88L, 6, "剧名一", 68)));
|
||||
|
||||
watchMvc.perform(get("/app/watch/recent").param("limit", "5"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.data").isArray())
|
||||
.andExpect(jsonPath("$.data[0].dramaTitle").value("剧名一"))
|
||||
.andExpect(jsonPath("$.data[0].episodeNumber").value(6));
|
||||
|
||||
verify(progressService).recent(USER_ID, 5);
|
||||
}
|
||||
|
||||
private Drama drama(Long id, String title) {
|
||||
Drama drama = new Drama();
|
||||
drama.setId(id);
|
||||
drama.setTitle(title);
|
||||
return drama;
|
||||
}
|
||||
|
||||
private AppDramaCardVO card(Long id) {
|
||||
AppDramaCardVO card = new AppDramaCardVO();
|
||||
card.setId(id);
|
||||
return card;
|
||||
}
|
||||
|
||||
private ProgressRespVO progress(Long dramaId, Long episodeId, int episodeNumber,
|
||||
String dramaTitle, int totalEpisodes) {
|
||||
ProgressRespVO vo = new ProgressRespVO();
|
||||
vo.setDramaId(dramaId);
|
||||
vo.setEpisodeId(episodeId);
|
||||
vo.setEpisodeNumber(episodeNumber);
|
||||
vo.setDramaTitle(dramaTitle);
|
||||
vo.setDramaCover("/files/cover/" + dramaId + ".jpg");
|
||||
vo.setTotalEpisodes(totalEpisodes);
|
||||
vo.setPositionMs(80_000L);
|
||||
vo.setDurationMs(120_000L);
|
||||
vo.setFinished(false);
|
||||
vo.setPlayCount(1);
|
||||
vo.setUpdatedAt(LocalDateTime.of(2026, 10, 22, 10, 0));
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user