From 829ff53526616113c95a7d7112b5cfd831ce6b66 Mon Sep 17 00:00:00 2001 From: kdletters Date: Wed, 24 Jun 2026 21:50:33 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AB=AF=E4=BB=85=E4=BF=9D?= =?UTF-8?q?=E7=95=99=E6=88=91=E7=9A=84=E9=A1=B5=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移动端底部导航只展示我的页签 隐藏移动端活动页签时回落到我的页 更新首页页签相关组件测试 --- .../RpgEntryHomeView.recharge.test.tsx | 168 +++++++++--------- src/components/rpg-entry/RpgEntryHomeView.tsx | 13 +- 2 files changed, 83 insertions(+), 98 deletions(-) diff --git a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx index f5148ec59..7ac2c3853 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx @@ -1142,14 +1142,19 @@ function renderStatefulLoggedOutHomeView( > > = {}, isDesktopLayout = false, + options: { + initialActiveTab?: RpgEntryHomeViewProps['activeTab']; + allowHiddenActiveTab?: boolean; + } = {}, ) { const authSpies = { openLoginModal: vi.fn(), }; function StatefulLoggedOutHomeView() { - const [activeTab, setActiveTab] = - useState('category'); + const [activeTab, setActiveTab] = useState< + RpgEntryHomeViewProps['activeTab'] + >(options.initialActiveTab ?? 'category'); return ( { expect(openLoginModal).toHaveBeenCalledTimes(1); }); -test('logged out bottom nav turns active recommend tab into next action', () => { - const { container } = renderLoggedOutHomeView(vi.fn()); +test('logged out mobile bottom nav only shows profile tab', () => { + const { container } = renderLoggedOutHomeView(vi.fn(), {}, 'profile'); const nav = container.querySelector('.platform-bottom-nav'); expect(nav).toBeTruthy(); expect(nav?.classList.contains('platform-bottom-nav')).toBe(true); + expect(nav?.classList.contains('grid-cols-1')).toBe(true); const buttons = within(nav as HTMLElement).getAllByRole('button'); - expect(buttons.map((button) => button.textContent)).toEqual([ - '下一个', - '发现', - '我的', - ]); - expect(buttons[0]?.querySelector('.lucide-chevron-down')).toBeTruthy(); - expect(buttons[1]?.querySelector('.lucide-compass')).toBeTruthy(); - expect(buttons[2]?.querySelector('.lucide-user-round')).toBeTruthy(); + expect(buttons.map((button) => button.textContent)).toEqual(['我的']); + expect(buttons[0]?.querySelector('.lucide-user-round')).toBeTruthy(); + expect( + within(nav as HTMLElement).queryByRole('button', { name: '推荐' }), + ).toBeNull(); + expect( + within(nav as HTMLElement).queryByRole('button', { name: '发现' }), + ).toBeNull(); expect( within(nav as HTMLElement).queryByRole('button', { name: '创作' }), ).toBeNull(); @@ -3809,24 +3816,24 @@ test('logged out bottom nav turns active recommend tab into next action', () => ).toBeTruthy(); }); -test('logged in mobile bottom nav hides draft and project entries', () => { +test('logged in mobile bottom nav only shows profile tab', () => { const { container } = renderLoggedInHomeView({ + activeTab: 'profile', hasUnreadDraftUpdate: true, draftTabContent:
草稿内容
, }); const nav = container.querySelector('.platform-bottom-nav'); expect(nav).toBeTruthy(); + expect(nav?.classList.contains('grid-cols-1')).toBe(true); + const buttons = within(nav as HTMLElement).getAllByRole('button'); + expect(buttons.map((button) => button.textContent)).toEqual(['我的']); expect( - within(nav as HTMLElement).getByRole('button', { name: '推荐' }), - ).toBeTruthy(); + within(nav as HTMLElement).queryByRole('button', { name: '推荐' }), + ).toBeNull(); expect( - within(nav as HTMLElement).getByRole('button', { name: '发现' }), - ).toBeTruthy(); - expect( - within(nav as HTMLElement).getByRole('button', { name: '我的' }), - ).toBeTruthy(); - + within(nav as HTMLElement).queryByRole('button', { name: '发现' }), + ).toBeNull(); expect( within(nav as HTMLElement).queryByRole('button', { name: '草稿,有新草稿', @@ -4106,7 +4113,6 @@ test('mobile discover search submits public work code', async () => { const onSearchPublicCode = vi.fn(); renderStatefulLoggedOutHomeView({ onSearchPublicCode }); - await user.click(screen.getByRole('button', { name: '发现' })); const searchInput = screen.getByPlaceholderText('搜索作品号、名称、作者、描述'); @@ -4145,7 +4151,6 @@ test('discover search fuzzy matches public work id, name, author and description onOpenGalleryDetail, onSearchPublicCode, }); - await user.click(screen.getByRole('button', { name: '发现' })); const discoverPanel = document.getElementById('platform-tab-panel-category'); if (!discoverPanel) { throw new Error('缺少发现面板'); @@ -4212,7 +4217,6 @@ test('mobile discover keeps edutainment works in the last dedicated channel only onOpenChildMotionDemo, onSearchPublicCode, }); - await user.click(screen.getByRole('button', { name: '发现' })); const discoverPanel = document.getElementById('platform-tab-panel-category'); if (!discoverPanel) { throw new Error('缺少发现面板'); @@ -4285,10 +4289,12 @@ test('desktop discover shows child motion demo in edutainment channel', async () const user = userEvent.setup(); const onOpenChildMotionDemo = vi.fn(); - renderStatefulLoggedOutHomeView({ - onOpenChildMotionDemo, - }); - await user.click(screen.getByRole('button', { name: '发现' })); + renderStatefulLoggedOutHomeView( + { + onOpenChildMotionDemo, + }, + true, + ); await user.click(screen.getByRole('tab', { name: '寓教于乐' })); const warmupButton = screen.getByRole('button', { name: /热身关卡/u }); @@ -4316,7 +4322,6 @@ test('mobile discover hides edutainment channel and work when switch is disabled latestEntries: [edutainmentEntry], onSearchPublicCode, }); - await user.click(screen.getByRole('button', { name: '发现' })); const discoverPanel = document.getElementById('platform-tab-panel-category'); if (!discoverPanel) { throw new Error('缺少发现面板'); @@ -4353,7 +4358,6 @@ test('mobile discover keeps baby object match works in edutainment channel only' onOpenGalleryDetail, onSearchPublicCode, }); - await user.click(screen.getByRole('button', { name: '发现' })); const discoverPanel = document.getElementById('platform-tab-panel-category'); if (!discoverPanel) { throw new Error('缺少发现面板'); @@ -4388,7 +4392,6 @@ test('discover search keeps public code fallback when local works do not match', latestEntries: [puzzlePublicEntry], onSearchPublicCode, }); - await user.click(screen.getByRole('button', { name: '发现' })); const searchInput = screen.getByPlaceholderText('搜索作品号、名称、作者、描述'); @@ -4406,7 +4409,6 @@ test('public gallery cards hide work code until detail is opened', async () => { latestEntries: [puzzlePublicEntry], onOpenGalleryDetail, }); - await user.click(screen.getByRole('button', { name: '发现' })); expect(screen.queryByText('PZ-EPUBLIC1')).toBeNull(); expect( @@ -4436,26 +4438,34 @@ test('public gallery cards hide phone masked author and public user code', async }, true, ); - await user.click(screen.getByRole('button', { name: '发现' })); const card = screen.getByRole('button', { name: /喜气洋洋/u }); expect(card).toBeTruthy(); - expect(within(card).getByText('公开作者')).toBeTruthy(); + expect(await within(card).findByText('公开作者')).toBeTruthy(); expect(within(card).queryByText('158****3533 · SY-00000003')).toBeNull(); expect(within(card).queryByText('158****3533')).toBeNull(); expect(within(card).queryByText('SY-00000003')).toBeNull(); }); -test('logged out mobile shell defaults to discover tab', () => { - const { container } = renderStatefulLoggedOutHomeView({ - latestEntries: [puzzlePublicEntry], - }); +test('logged out mobile shell defaults to profile tab when active tab is hidden', async () => { + const { container } = renderStatefulLoggedOutHomeView( + { + latestEntries: [puzzlePublicEntry], + }, + false, + { + allowHiddenActiveTab: false, + }, + ); - const activePanel = container.querySelector('.platform-tab-panel--active'); - expect(activePanel?.id).toBe('platform-tab-panel-category'); + await waitFor(() => { + expect(container.querySelector('.platform-tab-panel--active')?.id).toBe( + 'platform-tab-panel-profile', + ); + }); expect( - screen.getByPlaceholderText('搜索作品号、名称、作者、描述'), - ).toBeTruthy(); + screen.queryByPlaceholderText('搜索作品号、名称、作者、描述'), + ).toBeNull(); expect(container.querySelector('.platform-mobile-topbar')).toBeTruthy(); expect( container.querySelector('.platform-mobile-entry-shell--recommend'), @@ -4463,18 +4473,15 @@ test('logged out mobile shell defaults to discover tab', () => { }); test('logged out recommend tab opens embedded runtime without login modal', async () => { - const user = userEvent.setup(); - const { container, openLoginModal } = renderStatefulLoggedOutHomeView({ - latestEntries: [puzzlePublicEntry], - activeRecommendEntryKey: 'puzzle:user-2:puzzle-profile-public-1', - }); - const bottomNav = container.querySelector('.platform-bottom-nav'); - if (!bottomNav) { - throw new Error('缺少底部导航'); - } - - await user.click( - within(bottomNav as HTMLElement).getByRole('button', { name: '推荐' }), + const { container, openLoginModal } = renderStatefulLoggedOutHomeView( + { + latestEntries: [puzzlePublicEntry], + activeRecommendEntryKey: 'puzzle:user-2:puzzle-profile-public-1', + }, + false, + { + initialActiveTab: 'home', + }, ); expect(openLoginModal).not.toHaveBeenCalled(); @@ -4489,20 +4496,17 @@ test('logged out recommend tab opens embedded runtime without login modal', asyn }); test('logged out recommend runtime keeps detail callback idle', async () => { - const user = userEvent.setup(); const onOpenGalleryDetail = vi.fn(); - const { openLoginModal } = renderStatefulLoggedOutHomeView({ - latestEntries: [puzzlePublicEntry], - activeRecommendEntryKey: 'puzzle:user-2:puzzle-profile-public-1', - onOpenGalleryDetail, - }); - const bottomNav = document.querySelector('.platform-bottom-nav'); - if (!bottomNav) { - throw new Error('缺少底部导航'); - } - - await user.click( - within(bottomNav as HTMLElement).getByRole('button', { name: '推荐' }), + const { openLoginModal } = renderStatefulLoggedOutHomeView( + { + latestEntries: [puzzlePublicEntry], + activeRecommendEntryKey: 'puzzle:user-2:puzzle-profile-public-1', + onOpenGalleryDetail, + }, + false, + { + initialActiveTab: 'home', + }, ); expect(openLoginModal).not.toHaveBeenCalled(); @@ -4596,9 +4600,8 @@ test('mobile recommend meta matches active wooden fish runtime entry', () => { expect(within(meta).getByText('莲台木鱼')).toBeTruthy(); }); -test('logged out desktop recommend rail enters runtime without login modal', async () => { +test('logged out desktop rail hides recommend entry', () => { mockDesktopLayout(); - const user = userEvent.setup(); const openLoginModal = vi.fn(); const { container } = renderLoggedOutHomeView( @@ -4616,10 +4619,11 @@ test('logged out desktop recommend rail enters runtime without login modal', asy throw new Error('缺少桌面侧边栏'); } - await user.click( - within(desktopRail as HTMLElement).getByRole('button', { name: '推荐' }), - ); - + expect( + within(desktopRail as HTMLElement).queryByRole('button', { + name: '推荐', + }), + ).toBeNull(); expect(openLoginModal).not.toHaveBeenCalled(); expect(screen.queryByTestId('recommend-runtime')).toBeNull(); expect(container.querySelector('.platform-desktop-shell')).toBeTruthy(); @@ -5379,8 +5383,7 @@ test('logged in recommend runtime preloads adjacent work previews and drag switc vi.useRealTimers(); }); -test('logged out active recommend bottom tab selects next work without login', async () => { - const user = userEvent.setup(); +test('logged out active recommend bottom nav hides next action', () => { const onSelectNextRecommendEntry = vi.fn(); const openLoginModal = vi.fn(); @@ -5390,9 +5393,8 @@ test('logged out active recommend bottom tab selects next work without login', a onSelectNextRecommendEntry, }); - await user.click(screen.getByRole('button', { name: '下一个' })); - - expect(onSelectNextRecommendEntry).toHaveBeenCalledTimes(1); + expect(screen.queryByRole('button', { name: '下一个' })).toBeNull(); + expect(onSelectNextRecommendEntry).not.toHaveBeenCalled(); expect(openLoginModal).not.toHaveBeenCalled(); }); @@ -5487,9 +5489,6 @@ test('mobile discover recommend feed only rotates the card closest to screen cen renderStatefulLoggedOutHomeView({ latestEntries: [firstEntry, secondEntry], }); - act(() => { - screen.getByRole('button', { name: '发现' }).click(); - }); const tabPanel = document.querySelector('.platform-tab-panel--active'); const firstCard = screen.getByRole('button', { name: /中心拼图一/u }); @@ -5662,7 +5661,6 @@ test('mobile today channel only shows newly published works from today', async ( latestEntries: [yesterdayEntry, updatedTodayEntry, todayEntry], }); - await user.click(screen.getByRole('button', { name: '发现' })); await user.click(screen.getByRole('tab', { name: '今日' })); const discoverPanel = document.getElementById('platform-tab-panel-category'); if (!discoverPanel) { @@ -5816,7 +5814,6 @@ test('mobile home moves category shelf into game category channel', async () => expect(screen.queryByRole('button', { name: 'PC游戏' })).toBeNull(); expect(screen.queryByRole('button', { name: '即点即玩' })).toBeNull(); - await user.click(screen.getByRole('button', { name: '发现' })); await user.click(screen.getByRole('tab', { name: '分类' })); expect(screen.getAllByText('分类').length).toBeGreaterThan(0); @@ -5842,7 +5839,6 @@ test('mobile game category list orders works by composite public metric', async latestEntries: [puzzlePublicEntry, hotRankEntry], }); - await user.click(screen.getByRole('button', { name: '发现' })); await user.click(screen.getByRole('tab', { name: '分类' })); await user.click(screen.getByRole('button', { name: '奇幻' })); @@ -5874,7 +5870,6 @@ test('mobile game category filter dialog filters by play type', async () => { latestEntries: [puzzlePublicEntry, match3dEntry], }); - await user.click(screen.getByRole('button', { name: '发现' })); await user.click(screen.getByRole('tab', { name: '分类' })); await user.click(screen.getByRole('button', { name: '奇幻' })); @@ -5909,7 +5904,6 @@ test('mobile game category keeps filter controls when current filter becomes emp latestEntries: [puzzlePublicEntry], }); - await user.click(screen.getByRole('button', { name: '发现' })); await user.click(screen.getByRole('tab', { name: '分类' })); await user.click(screen.getByRole('button', { name: '奇幻' })); await user.click(screen.getByRole('button', { name: /筛选/u })); @@ -5955,7 +5949,6 @@ test('bottom category tab becomes ranking and switches ranking metrics', async ( latestEntries: [remixRankEntry, hotRankEntry, newRankEntry], }); - await user.click(screen.getByRole('button', { name: '发现' })); await user.click(screen.getByRole('tab', { name: '排行' })); expect(await screen.findByRole('tab', { name: '热门榜' })).toBeTruthy(); @@ -5989,7 +5982,6 @@ test('ranking rows limit displayed work name and show two short tags on the thir latestEntries: [longTextRankEntry], }); - await user.click(screen.getByRole('button', { name: '发现' })); await user.click(screen.getByRole('tab', { name: '排行' })); const rankingPanel = document.getElementById('platform-tab-panel-category'); diff --git a/src/components/rpg-entry/RpgEntryHomeView.tsx b/src/components/rpg-entry/RpgEntryHomeView.tsx index 15cca86d1..dce9c1f00 100644 --- a/src/components/rpg-entry/RpgEntryHomeView.tsx +++ b/src/components/rpg-entry/RpgEntryHomeView.tsx @@ -2899,13 +2899,7 @@ export function RpgEntryHomeView({ hasManualCategoryTagSelectionRef.current = true; setSelectedCategoryTag(tag); }, []); - const visibleMobileTabs = useMemo( - () => - isAuthenticated - ? ['home', 'category', 'profile'] - : ['home', 'category', 'profile'], - [isAuthenticated], - ); + const visibleMobileTabs = useMemo(() => ['profile'], []); const visibleDesktopNavTabs = useMemo( () => (isAuthenticated @@ -2962,12 +2956,11 @@ export function RpgEntryHomeView({ return; } if (!visibleMobileTabs.includes(activeTab) && !isDesktopLayout) { - onTabChange(isAuthenticated ? 'home' : 'category'); + onTabChange('profile'); } }, [ activeTab, allowHiddenActiveTab, - isAuthenticated, isDesktopLayout, onTabChange, visibleMobileTabs, @@ -5115,7 +5108,7 @@ export function RpgEntryHomeView({
{visibleMobileTabs.map((tab) => (