/* @vitest-environment jsdom */ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; import { afterEach, describe, expect, test, vi } from 'vitest'; import App from './App'; import { AuthUiContext } from './components/auth/AuthUiContext'; import type { PlatformEntryFlowShellProps } from './components/platform-entry'; import { canUseNativeHostCapability, resetHostRuntimeCacheForTest, } from './services/host-bridge/hostBridge'; import { resetNativeAppHostBridgeForTest } from './services/host-bridge/nativeAppHostBridge'; const appTitleMock = vi.hoisted(() => ({ syncAppTitle: vi.fn(), })); vi.mock('./services/appTitle', async (importOriginal) => { const actual = await importOriginal(); return { ...actual, syncAppTitle: appTitleMock.syncAppTitle, }; }); vi.mock('./components/platform-entry/PlatformEntryFlowShell', () => ({ PlatformEntryFlowShell: ({ handleCustomWorldSelect, setSelectionStage, selectionStage, }: PlatformEntryFlowShellProps) => (
{selectionStage}
{canUseNativeHostCapability('share.open') ? 'enabled' : 'disabled'}
), })); vi.mock('./RpgRuntimeApp', () => ({ RpgRuntimeApp: ({ onExitRuntime }: { onExitRuntime: () => void }) => ( ), })); function renderApp() { return render( undefined), musicVolume: 0.6, openAccountModal: vi.fn(), openLoginModal: vi.fn(), openSettingsModal: vi.fn(), platformTheme: 'light', requireAuth: vi.fn(), setCurrentUser: vi.fn(), setMusicVolume: vi.fn(), setPlatformTheme: vi.fn(), settingsError: null, user: null, }} > , ); } afterEach(() => { appTitleMock.syncAppTitle.mockReset(); window.history.replaceState(null, '', '/'); delete window.__TAURI__; delete window.ReactNativeWebView; resetHostRuntimeCacheForTest(); resetNativeAppHostBridgeForTest(); vi.restoreAllMocks(); }); describe('App title sync', () => { test('主站阶段变化会同步浏览器与宿主标题', () => { renderApp(); expect(appTitleMock.syncAppTitle).toHaveBeenLastCalledWith('陶泥儿'); act(() => { fireEvent.click(screen.getByRole('button', { name: '打开拼图创作' })); }); expect(appTitleMock.syncAppTitle).toHaveBeenLastCalledWith( '拼图创作 - 陶泥儿', ); }); test('RPG runtime 进入和退出时同步窗口标题', async () => { renderApp(); await act(async () => { fireEvent.click(screen.getByRole('button', { name: '进入 RPG' })); }); expect(appTitleMock.syncAppTitle).toHaveBeenLastCalledWith( 'RPG 运行中 - 陶泥儿', ); await act(async () => { fireEvent.click(screen.getByRole('button', { name: '退出 RPG' })); }); expect(appTitleMock.syncAppTitle).toHaveBeenLastCalledWith('陶泥儿'); }); test('启动时回读宿主 runtime 后刷新壳能力 UI', async () => { window.history.replaceState( null, '', '/?clientRuntime=native_app&hostShell=tauri_desktop', ); window.__TAURI__ = { core: { invoke: vi.fn(async (_command, args) => { const request = (args as { request: { id: string } }).request; return { bridge: 'GenarrativeHostBridge', version: 1, id: request.id, ok: true, result: { shell: 'tauri_desktop', platform: 'linux', hostVersion: '0.1.0', bridgeVersion: 1, capabilities: ['host.getRuntime', 'share.open'], }, }; }), }, }; renderApp(); expect(screen.getByTestId('share-capability').textContent).toBe( 'disabled', ); await screen.findByText('enabled'); expect(screen.getByTestId('share-capability').textContent).toBe( 'enabled', ); }); test('原生壳直达二级页面时补齐 H5 返回锚点', async () => { window.history.replaceState( null, '', '/creation/puzzle?clientRuntime=native_app&hostShell=tauri_desktop&hostCapabilities=host.events,navigation.canGoBack', ); window.__TAURI__ = { core: { invoke: vi.fn(async () => { throw new Error('unsupported'); }), }, }; renderApp(); expect(screen.getByTestId('selection-stage').textContent).toBe( 'puzzle-agent-workspace', ); expect(window.location.pathname).toBe('/creation/puzzle'); expect(window.location.search).toBe( '?clientRuntime=native_app&hostShell=tauri_desktop&hostCapabilities=host.events%2Cnavigation.canGoBack', ); await act(async () => { window.history.back(); }); await waitFor(() => { expect(window.location.pathname).toBe('/'); }); expect(window.location.search).toBe( '?clientRuntime=native_app&hostShell=tauri_desktop&hostCapabilities=host.events%2Cnavigation.canGoBack', ); expect(screen.getByTestId('selection-stage').textContent).toBe('platform'); }); });