Files
Genarrative/apps/ai-game-creator-shell/tests/projectSnapshotWorkspace.test.tsx
T
kdletters 15774a1c02
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 7m24s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 7m25s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 7m28s
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 7m31s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m57s
Project CI / AI game creator shell Rust crates (push) Successful in 2m41s
Project CI / Repository checks (push) Successful in 4m10s
Project CI / Native shell tests (push) Successful in 11m20s
Project CI / Frontend tests (push) Successful in 10m30s
Project CI / AI game creator shell web tests (push) Successful in 5m41s
Project CI / Backend tests (push) Successful in 14m9s
修复项目自动上传并增加后台完整工程下载
接入真实项目打开、切换和关闭生命周期并修复退出等待竞态
新增后台项目列表及按原目录校验导出的 ZIP 下载
补充快照完整性元数据、后台权限和取消清理
固定默认 AGC 存储目标并支持空文件与特殊字符路径
补充自动化测试及真实 OSS 只读导出验证
记录本地数据库 404 导致完整 HTTP 联调和安装版实机验证待补
2026-09-20 10:07:31 +08:00

109 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';
afterEach(() => {
cleanup();
delete window.__TAURI__;
});
describe('项目快照窗口登记', () => {
it('在无 projectPath URL 的单窗口登记、切换、离开,StrictMode 不误关项目', async () => {
const invoke = vi.fn(async () => undefined);
window.__TAURI__ = { core: { invoke: invoke as never } };
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' },
);
});
});