测试:全仓测试统一 Tauri 运行时替身安装点
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m58s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 6m34s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m29s
Project CI / Backend tests (pull_request) Failing after 4m38s
Project CI / Frontend tests (pull_request) Successful in 3m33s
Project CI / Repository checks (pull_request) Failing after 4m4s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m13s
Project CI / Native shell tests (pull_request) Successful in 6m35s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m58s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 6m34s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m29s
Project CI / Backend tests (pull_request) Failing after 4m38s
Project CI / Frontend tests (pull_request) Successful in 3m33s
Project CI / Repository checks (pull_request) Failing after 4m4s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m13s
Project CI / Native shell tests (pull_request) Successful in 6m35s
- 78 处内联 window.__TAURI__ 赋值改为 installTauriRuntime,覆盖 appSurface 之外的 37 个测试文件 - 31 处 delete window.__TAURI__ / window.__TAURI__ = undefined 复位改为 resetTauriRuntime - 删除 recentProjectsHook、projectCreationDirectory、projectResourceLiveIntegration、useProjectResourceCardPreviews、resourceVersionReplacementModel、unityProjectOpen 里的本地 asTauriInvoke / asTauriListen 适配器与相关类型别名 - designProjectRestore 的 setup 参数由 ReturnType<typeof vi.fn> 收窄为具体 invoke 签名 - 迁移后仅 tests/tauriRuntimeFake.ts 直接读写 window.__TAURI__
This commit is contained in:
@@ -14,9 +14,9 @@ const platformSession = vi.hoisted(() => ({
|
||||
}));
|
||||
|
||||
// 与仓库其它 App 内调用方同口径:通过 `window.__TAURI__.core.invoke` 解析原生桥。
|
||||
window.__TAURI__ = {
|
||||
installTauriRuntime({
|
||||
core: { invoke: (...args: unknown[]) => invoke(...args) },
|
||||
} as never;
|
||||
});
|
||||
vi.mock('../src/services/platformSession', () => ({
|
||||
currentPlatformSessionGeneration: () => platformSession.generation,
|
||||
requestPlatformSessionRefresh: (...args: unknown[]) =>
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
getClientProfileWalletLedger,
|
||||
redeemClientProfileRewardCode,
|
||||
} from '../src/services/accountHost';
|
||||
import { installTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
beforeEach(() => {
|
||||
invoke.mockReset();
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
it,
|
||||
React,
|
||||
render,
|
||||
resetTauriRuntime,
|
||||
screen,
|
||||
testAuthUser,
|
||||
vi,
|
||||
@@ -92,7 +93,7 @@ function captureWindowRejections() {
|
||||
export function registerAuthTests() {
|
||||
afterEach(() => {
|
||||
resetPlatformSessionForTests();
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
});
|
||||
|
||||
it('throws a startup timeout through to unhandledrejection and leaves the loading state', async () => {
|
||||
|
||||
@@ -18,6 +18,7 @@ import { useLauncherHomeDraftStore } from '../../src/view/home/useHomeDraftStore
|
||||
import {
|
||||
createTauriEventBridge,
|
||||
installTauriRuntime,
|
||||
resetTauriRuntime,
|
||||
} from '../tauriRuntimeFake';
|
||||
|
||||
const nativeClipboardMock = vi.hoisted(() => ({
|
||||
@@ -945,7 +946,7 @@ function createProjectChatRuntimeHarness({
|
||||
* 定义已收进 `tests/tauriRuntimeFake.ts`(全仓唯一安装点),这里只转出,供 appSurface 各
|
||||
* suite 沿用既有的 `./harness` 导入路径。
|
||||
*/
|
||||
export { createTauriEventBridge, installTauriRuntime };
|
||||
export { createTauriEventBridge, installTauriRuntime, resetTauriRuntime };
|
||||
|
||||
export function installResizeObserverStub() {
|
||||
let observerCount = 0;
|
||||
@@ -1014,7 +1015,7 @@ afterEach(() => {
|
||||
window.history.pushState({}, '', '/');
|
||||
window.localStorage.clear();
|
||||
window.sessionStorage.clear();
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
vi.restoreAllMocks();
|
||||
|
||||
if (originalCreateObjectUrl) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
it,
|
||||
mockRoleAgentReply,
|
||||
renderAppAt,
|
||||
resetTauriRuntime,
|
||||
roleAgentMockReply,
|
||||
screen,
|
||||
vi,
|
||||
@@ -691,7 +692,7 @@ export function registerProjectConversationTests() {
|
||||
fireEvent.click(screen.getByRole('button', { name: /拆解创作方向/ }));
|
||||
const input = await screen.findByLabelText('Agent 对话内容');
|
||||
fireEvent.change(input, { target: { value: '确认运行环境提示' } });
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
fireEvent.submit(input.closest('form') as HTMLFormElement);
|
||||
|
||||
expect(await screen.findByText('需要在 Tauri App 内运行')).not.toBeNull();
|
||||
|
||||
@@ -28,6 +28,7 @@ import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
import { AuthenticatedClient } from '../src/app/AuthenticatedClient';
|
||||
import { resetPlatformSessionForTests } from '../src/services/platformSession';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
import { installUnhandledRejectionBridge } from './unhandledRejectionBridge';
|
||||
|
||||
type AuthInvoke = (
|
||||
@@ -42,7 +43,7 @@ function reportCalls() {
|
||||
}
|
||||
|
||||
function renderLogin(invokeAuth: AuthInvoke) {
|
||||
window.__TAURI__ = { core: { invoke: invokeAuth } } as never;
|
||||
installTauriRuntime({ core: { invoke: invokeAuth } });
|
||||
render(
|
||||
// React 19 的 createElement 的 children 形参只接受 ReactNode,渲染函数子节点改编进 props。
|
||||
createElement(AuthenticatedClient, {
|
||||
@@ -68,7 +69,7 @@ describe('认证失败的上报判据', () => {
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
resetPlatformSessionForTests();
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
vi.mocked(invoke).mockClear();
|
||||
});
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
useDirectProjectChatController,
|
||||
} from '../src/view/project-development/chat/controller/useDirectProjectChatController';
|
||||
import type { DirectCodexTurnAttachment } from '../src/view/project-development/chat/conversation/directCodexTurnAttachments';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
// jsdom 的 Blob/File 没实现 `arrayBuffer`,而附件导入链路要按字节读文件。
|
||||
if (typeof Blob.prototype.arrayBuffer !== 'function') {
|
||||
@@ -25,7 +26,7 @@ function files(count: number, prefix: string) {
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
vi.restoreAllMocks();
|
||||
window.__TAURI__ = undefined;
|
||||
resetTauriRuntime();
|
||||
});
|
||||
|
||||
describe('聊天输入盒的附件上限', () => {
|
||||
@@ -38,7 +39,7 @@ describe('聊天输入盒的附件上限', () => {
|
||||
const fileName = (args as { fileName?: string }).fileName ?? 'file';
|
||||
return { localPath: `assets/upload-${(uploadSeq += 1)}-${fileName}` };
|
||||
});
|
||||
window.__TAURI__ = { core: { invoke: invoke as never } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useDirectProjectChatController({
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
beginProjectOpenAnalytics,
|
||||
beginUiSaveAnalytics,
|
||||
} from '../src/services/clientAnalytics';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
const context = {
|
||||
route: { user_id: 'user-a', destination_origin: 'https://a.example' },
|
||||
@@ -27,7 +28,7 @@ function deferred<T>() {
|
||||
}
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
@@ -54,7 +55,7 @@ function mount(
|
||||
return null;
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = { core: { invoke } } as unknown as typeof window.__TAURI__;
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
const hook = renderHook(
|
||||
() =>
|
||||
useHomeProjectCreation({
|
||||
|
||||
@@ -24,6 +24,7 @@ import type { RuntimeSessionInstallFailed } from '../src/services/generated/Runt
|
||||
import type { SendCodeRejected } from '../src/services/generated/SendCodeRejected';
|
||||
import type { ServerAddressRejected } from '../src/services/generated/ServerAddressRejected';
|
||||
import type { UnexpectedRejection } from '../src/services/generated/UnexpectedRejection';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
function expectNever(value: never): void {
|
||||
void value;
|
||||
@@ -127,7 +128,7 @@ function variantMessage(error: ClientAuthError): string {
|
||||
}
|
||||
|
||||
function installInvoke(handler: () => Promise<unknown>) {
|
||||
window.__TAURI__ = { core: { invoke: vi.fn(handler) } } as never;
|
||||
installTauriRuntime({ core: { invoke: vi.fn(handler) } });
|
||||
}
|
||||
|
||||
describe('认证命令失败的 JS 侧载体', () => {
|
||||
@@ -150,7 +151,7 @@ describe('认证命令失败的 JS 侧载体', () => {
|
||||
});
|
||||
|
||||
it('认证桥未安装时保持原样抛出,不包装成命令失败', async () => {
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
|
||||
await expect(
|
||||
loginClientWithPassword(
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
refreshClientAuthSession,
|
||||
sendClientPhoneLoginCode,
|
||||
} from '../src/services/clientAuth';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
const testUser = {
|
||||
id: 'user-1',
|
||||
@@ -35,9 +36,9 @@ const testUser = {
|
||||
|
||||
beforeEach(() => {
|
||||
invoke.mockReset();
|
||||
window.__TAURI__ = {
|
||||
installTauriRuntime({
|
||||
core: { invoke: (...args: unknown[]) => invoke(...args) },
|
||||
} as never;
|
||||
});
|
||||
});
|
||||
|
||||
test('手机号归一化只保留可提交的纯号码', () => {
|
||||
@@ -144,7 +145,7 @@ test('续期结果区分成功、失效与身份变化', async () => {
|
||||
});
|
||||
|
||||
test('没有原生宿主时登录能力明确失败关闭', async () => {
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
await expect(readClientAuthState()).rejects.toThrow(
|
||||
'需要在 Tauri App 内登录',
|
||||
);
|
||||
|
||||
@@ -4,9 +4,10 @@ import { afterEach, expect, test, vi } from 'vitest';
|
||||
|
||||
import { createGameCreationAppManifest } from '../../../packages/shared/src/contracts/gameCreationApp';
|
||||
import { useHomeProjectCreation } from '../src/features/app-shell/useHomeProjectCreation';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
afterEach(() => {
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
});
|
||||
|
||||
test('打开 Cocos 目录走导入入口,不创建 Web 脚手架或发送初始消息', async () => {
|
||||
@@ -39,7 +40,7 @@ test('打开 Cocos 目录走导入入口,不创建 Web 脚手架或发送初
|
||||
throw new Error(`意外调用:${command}`);
|
||||
});
|
||||
// TauriInvoke 是泛型函数签名,vi.fn 的具体返回类型无法直接赋给它,这里只在装配处桥接。
|
||||
window.__TAURI__ = { core: { invoke } } as unknown as typeof window.__TAURI__;
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
const setLauncherView = vi.fn();
|
||||
const { result } = renderHook(() =>
|
||||
useHomeProjectCreation({
|
||||
|
||||
@@ -18,6 +18,7 @@ import type {
|
||||
} from '../src/app/types';
|
||||
import { CustomLlmSettings } from '../src/features/runtime-config/CustomLlmSettings';
|
||||
import { RuntimeConfigDialog } from '../src/features/runtime-config/RuntimeConfigDialog';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
const invoke = vi.fn();
|
||||
const llm = {
|
||||
@@ -34,11 +35,11 @@ function Harness() {
|
||||
|
||||
beforeEach(() => {
|
||||
invoke.mockReset();
|
||||
window.__TAURI__ = { core: { invoke } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
});
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
});
|
||||
|
||||
test('reads endpoint models, filters candidates, and previews only checked models', async () => {
|
||||
|
||||
@@ -4,17 +4,20 @@ import { afterEach, expect, it, vi } from 'vitest';
|
||||
|
||||
import { createGameCreationAppManifest } from '../../../packages/shared/src/contracts/gameCreationApp';
|
||||
import { useHomeProjectCreation } from '../src/features/app-shell/useHomeProjectCreation';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
});
|
||||
|
||||
const projectPath = 'C:/test/design-project';
|
||||
const manifest = createGameCreationAppManifest('test-project', '策划项目');
|
||||
|
||||
function setup(invoke: ReturnType<typeof vi.fn>) {
|
||||
window.__TAURI__ = { core: { invoke } } as unknown as typeof window.__TAURI__;
|
||||
function setup(
|
||||
invoke: (command: string, args?: Record<string, unknown>) => Promise<unknown>,
|
||||
) {
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
return renderHook(() =>
|
||||
useHomeProjectCreation({
|
||||
setStatus: vi.fn(),
|
||||
|
||||
@@ -12,6 +12,7 @@ import React from 'react';
|
||||
import { afterEach, expect, it, vi } from 'vitest';
|
||||
|
||||
import { DesignWorkspacePanel } from '../src/features/project-workspace/DesignWorkspacePanel';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
vi.mock('../src/components/ChatMarkdownMessage', () => ({
|
||||
ChatMarkdownMessage: () => null,
|
||||
@@ -20,7 +21,7 @@ vi.mock('../src/components/ChatMarkdownMessage', () => ({
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
vi.unstubAllEnvs();
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
});
|
||||
|
||||
it('shows imported references after a workspace event without reloading the design session', async () => {
|
||||
@@ -41,7 +42,7 @@ it('shows imported references after a workspace event without reloading the desi
|
||||
if (command === 'read_design_workspace_file') return '# 导入的需求';
|
||||
throw new Error(`Unexpected command: ${command}`);
|
||||
});
|
||||
window.__TAURI__ = {
|
||||
installTauriRuntime({
|
||||
core: { invoke },
|
||||
event: {
|
||||
listen: vi.fn(async (_name, callback) => {
|
||||
@@ -49,7 +50,7 @@ it('shows imported references after a workspace event without reloading the desi
|
||||
return () => undefined;
|
||||
}),
|
||||
},
|
||||
} as unknown as typeof window.__TAURI__;
|
||||
});
|
||||
render(<DesignWorkspacePanel projectPath="imported-project" />);
|
||||
await waitFor(() => expect(onUpdate).toBeDefined());
|
||||
await waitFor(() =>
|
||||
@@ -95,7 +96,7 @@ it('prepares debug fixtures from the header and refreshes the phase and files wi
|
||||
}
|
||||
throw new Error(`Unexpected command: ${command}`);
|
||||
});
|
||||
window.__TAURI__ = { core: { invoke } } as unknown as typeof window.__TAURI__;
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
render(<DesignWorkspacePanel projectPath="test-project" />);
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
|
||||
@@ -4,6 +4,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { useDirectThreadChatSubscription } from '../src/view/project-development/chat/controller/useDirectThreadChatSubscription';
|
||||
import { createTauriEventFake, type TauriEventFake } from './tauriEventFake';
|
||||
import { resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
const BOOTSTRAP = {
|
||||
subscriptionId: 'direct-subscription-1',
|
||||
@@ -17,7 +18,7 @@ afterEach(() => {
|
||||
cleanup();
|
||||
eventFake?.restore();
|
||||
eventFake = null;
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
delete (window as Window & { __TAURI_INTERNALS__?: unknown })
|
||||
.__TAURI_INTERNALS__;
|
||||
});
|
||||
|
||||
@@ -85,6 +85,7 @@ import {
|
||||
subscribeClientErrorEvents,
|
||||
} from '../src/services/errorReporting';
|
||||
import type { ClientAuthError } from '../src/services/generated/ClientAuthError';
|
||||
import { resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
describe('客户端错误报告池', () => {
|
||||
afterEach(() => {
|
||||
@@ -272,7 +273,7 @@ describe('客户端错误报告池', () => {
|
||||
});
|
||||
|
||||
it('浏览器预览中订阅错误事件不会产生未处理拒绝', async () => {
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
|
||||
const unsubscribe = subscribeClientErrorEvents(vi.fn());
|
||||
unsubscribe();
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
parseStyleSheet,
|
||||
resolveDeclarations,
|
||||
} from './styleCascade';
|
||||
import { installTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
const readGamePublishAvailabilityMock = vi.hoisted(() =>
|
||||
vi.fn(async () => true),
|
||||
@@ -107,10 +108,10 @@ function installTauri(
|
||||
return chatHarness.invoke(command, args);
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = {
|
||||
core: { invoke: invoke as never },
|
||||
event: { listen: chatHarness.listen as never },
|
||||
};
|
||||
installTauriRuntime({
|
||||
core: { invoke },
|
||||
event: { listen: chatHarness.listen },
|
||||
});
|
||||
return { invoke };
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,11 @@ import {
|
||||
HOME_WEB_PREFLIGHT_IPC_FAILURE,
|
||||
} from '../src/features/app-shell/homeWebPreflight';
|
||||
import { useHomeProjectCreation } from '../src/features/app-shell/useHomeProjectCreation';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
});
|
||||
|
||||
function mount(preflight: () => Promise<unknown>) {
|
||||
@@ -31,7 +32,7 @@ function mount(preflight: () => Promise<unknown>) {
|
||||
return { activeRuntime: 'design' };
|
||||
return null;
|
||||
});
|
||||
window.__TAURI__ = { core: { invoke } } as unknown as typeof window.__TAURI__;
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
const hook = renderHook(() =>
|
||||
useHomeProjectCreation({
|
||||
setStatus: vi.fn(),
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
pickProjectFromLauncher,
|
||||
testAuthUser,
|
||||
} from './appSurface/harness';
|
||||
import { installTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
const PROJECT_PATH = '/tmp/run-notice-shell-project';
|
||||
|
||||
@@ -115,10 +116,10 @@ function renderWorkbench() {
|
||||
return runtimeHarness.invoke(command, args);
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = {
|
||||
core: { invoke: invoke as never },
|
||||
event: { listen: runtimeHarness.listen as never },
|
||||
};
|
||||
installTauriRuntime({
|
||||
core: { invoke },
|
||||
event: { listen: runtimeHarness.listen },
|
||||
});
|
||||
render(
|
||||
<WorkspaceLauncherShell
|
||||
currentUser={testAuthUser}
|
||||
@@ -179,10 +180,10 @@ describe('浮层提示的外壳接线', () => {
|
||||
}
|
||||
return runtimeHarness.invoke(command);
|
||||
});
|
||||
window.__TAURI__ = {
|
||||
core: { invoke: invoke as never },
|
||||
event: { listen: runtimeHarness.listen as never },
|
||||
};
|
||||
installTauriRuntime({
|
||||
core: { invoke },
|
||||
event: { listen: runtimeHarness.listen },
|
||||
});
|
||||
render(
|
||||
<WorkspaceLauncherShell
|
||||
currentUser={testAuthUser}
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
screen,
|
||||
waitFor,
|
||||
} from './appSurface/harness';
|
||||
import { installTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
const PROJECT_PATH = '/tmp/preview-activation-project';
|
||||
const PROJECT_ID = 'preview-activation-project';
|
||||
@@ -75,10 +76,10 @@ function installTauri(
|
||||
return chatHarness.invoke(command, args);
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = {
|
||||
core: { invoke: invoke as never },
|
||||
event: { listen: chatHarness.listen as never },
|
||||
};
|
||||
installTauriRuntime({
|
||||
core: { invoke },
|
||||
event: { listen: chatHarness.listen },
|
||||
});
|
||||
return { invoke, invokeCounts };
|
||||
}
|
||||
|
||||
|
||||
@@ -9,36 +9,12 @@ import {
|
||||
resetWorkspacePreferencesForTests,
|
||||
setProjectCreationDirectory,
|
||||
} from '../src/features/app-shell/workspacePreferences';
|
||||
|
||||
type TauriInvoke = NonNullable<
|
||||
NonNullable<NonNullable<Window['__TAURI__']>['core']>['invoke']
|
||||
>;
|
||||
|
||||
type TauriListen = NonNullable<
|
||||
NonNullable<NonNullable<Window['__TAURI__']>['event']>['listen']
|
||||
>;
|
||||
|
||||
function asTauriInvoke(
|
||||
invoke: (command: string, args?: Record<string, unknown>) => Promise<unknown>,
|
||||
): TauriInvoke {
|
||||
// 泛型 invoke 与具体的非泛型 mock 结构上不可兼容,只能用 as unknown as 收敛。
|
||||
return invoke as unknown as TauriInvoke;
|
||||
}
|
||||
|
||||
function asTauriListen(
|
||||
listen: (
|
||||
event: string,
|
||||
handler: (event: { payload: unknown }) => void,
|
||||
) => Promise<unknown>,
|
||||
): TauriListen {
|
||||
// 泛型 listen 与携带具体负载的 mock 结构上不可兼容,只能用 as unknown as 收敛。
|
||||
return listen as unknown as TauriListen;
|
||||
}
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
describe('项目创建目录偏好', () => {
|
||||
beforeEach(() => {
|
||||
resetWorkspacePreferencesForTests();
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
});
|
||||
|
||||
it('去掉首尾空白与多余分隔符,并保留盘根', () => {
|
||||
@@ -106,19 +82,17 @@ describe('项目创建目录偏好', () => {
|
||||
}
|
||||
throw new Error('unexpected invoke ' + command);
|
||||
});
|
||||
window.__TAURI__ = {
|
||||
core: { invoke: asTauriInvoke(invoke) },
|
||||
installTauriRuntime({
|
||||
core: { invoke },
|
||||
event: {
|
||||
listen: asTauriListen(
|
||||
vi.fn(async (_event, handler) => {
|
||||
eventHandler = handler;
|
||||
return () => {
|
||||
eventHandler = null;
|
||||
};
|
||||
}),
|
||||
),
|
||||
listen: vi.fn(async (_event, handler) => {
|
||||
eventHandler = handler;
|
||||
return () => {
|
||||
eventHandler = null;
|
||||
};
|
||||
}),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useProjectCreationDirectory());
|
||||
await waitFor(() => {
|
||||
|
||||
@@ -7,7 +7,6 @@ import type {
|
||||
GameCreationAppAssetManifestEntry,
|
||||
GameCreationAppManifest,
|
||||
} from '../../../packages/shared/src/contracts/gameCreationApp';
|
||||
import type { TauriInvoke } from '../src/app/types';
|
||||
|
||||
const canvasFixture = vi.hoisted(() => ({
|
||||
manifest: null as GameCreationAppManifest | null,
|
||||
@@ -34,6 +33,7 @@ import {
|
||||
waitFor,
|
||||
within,
|
||||
} from './appSurface/harness';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
const projectPath = '/tmp/live-canvas-integration';
|
||||
|
||||
@@ -47,16 +47,6 @@ function legacyAssetKind(kind: string): GameCreationAppAssetKind {
|
||||
return kind as unknown as GameCreationAppAssetKind;
|
||||
}
|
||||
|
||||
/**
|
||||
* 泛型 `invoke` 与具体的非泛型 mock 结构上不可兼容,只能用显式转换收敛类型;
|
||||
* 运行时原样返回同一个 mock,调用方仍持有原引用(`mock.calls` 等断言不受影响)。
|
||||
*/
|
||||
function asTauriInvoke(
|
||||
invoke: (command: string, args?: Record<string, unknown>) => Promise<unknown>,
|
||||
): TauriInvoke {
|
||||
return invoke as unknown as TauriInvoke;
|
||||
}
|
||||
|
||||
/**
|
||||
* 切栏目走「资源总览」的栏目缩略卡片(左侧大纲导航已删除)。
|
||||
* 与两个 appSurface suite 里的同名助手同口径:切完必须落到目标栏目的子画布。
|
||||
@@ -543,7 +533,7 @@ function SwitchableDerivedWorkbench({
|
||||
|
||||
describe('project resource live canvas integration', () => {
|
||||
afterEach(() => {
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
canvasFixture.manifest = null;
|
||||
canvasFixture.revision = 0;
|
||||
});
|
||||
@@ -837,10 +827,10 @@ describe('project resource live canvas integration', () => {
|
||||
throw new Error(`unexpected invoke ${command}`);
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = {
|
||||
core: { invoke: asTauriInvoke(invoke) },
|
||||
installTauriRuntime({
|
||||
core: { invoke },
|
||||
event: { listen: async () => () => undefined },
|
||||
};
|
||||
});
|
||||
return {
|
||||
invoke,
|
||||
deriveCalls,
|
||||
|
||||
@@ -5,16 +5,17 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { useProjectSnapshotWorkspace } from '../src/features/app-shell/useProjectSnapshotWorkspace';
|
||||
import { createProjectSnapshotWorkspaceRegistration } from '../src/services/projectSnapshotWorkspace';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
});
|
||||
|
||||
describe('项目快照窗口登记', () => {
|
||||
it('在无 projectPath URL 的单窗口登记、切换、离开,StrictMode 不误关项目', async () => {
|
||||
const invoke = vi.fn(async () => undefined);
|
||||
window.__TAURI__ = { core: { invoke: invoke as never } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
function Workspace({ path }: { path: string | null }) {
|
||||
useProjectSnapshotWorkspace(path);
|
||||
return null;
|
||||
|
||||
@@ -3,31 +3,7 @@ import { act, renderHook, waitFor } from '@testing-library/react';
|
||||
import { afterEach, expect, test, vi } from 'vitest';
|
||||
|
||||
import { useRecentProjects } from '../src/features/app-shell/useRecentProjects';
|
||||
|
||||
type TauriInvoke = NonNullable<
|
||||
NonNullable<NonNullable<Window['__TAURI__']>['core']>['invoke']
|
||||
>;
|
||||
|
||||
type TauriListen = NonNullable<
|
||||
NonNullable<NonNullable<Window['__TAURI__']>['event']>['listen']
|
||||
>;
|
||||
|
||||
function asTauriInvoke(
|
||||
invoke: (command: string, args?: Record<string, unknown>) => Promise<unknown>,
|
||||
): TauriInvoke {
|
||||
// 泛型 invoke 与具体的非泛型 mock 结构上不可兼容,只能用 as unknown as 收敛。
|
||||
return invoke as unknown as TauriInvoke;
|
||||
}
|
||||
|
||||
function asTauriListen(
|
||||
listen: (
|
||||
event: string,
|
||||
handler: (event: { payload: unknown }) => void,
|
||||
) => Promise<unknown>,
|
||||
): TauriListen {
|
||||
// 泛型 listen 与携带具体负载的 mock 结构上不可兼容,只能用 as unknown as 收敛。
|
||||
return listen as unknown as TauriListen;
|
||||
}
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
const READY_PROJECT = {
|
||||
projectPath: '/tmp/ready-project',
|
||||
@@ -46,7 +22,7 @@ const READY_PROJECT = {
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
delete window.__TAURI__;
|
||||
resetTauriRuntime();
|
||||
window.localStorage.clear();
|
||||
});
|
||||
|
||||
@@ -72,7 +48,7 @@ test('刷新坏项目时保留其它项目已确认的正常状态', async () =>
|
||||
return READY_PROJECT;
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = { core: { invoke: asTauriInvoke(invoke) } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
window.localStorage.setItem(
|
||||
'genarrative-ai-game-creator.recent-workspaces.v1',
|
||||
JSON.stringify(['/tmp/ready-project']),
|
||||
@@ -131,7 +107,7 @@ test('单次目录检查失败会就地重试,不会把整行钉成「检查
|
||||
return READY_PROJECT;
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = { core: { invoke: asTauriInvoke(invoke) } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
window.localStorage.setItem(
|
||||
'genarrative-ai-game-creator.recent-workspaces.v1',
|
||||
JSON.stringify(['/tmp/ready-project']),
|
||||
@@ -173,7 +149,7 @@ test('失败结果不跨轮保留:刷新时该项回到「检查中」并重
|
||||
return { ...READY_PROJECT, projectPath };
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = { core: { invoke: asTauriInvoke(invoke) } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
window.localStorage.setItem(
|
||||
'genarrative-ai-game-creator.recent-workspaces.v1',
|
||||
JSON.stringify(['/tmp/broken-project']),
|
||||
@@ -218,7 +194,7 @@ test('提权类失败不重试:不放大 UAC 弹窗', async () => {
|
||||
);
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = { core: { invoke: asTauriInvoke(invoke) } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
window.localStorage.setItem(
|
||||
'genarrative-ai-game-creator.recent-workspaces.v1',
|
||||
JSON.stringify(['/tmp/elevation-project']),
|
||||
@@ -263,19 +239,17 @@ test('Rust 偏好事件与 command 返回同时到达时只检查新增项目一
|
||||
throw new Error('unexpected invoke ' + command);
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = {
|
||||
core: { invoke: asTauriInvoke(invoke) },
|
||||
installTauriRuntime({
|
||||
core: { invoke },
|
||||
event: {
|
||||
listen: asTauriListen(
|
||||
vi.fn(async (_event, handler) => {
|
||||
emitPreferenceEvent = handler;
|
||||
return () => {
|
||||
emitPreferenceEvent = null;
|
||||
};
|
||||
}),
|
||||
),
|
||||
listen: vi.fn(async (_event, handler) => {
|
||||
emitPreferenceEvent = handler;
|
||||
return () => {
|
||||
emitPreferenceEvent = null;
|
||||
};
|
||||
}),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useRecentProjects(vi.fn()));
|
||||
await waitFor(() => {
|
||||
@@ -309,7 +283,7 @@ test('Rust 偏好事件与 command 返回同时到达时只检查新增项目一
|
||||
);
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = { core: { invoke: asTauriInvoke(invoke) } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
window.localStorage.setItem(
|
||||
'genarrative-ai-game-creator.recent-workspaces.v1',
|
||||
JSON.stringify(['/tmp/denied-elevation-project']),
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
type RuntimeRegionReference,
|
||||
} from '../src/features/project-workspace/resourceReferences';
|
||||
import type { UserContentPart } from '../src/view/project-development/chat/generated/UserContentPart';
|
||||
import { installTauriRuntime, resetTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
function asset(
|
||||
id: string,
|
||||
@@ -67,7 +68,7 @@ const attachmentPart: UserContentPart = {
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
vi.restoreAllMocks();
|
||||
window.__TAURI__ = undefined;
|
||||
resetTauriRuntime();
|
||||
});
|
||||
|
||||
describe('资源引用 provider', () => {
|
||||
@@ -368,7 +369,7 @@ describe('Skill provider', () => {
|
||||
if (command === 'list_client_extensions') return [];
|
||||
throw new Error(`unexpected invoke ${command}`);
|
||||
});
|
||||
window.__TAURI__ = { core: { invoke: invoke as never } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
|
||||
const { result } = renderHook(() => useSkillReferenceProvider());
|
||||
expect(result.current.trigger).toBe('$');
|
||||
@@ -420,7 +421,7 @@ describe('Skill provider', () => {
|
||||
}
|
||||
throw new Error(`unexpected invoke ${command}`);
|
||||
});
|
||||
window.__TAURI__ = { core: { invoke: invoke as never } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
|
||||
const { result } = renderHook(() => useSkillReferenceProvider());
|
||||
act(() => {
|
||||
@@ -450,7 +451,7 @@ describe('Skill provider', () => {
|
||||
if (command === 'list_client_extensions') return [];
|
||||
throw new Error(`unexpected invoke ${command}`);
|
||||
});
|
||||
window.__TAURI__ = { core: { invoke: invoke as never } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
|
||||
const { result } = renderHook(() => useSkillReferenceProvider());
|
||||
|
||||
@@ -511,7 +512,7 @@ describe('Skill provider', () => {
|
||||
}
|
||||
throw new Error(`unexpected invoke ${command}`);
|
||||
});
|
||||
window.__TAURI__ = { core: { invoke: invoke as never } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
|
||||
const { result } = renderHook(() => useSkillReferenceProvider());
|
||||
act(() => {
|
||||
@@ -542,7 +543,7 @@ describe('Skill provider', () => {
|
||||
throw new Error(`unexpected invoke ${command}`);
|
||||
})
|
||||
.mockRejectedValueOnce(new Error('transient'));
|
||||
window.__TAURI__ = { core: { invoke: invoke as never } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
|
||||
const { result } = renderHook(() => useSkillReferenceProvider());
|
||||
act(() => {
|
||||
@@ -568,7 +569,7 @@ describe('Skill provider', () => {
|
||||
|
||||
it('`toReference` / `refresh` / `mentionToken` 只认 Skill', async () => {
|
||||
const invoke = vi.fn(async () => []);
|
||||
window.__TAURI__ = { core: { invoke: invoke as never } };
|
||||
installTauriRuntime({ core: { invoke } });
|
||||
const { result } = renderHook(() => useSkillReferenceProvider());
|
||||
|
||||
expect(
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
waitFor,
|
||||
within,
|
||||
} from './appSurface/harness';
|
||||
import { installTauriRuntime } from './tauriRuntimeFake';
|
||||
|
||||
const PROJECT_PATH = '/tmp/batch-tags-project';
|
||||
const PROJECT_ID = 'batch-tags-project';
|
||||
@@ -294,10 +295,10 @@ function installHostTauri(
|
||||
throw new Error(`unexpected invoke ${command}`);
|
||||
},
|
||||
);
|
||||
window.__TAURI__ = {
|
||||
core: { invoke: invoke as never },
|
||||
event: { listen: (async () => () => undefined) as never },
|
||||
};
|
||||
installTauriRuntime({
|
||||
core: { invoke },
|
||||
event: { listen: async () => () => undefined },
|
||||
});
|
||||
return {
|
||||
invoke,
|
||||
batchWrites,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user