恢复移动端创作工具门禁

移动端底部导航仅保留我的入口
移动端创作、项目与画布直达统一展示桌面端提示
补充移动端入口与画布阻断回归测试
纠正旧模板退役时越权扩大的移动端产品口径
This commit is contained in:
2026-08-03 15:13:26 +08:00
parent d1a657b5d2
commit d3eeaf979d
8 changed files with 166 additions and 33 deletions
@@ -1,9 +1,11 @@
/* @vitest-environment jsdom */
import { fireEvent, render, screen, within } from '@testing-library/react';
import { useState } from 'react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { PlatformEntryFlowShellImpl } from './PlatformEntryActiveFlowShell';
import type { SelectionStage } from './platformEntryActiveTypes';
const authUiMock = vi.hoisted(() => ({
value: {
@@ -15,10 +17,18 @@ const authUiMock = vi.hoisted(() => ({
},
}));
const responsiveMock = vi.hoisted(() => ({
isDesktopLayout: true,
}));
vi.mock('../auth/AuthUiContext', () => ({
useAuthUi: () => authUiMock.value,
}));
vi.mock('./platformEntryResponsive', () => ({
usePlatformDesktopLayout: () => responsiveMock.isDesktopLayout,
}));
vi.mock('../creation-home/CreationLandingView', () => ({
CreationLandingView: ({
onOpenProject,
@@ -102,10 +112,26 @@ vi.mock('./usePlatformProfileCenterController', () => ({
}),
}));
function StatefulPlatformEntryFlowShell({
initialStage,
}: {
initialStage: SelectionStage;
}) {
const [selectionStage, setSelectionStage] = useState(initialStage);
return (
<PlatformEntryFlowShellImpl
selectionStage={selectionStage}
setSelectionStage={(nextStage) => setSelectionStage(nextStage)}
/>
);
}
describe('PlatformEntryActiveFlowShell', () => {
beforeEach(() => {
window.history.replaceState(null, '', '/creation');
authUiMock.value.openLoginModal.mockReset();
responsiveMock.isDesktopLayout = true;
});
it('keeps the active desktop rail and the shared account capsule', async () => {
@@ -174,11 +200,12 @@ describe('PlatformEntryActiveFlowShell', () => {
).toBe('page');
});
it('keeps creation, project, and profile reachable from the mobile dock', async () => {
it('keeps only profile reachable from the mobile dock', async () => {
responsiveMock.isDesktopLayout = false;
const setSelectionStage = vi.fn();
render(
<PlatformEntryFlowShellImpl
selectionStage="project"
selectionStage="platform"
setSelectionStage={setSelectionStage}
/>,
);
@@ -190,12 +217,7 @@ describe('PlatformEntryActiveFlowShell', () => {
within(navigation)
.getAllByRole('button')
.map((button) => button.getAttribute('aria-label')),
).toEqual(['创作', '项目', '我的']);
expect(
within(navigation)
.getByRole('button', { name: '项目' })
.getAttribute('aria-current'),
).toBe('page');
).toEqual(['我的']);
fireEvent.click(within(navigation).getByRole('button', { name: '我的' }));
expect(window.location.pathname).toBe('/profile');
@@ -204,6 +226,48 @@ describe('PlatformEntryActiveFlowShell', () => {
});
});
it.each(['creation-home', 'project', 'image-editor'] as const)(
'shows the desktop guide instead of mounting the %s page on mobile',
async (selectionStage) => {
responsiveMock.isDesktopLayout = false;
render(
<PlatformEntryFlowShellImpl
selectionStage={selectionStage}
setSelectionStage={vi.fn()}
/>,
);
expect(
await screen.findByRole('main', { name: '桌面端创作提示' }),
).toBeTruthy();
expect(
screen.queryByRole('main', { name: '陶泥儿创作主页' }),
).toBeNull();
expect(screen.queryByRole('main', { name: '项目' })).toBeNull();
expect(
screen.queryByRole('main', { name: '图片画布编辑器' }),
).toBeNull();
},
);
it('shows the desktop guide instead of the editor after opening a canvas tool from the mobile root', async () => {
responsiveMock.isDesktopLayout = false;
render(<StatefulPlatformEntryFlowShell initialStage="platform" />);
fireEvent.click(
await screen.findByRole('button', { name: '打开音乐工具' }),
);
expect(
await screen.findByRole('main', { name: '桌面端创作提示' }),
).toBeTruthy();
expect(
screen.queryByRole('main', { name: '图片画布编辑器' }),
).toBeNull();
});
it('switches between creation and projects and passes search to the active page', async () => {
const setSelectionStage = vi.fn();
const { rerender } = render(