25c5ecdf6e
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__
110 lines
4.0 KiB
TypeScript
110 lines
4.0 KiB
TypeScript
/** @vitest-environment jsdom */
|
|
import { act, cleanup, render, waitFor } from '@testing-library/react';
|
|
import React, { StrictMode } from 'react';
|
|
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();
|
|
resetTauriRuntime();
|
|
});
|
|
|
|
describe('项目快照窗口登记', () => {
|
|
it('在无 projectPath URL 的单窗口登记、切换、离开,StrictMode 不误关项目', async () => {
|
|
const invoke = vi.fn(async () => undefined);
|
|
installTauriRuntime({ core: { invoke } });
|
|
function Workspace({ path }: { path: string | null }) {
|
|
useProjectSnapshotWorkspace(path);
|
|
return null;
|
|
}
|
|
const view = (path: string | null) => (
|
|
<StrictMode>
|
|
<Workspace path={path} />
|
|
</StrictMode>
|
|
);
|
|
expect(new URL(window.location.href).searchParams.has('projectPath')).toBe(
|
|
false,
|
|
);
|
|
const rendered = render(view('/projects/first'));
|
|
await waitFor(() => expect(invoke).toHaveBeenCalledTimes(1));
|
|
expect(invoke).toHaveBeenLastCalledWith(
|
|
'set_active_project_snapshot_workspace',
|
|
{ projectPath: '/projects/first' },
|
|
);
|
|
rendered.rerender(view('/projects/first'));
|
|
await act(async () => {
|
|
await Promise.resolve();
|
|
});
|
|
expect(invoke).toHaveBeenCalledTimes(1);
|
|
rendered.rerender(view('/projects/second'));
|
|
await waitFor(() => expect(invoke).toHaveBeenCalledTimes(2));
|
|
expect(invoke).toHaveBeenLastCalledWith(
|
|
'set_active_project_snapshot_workspace',
|
|
{ projectPath: '/projects/second' },
|
|
);
|
|
rendered.rerender(view(null));
|
|
await waitFor(() => expect(invoke).toHaveBeenCalledTimes(3));
|
|
expect(invoke).toHaveBeenLastCalledWith(
|
|
'set_active_project_snapshot_workspace',
|
|
{ projectPath: null },
|
|
);
|
|
rendered.rerender(view('/projects/third'));
|
|
await waitFor(() => expect(invoke).toHaveBeenCalledTimes(4));
|
|
rendered.unmount();
|
|
await waitFor(() => expect(invoke).toHaveBeenCalledTimes(5));
|
|
expect(invoke).toHaveBeenLastCalledWith(
|
|
'set_active_project_snapshot_workspace',
|
|
{ projectPath: null },
|
|
);
|
|
});
|
|
|
|
it('原生登记未完成时顺序提交后续切换,不让迟到回包覆盖新项目', async () => {
|
|
let release!: () => void;
|
|
const first = new Promise<void>((resolve) => {
|
|
release = resolve;
|
|
});
|
|
const invoke = vi
|
|
.fn()
|
|
.mockImplementationOnce(() => first)
|
|
.mockResolvedValue(undefined);
|
|
const registration = createProjectSnapshotWorkspaceRegistration(invoke);
|
|
void registration.setProject('/projects/first');
|
|
void registration.setProject('/projects/second');
|
|
const idle = registration.setProject(null);
|
|
await Promise.resolve();
|
|
expect(invoke).toHaveBeenCalledTimes(1);
|
|
release();
|
|
await idle;
|
|
expect(invoke.mock.calls.map((call) => call[1]?.projectPath)).toEqual([
|
|
'/projects/first',
|
|
'/projects/second',
|
|
null,
|
|
]);
|
|
});
|
|
|
|
it('失败写固定诊断并允许再次登记,不能泄漏原生错误中的路径和凭据', async () => {
|
|
const invoke = vi
|
|
.fn()
|
|
.mockRejectedValueOnce(new Error('C:\\private\\project token=secret'))
|
|
.mockResolvedValue(undefined);
|
|
const registration = createProjectSnapshotWorkspaceRegistration(invoke);
|
|
await expect(
|
|
registration.setProject('/projects/first'),
|
|
).resolves.toBeUndefined();
|
|
expect(invoke).toHaveBeenLastCalledWith('append_application_log', {
|
|
level: 'error',
|
|
source: 'project-snapshot',
|
|
message: 'project_snapshot.workspace.registration.failed',
|
|
});
|
|
await registration.setProject('/projects/first');
|
|
expect(invoke).toHaveBeenCalledTimes(3);
|
|
expect(invoke).toHaveBeenLastCalledWith(
|
|
'set_active_project_snapshot_workspace',
|
|
{ projectPath: '/projects/first' },
|
|
);
|
|
});
|
|
});
|