Files
Genarrative/apps/ai-game-creator-shell/tests/clientOperation.test.ts
T
kdletters c146f7f99c
Project CI / Repository checks (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
建立 AGC 稳定版生命周期基础合同 (#348)
## 变更内容

这是基于 PR #346 的稳定版生命周期基础切换,承接已完成的 HTTP body timeout、Runner blocking worker、最近项目逐项刷新和首页跨页防重:

- 新增统一 `ClientOperation` 合同,固定 operationId、requestId、phase、deadline、scope、cancellable 和 stale 判定;
- 认证 refresh 投影 `auth-refresh` operation;登录、401 refresh、退出共用平台 session generation,并由 `auth-transition` 投影 Runner phase/成功/失败/不确定状态;
- 首页自动创建记录 draft、startMode、phase 和建项后的 project scope,页面卸载不会释放 operation;
- `.app/dev-stack.json` 增加 instanceId、repoRoot、服务级 dataDir/instanceId,AGC Vite marker 增加 repoRoot/processId/port;缺身份的旧状态拒绝 AGC 后端复用;
- 新增稳定版生命周期主规范、开发运维口径和 shared pitfalls。

## 验证

- `npm --prefix apps/ai-game-creator-shell run typecheck`
- `npm --prefix apps/ai-game-creator-shell exec -- vitest run tests/clientOperation.test.ts tests/clientApi.test.ts tests/clientHttp.test.ts tests/recentProjectsModel.test.ts tests/start-dev-stack.test.ts tests/dev-port.test.ts --reporter=dot`(61 passed,2 skipped)
- `npm --prefix apps/ai-game-creator-shell exec -- vitest run tests/appSurface.test.ts --reporter=dot`(423/423 passed)
- `node --check scripts/dev.mjs`
- `node --check apps/ai-game-creator-shell/scripts/start-dev-stack.mjs`
- `npm run check:doc-index`
- `npm run check:encoding`
- `git diff --check`

`scripts/dev.test.ts` 全量仍有 1 个 Windows 文件权限相关既有失败:bootstrap secret 测试在 Windows 上无法通过 chmod 模拟 0600;本变更未触及该逻辑。

Reviewed-on: #348
2026-09-14 13:56:56 +08:00

43 lines
1.6 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
cancelClientOperation,
clientOperationCanRetry,
createClientOperation,
isCurrentClientOperation,
transitionClientOperation,
} from '../src/services/clientOperation';
describe('AGC client operation contract', () => {
it('keeps operation/request identity and deadline across phase transitions', () => {
const operation = createClientOperation(
'home-create',
{ prompt: '做一个游戏' },
{ scope: { projectPath: 'C:\\games\\demo' }, deadlineMs: 15_000 },
);
const network = transitionClientOperation(operation, 'network');
const project = transitionClientOperation(network, 'project', {
scope: { projectPath: 'C:\\games\\created' },
});
expect(project.operationId).toBe(operation.operationId);
expect(project.requestId).toBe(operation.requestId);
expect(project.deadlineAt).toBe(operation.startedAt + 15_000);
expect(project.scope.projectPath).toBe('C:\\games\\created');
expect(project.cancellable).toBe(true);
expect(isCurrentClientOperation(project, operation.operationId)).toBe(true);
});
it('marks cancellation as stale and does not make it retryable', () => {
const operation = createClientOperation('auth-refresh', null);
const failed = transitionClientOperation(operation, 'retryable-failure');
expect(clientOperationCanRetry(failed)).toBe(true);
const cancelled = cancelClientOperation(failed);
expect(cancelled.cancelled).toBe(true);
expect(isCurrentClientOperation(cancelled, operation.operationId)).toBe(
false,
);
expect(clientOperationCanRetry(cancelled)).toBe(false);
});
});