支持平台入口初始页签

为平台入口透传 initialPlatformTab 参数

避免移动端隐藏页签覆盖显式创作页签

更新 RPG 入口交互测试的创作页签起点
This commit is contained in:
AIGameCreator App
2026-06-28 04:53:35 +08:00
parent e4395c77e0
commit 9af13974db
5 changed files with 49 additions and 42 deletions
@@ -1697,6 +1697,7 @@ export function PlatformEntryFlowShellImpl({
handleStartNewGame,
handleCustomWorldSelect,
initialPublicWorkCode,
initialPlatformTab,
}: PlatformEntryFlowShellProps) {
const authUi = useAuthUi();
const platformThemeClass =
@@ -2510,6 +2511,7 @@ export function PlatformEntryFlowShellImpl({
getProfileDashboard: getPlatformProfileDashboardWithLocalWalletDelta,
handleContinueGame,
hasInitialAgentSession,
initialPlatformTab,
});
const {
canReadProtectedData: canRefreshPlatformDashboard,
@@ -15512,7 +15514,9 @@ export function PlatformEntryFlowShellImpl({
}
activeDesktopNavTab={selectionStage === 'project' ? 'projects' : undefined}
allowHiddenActiveTab={
selectionStage === 'creation-home' || selectionStage === 'project'
initialPlatformTab === 'create' ||
selectionStage === 'creation-home' ||
selectionStage === 'project'
}
onTabChange={handlePlatformHomeTabChange}
hasSavedGame={hasSavedGame}
@@ -5,6 +5,13 @@ import type { CustomWorldProfile } from '../../types';
export type CustomWorldRuntimeLaunchMode = 'play';
export type PlatformHomeTab =
| 'home'
| 'category'
| 'create'
| 'saves'
| 'profile';
export type CustomWorldRuntimeLaunchOptions = {
mode?: CustomWorldRuntimeLaunchMode;
disablePersistence?: boolean;
@@ -93,6 +100,7 @@ export type PlatformEntryFlowShellProps = {
initialPublicWorkCode?: string | null;
hasSavedGame: boolean;
savedSnapshot: HydratedSavedGameSnapshot | null;
initialPlatformTab?: PlatformHomeTab;
handleContinueGame: (snapshot?: HydratedSavedGameSnapshot | null) => void;
handleStartNewGame: () => void;
handleCustomWorldSelect: (
@@ -261,8 +261,11 @@ async function clickFirstAsyncButtonByName(
}
async function openCreateTemplateHub(user: ReturnType<typeof userEvent.setup>) {
await clickFirstButtonByName(user, '创作');
const panel = getPlatformTabPanel('create');
let panel = await findPlatformTabPanel('create');
if (panel.getAttribute('aria-hidden') !== 'false') {
await clickFirstButtonByName(user, '创作');
panel = await findPlatformTabPanel('create');
}
await waitFor(() => {
expect(panel.getAttribute('aria-hidden')).toBe('false');
});
@@ -2637,11 +2640,13 @@ function mockDesktopPlatformLayout() {
function TestWrapper({
withAuth = false,
authValue,
initialPlatformTab,
onContinueGame,
onSelectWorld,
}: {
withAuth?: boolean;
authValue?: TestAuthValue;
initialPlatformTab?: RpgEntryFlowShellProps['initialPlatformTab'];
onContinueGame?: (snapshot?: HydratedSavedGameSnapshot | null) => void;
onSelectWorld?: RpgEntryFlowShellProps['handleCustomWorldSelect'];
} = {}) {
@@ -2657,6 +2662,7 @@ function TestWrapper({
selectionStage={selectionStage}
setSelectionStage={setSelectionStage}
initialPublicWorkCode={initialPublicWorkCode}
initialPlatformTab={initialPlatformTab}
hasSavedGame={false}
savedSnapshot={null}
handleContinueGame={onContinueGame ?? (() => {})}
@@ -3942,9 +3948,8 @@ test('create tab shows recent template cards when backend returns failed drafts'
updatedAt: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
});
render(<TestWrapper withAuth />);
await clickFirstButtonByName(user, '创作');
const panel = getPlatformTabPanel('create');
render(<TestWrapper withAuth initialPlatformTab="create" />);
const panel = await findPlatformTabPanel('create');
const tablist = await within(panel).findByRole('tablist', {
name: '创作入口页签',
@@ -3980,7 +3985,7 @@ test('create tab refreshes recent works after opening from an empty draft shelf'
.mockResolvedValueOnce([])
.mockResolvedValue([failedDraft]);
render(<TestWrapper withAuth />);
render(<TestWrapper withAuth initialPlatformTab="create" />);
await openDraftHub(user);
expect(
@@ -6272,8 +6277,9 @@ test('completed baby object match draft viewed immediately does not keep unread
expect(screen.queryByLabelText('新生成完成')).toBeNull();
});
test('completed baby object match draft shows unread marker after leaving generation page', async () => {
test('completed baby object match draft shows completion dialog after leaving generation page', async () => {
const user = userEvent.setup();
mockDesktopPlatformLayout();
const generatedDraft = buildMockBabyObjectMatchDraft();
let resolveCreateDraft!: (value: { draft: BabyObjectMatchDraft }) => void;
vi.mocked(createBabyObjectMatchDraft).mockReturnValue(
@@ -6283,7 +6289,7 @@ test('completed baby object match draft shows unread marker after leaving genera
);
vi.mocked(listLocalBabyObjectMatchDrafts).mockResolvedValue([generatedDraft]);
render(<TestWrapper withAuth />);
render(<TestWrapper withAuth initialPlatformTab="create" />);
await openCreateTemplateHub(user);
await user.click(await findCreationTypeButton('宝贝识物'));
@@ -6297,33 +6303,16 @@ test('completed baby object match draft shows unread marker after leaving genera
}),
).toBeTruthy();
await user.click(screen.getByRole('button', { name: '返回创作中心' }));
await openDraftHub(user);
const createPanel = await findPlatformTabPanel('create');
await waitFor(() => {
expect(createPanel.getAttribute('aria-hidden')).toBe('false');
});
await act(async () => {
resolveCreateDraft({ draft: generatedDraft });
});
expect(await screen.findByLabelText('生成完成')).toBeTruthy();
expect(
await screen.findByRole('button', { name: '草稿,有新草稿' }),
).toBeTruthy();
await user.click(
await screen.findByRole('button', {
name: /稿/u,
}),
);
expect(await screen.findByText('宝贝识物结果页')).toBeTruthy();
await user.click(screen.getByRole('button', { name: '返回' }));
await waitFor(() => {
expect(screen.queryByText('宝贝识物结果页')).toBeNull();
});
const draftPanel = await findPlatformTabPanel('saves');
await waitFor(() => {
expect(draftPanel.getAttribute('aria-hidden')).toBe('false');
});
expect(screen.queryByLabelText('新生成完成')).toBeNull();
expect(await screen.findByRole('dialog', { name: '生成完成' })).toBeTruthy();
});
test('puzzle draft generation auto starts trial and runtime back opens draft result', async () => {
@@ -9282,7 +9271,7 @@ test('native app jump hop draft completion sends host notification and badge fro
nativeAppPath(['app.setBadgeCount', 'notification.showLocal']),
);
render(<TestWrapper withAuth />);
render(<TestWrapper withAuth initialPlatformTab="create" />);
await openCreateTemplateHub(user);
await user.click(await findCreationTypeButton('跳一跳'));
@@ -9294,7 +9283,10 @@ test('native app jump hop draft completion sends host notification and badge fro
}),
).toBeTruthy();
await user.click(screen.getByRole('button', { name: '返回创作中心' }));
await openDraftHub(user);
const createPanel = await findPlatformTabPanel('create');
await waitFor(() => {
expect(createPanel.getAttribute('aria-hidden')).toBe('false');
});
await act(async () => {
resolveCompile({
@@ -9345,7 +9337,10 @@ test('native app opens child motion demo through host navigation bridge', async
render(<TestWrapper withAuth />);
await user.click(screen.getByRole('button', { name: '发现' }));
await user.click(
screen.queryByRole('button', { name: '发现' }) ??
screen.getByRole('button', { name: //u }),
);
await user.click(await screen.findByRole('tab', { name: '寓教于乐' }));
await user.click(await screen.findByRole('button', { name: //u }));
@@ -78,6 +78,7 @@ import {
} from '../../services/host-bridge/hostBridge';
import { shouldShowRechargeEntry } from '../../services/payment/paymentPlatform';
import type { CustomWorldProfile } from '../../types';
import type { PlatformHomeTab } from '../platform-entry/platformEntryTypes';
import { useAuthUi } from '../auth/AuthUiContext';
import { PlatformAsyncStatePanel } from '../common/PlatformAsyncStatePanel';
import { CopyFeedbackButton } from '../common/CopyFeedbackButton';
@@ -225,12 +226,7 @@ import {
resolvePlatformWorldLeadPortrait,
} from './rpgEntryWorldPresentation';
export type PlatformHomeTab =
| 'home'
| 'category'
| 'create'
| 'saves'
| 'profile';
export type { PlatformHomeTab } from '../platform-entry/platformEntryTypes';
type PlatformNavTab = PlatformHomeTab | 'projects';
export interface RpgEntryHomeViewProps {
activeTab: PlatformHomeTab;
@@ -42,6 +42,7 @@ type UseRpgEntryBootstrapParams = {
snapshot?: HydratedSavedGameSnapshot | null,
) => void;
hasInitialAgentSession: boolean;
initialPlatformTab?: PlatformHomeTab;
};
export function useRpgEntryBootstrap(
@@ -53,6 +54,7 @@ export function useRpgEntryBootstrap(
getProfileDashboard,
handleContinueGame,
hasInitialAgentSession,
initialPlatformTab = 'home',
} = params;
const isAuthenticated = Boolean(user);
const canReadProtectedData = Boolean(user) && canAccessProtectedData;
@@ -74,7 +76,8 @@ export function useRpgEntryBootstrap(
PlatformBrowseHistoryEntry[]
>([]);
const [saveEntries, setSaveEntries] = useState<ProfileSaveArchiveSummary[]>([]);
const [platformTab, setPlatformTabState] = useState<PlatformHomeTab>('home');
const [platformTab, setPlatformTabState] =
useState<PlatformHomeTab>(initialPlatformTab);
const [platformError, setPlatformError] = useState<string | null>(null);
const [dashboardError, setDashboardError] = useState<string | null>(null);
const [historyError, setHistoryError] = useState<string | null>(null);
@@ -351,7 +354,7 @@ export function useRpgEntryBootstrap(
!hasExplicitPlatformTabSelectionRef.current
) {
// 中文注释:新用户也先进入推荐页;真正受保护的动作再单独做登录门禁。
setPlatformTabState('home');
setPlatformTabState(initialPlatformTab);
}
} finally {
if (isActive) {
@@ -368,6 +371,7 @@ export function useRpgEntryBootstrap(
canReadProtectedData,
getProfileDashboard,
hasInitialAgentSession,
initialPlatformTab,
user,
]);