测试:把 Tauri 替身安装点收口到 appSurface harness

- 合并 chat-composer / project-conversation / project-development / runtime-settings / design-agent 五处重复的 installTauriRuntime 定义为 harness 中一处
- 安装参数由 unknown 收成可调用下界并声明 event 可缺省,非函数的误装会在编译期被挡下
- design-agent 改为薄适配 installChatRuntime,调用点与运行时行为不变
This commit is contained in:
2026-10-03 19:14:08 +08:00
parent a83525c964
commit 6efab10743
6 changed files with 42 additions and 60 deletions
@@ -21,6 +21,7 @@ import {
createProjectChatRuntimeHarness,
expect,
fireEvent,
installTauriRuntime,
it,
pickProjectFromLauncher,
React,
@@ -40,19 +41,6 @@ type InvokeOverrides = Record<
(args: Record<string, unknown> | undefined) => unknown
>;
/**
* 安装测试用 Tauri 替身。
*
* `vi.fn` 的返回类型是固定签名,装不进 `window.__TAURI__` 声明的泛型签名(invoke/listen 都是
* 泛型函数),这里在装入点整体显式转换,行为与直接赋值一致。
*/
function installTauriRuntime(runtime: {
core: { invoke: unknown };
event?: { listen: unknown };
}) {
window.__TAURI__ = runtime as unknown as Window['__TAURI__'];
}
function gameCreatorConfigView(reasoningEffort: string) {
return {
path: '/tmp/chat-composer-config.json',
@@ -6,6 +6,7 @@ import {
createProjectChatRuntimeHarness,
expect,
fireEvent,
installTauriRuntime,
it,
React,
render,
@@ -17,16 +18,13 @@ import {
type ChatRuntimeHarness = ReturnType<typeof createProjectChatRuntimeHarness>;
/**
* 安装测试用 Tauri 替身。
*
* harness 的 invoke/listen 是 `vi.fn` 的固定签名,装不进 `window.__TAURI__` 声明的泛型签名
* (invoke/listen 都是泛型函数),这里在装入点整体显式转换,行为与直接赋值一致。
* 把夹具的 invoke / listen 装进 `window.__TAURI__`:转换点只有 harness.installTauriRuntime 一处。
*/
function installTauriRuntime(harness: ChatRuntimeHarness) {
window.__TAURI__ = {
function installChatRuntime(harness: ChatRuntimeHarness) {
installTauriRuntime({
core: { invoke: harness.invoke },
event: { listen: harness.listen },
} as unknown as Window['__TAURI__'];
});
}
/**
@@ -50,7 +48,7 @@ const AppComponent = App as React.ComponentType<
function renderDesignAgent(
harness: ReturnType<typeof createProjectChatRuntimeHarness>,
) {
installTauriRuntime(harness);
installChatRuntime(harness);
window.history.pushState({}, '', '/');
return render(
React.createElement(AppComponent, {
@@ -401,7 +399,7 @@ export function registerDesignAgentSurfaceTests() {
],
},
});
installTauriRuntime(harness);
installChatRuntime(harness);
window.history.pushState({}, '', '/');
render(
React.createElement(AppComponent, {
@@ -765,7 +763,7 @@ export function registerDesignAgentSurfaceTests() {
const harness = createProjectChatRuntimeHarness({
designAgentView: designApprovalView(),
});
installTauriRuntime(harness);
installChatRuntime(harness);
window.history.pushState({}, '', '/');
render(
React.createElement(AppComponent, {
@@ -808,7 +806,7 @@ export function registerDesignAgentSurfaceTests() {
},
},
});
installTauriRuntime(harness);
installChatRuntime(harness);
window.history.pushState({}, '', '/');
render(
React.createElement(AppComponent, {
@@ -843,7 +841,7 @@ export function registerDesignAgentSurfaceTests() {
designAgentView: designConversationView(),
designAgentContinueView: designConversationView(),
});
installTauriRuntime(harness);
installChatRuntime(harness);
window.history.pushState({}, '', '/');
render(
React.createElement(AppComponent, {
@@ -910,7 +908,7 @@ export function registerDesignAgentSurfaceTests() {
const harness = createProjectChatRuntimeHarness({
designAgentView: designHistoryView(),
});
installTauriRuntime(harness);
installChatRuntime(harness);
window.history.pushState({}, '', '/');
render(
React.createElement(AppComponent, {
@@ -935,6 +935,33 @@ function createProjectChatRuntimeHarness({
};
}
/**
* 安装测试用 Tauri 替身。
*
* `vi.fn` 与各夹具的 invoke / listen 是固定签名,装不进 `window.__TAURI__` 声明的泛型签名
* (两者都是泛型函数),这里把唯一的装入点收在 harness,整体显式转换,行为与直接赋值一致。
*
* 参数用「可调用」下界而不是 `unknown`:非函数的误装(字符串、undefined)会在编译期被挡下,
* 同时不与各夹具更具体的 mock 签名冲突;`core` / `event` 都可缺省,只装 invoke 的用例
* 不需要伪造 event。
*/
export function installTauriRuntime(runtime: {
core?: {
invoke?: (
command: string,
args?: Record<string, unknown>,
) => Promise<unknown>;
};
event?: {
listen?: (
event: string,
handler: (event: { payload: unknown }) => void,
) => Promise<() => void>;
};
}) {
window.__TAURI__ = runtime as unknown as Window['__TAURI__'];
}
export function installResizeObserverStub() {
let observerCount = 0;
let observerDisconnected = false;
@@ -10,6 +10,7 @@ import {
emptyProjectPolicy,
expect,
fireEvent,
installTauriRuntime,
it,
mockRoleAgentReply,
renderAppAt,
@@ -20,19 +21,6 @@ import {
within,
} from './harness';
/**
* 安装测试用 Tauri 替身。
*
* `vi.fn` 的返回类型是固定签名,装不进 `window.__TAURI__` 声明的泛型签名(invoke/listen 都是
* 泛型函数),这里在装入点整体显式转换,行为与直接赋值一致。
*/
function installTauriRuntime(runtime: {
core: { invoke: unknown };
event?: { listen: unknown };
}) {
window.__TAURI__ = runtime as unknown as Window['__TAURI__'];
}
export function registerProjectConversationTests() {
it('splits structured rejections by variant and never by copy', () => {
// 入队失败是**结构化**载荷:分流只看 `instanceof` 与 `error.type`,文案不参与任何判断,
@@ -38,6 +38,7 @@ import {
fireEvent,
getResourceSelectButton,
installResizeObserverStub,
installTauriRuntime,
it,
openResourceFilterPanel,
ProjectDevelopmentView,
@@ -52,17 +53,6 @@ import {
within,
} from './harness';
/**
* 安装测试用 Tauri 替身。
*
* `vi.fn` 的返回类型是固定签名,装不进 `window.__TAURI__` 声明的泛型签名(invoke 是泛型函数),
* 这里在装入点整体显式转换,行为与直接赋值一致。
*/
function installTauriRuntime(runtime: { core: { invoke: unknown } }) {
// `vi.fn` 固定签名装不进 `window.__TAURI__` 的泛型签名,这里显式转换,运行时行为不变。
window.__TAURI__ = runtime as unknown as Window['__TAURI__'];
}
/**
* 历史夹具沿用的旧 kind 字面量(如 `design-document` / `game-code`)已不在当前
* `GameCreationAppAssetKind` 联合里;这些用例依赖未识别 kind 落「待归类」的运行时语义,
@@ -11,6 +11,7 @@ import {
fireEvent,
GAME_CREATION_AGENT_RUN_SCHEMA_VERSION,
type GameCreationAgentRunTrace,
installTauriRuntime,
it,
renderLauncherAt,
screen,
@@ -19,16 +20,6 @@ import {
within,
} from './harness';
/**
* 安装测试用 Tauri invoke 替身。
*
* `vi.fn` 的返回类型是固定签名,装不进 `window.__TAURI__` 声明的泛型签名(invoke 是泛型
* 函数),这里在装入点整体显式转换,行为与直接赋值一致。
*/
function installTauriRuntime(runtime: { core: { invoke: unknown } }) {
window.__TAURI__ = runtime as unknown as Window['__TAURI__'];
}
export function registerAgentStatusDerivationTests() {
it('keeps fixed overlays below the in-page window title bar', () => {
const styles = fs.readFileSync(