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 联调和安装版实机验证待补
109 lines
4.0 KiB
TypeScript
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' },
|
|
);
|
|
});
|
|
});
|