Files
Genarrative/apps/ai-game-creator-shell/tests/directRunAnalytics.test.ts
T
lhk229 9f225b7a41 实现客户端本地埋点与创作链路采集
新增统一事件合同、非阻塞明文队列、批次封存及保留清理
接入会话前台时长、项目创建打开、创作提交和双智能体运行结果
按策划阶段推进及已接入成果路径记录变化、预览就绪与保存
补齐身份隔离、异常会话和同一宿主创作链路验证
同步团队方案与验收证据,本期不上传、不加密、不扩展资源操作采集
2026-09-21 12:18:47 +00:00

92 lines
2.9 KiB
TypeScript

// @vitest-environment jsdom
import { afterEach, expect, it, vi } from 'vitest';
import type { TauriInvoke } from '../src/app/types';
import { beginDirectRunAnalytics } from '../src/services/clientAnalytics';
afterEach(() => vi.restoreAllMocks());
it('自动重试保持业务回合,只确认最后一次尝试且确认不等待桥接', async () => {
const first = '11111111-1111-4111-8111-111111111111';
const last = '22222222-2222-4222-8222-222222222222';
vi.spyOn(crypto, 'randomUUID')
.mockReturnValueOnce(first)
.mockReturnValueOnce(last);
const invoke = vi.fn(() => new Promise(() => {}));
const analytics = beginDirectRunAnalytics(invoke as TauriInvoke, () => 1);
const attempts: string[] = [];
const operation = async () => {
attempts.push(analytics.nextAttempt()!);
if (attempts.length === 1) throw new Error('authentication-required');
return '完成';
};
let result: string;
try {
result = await operation().catch(() => operation());
expect(invoke).not.toHaveBeenCalled();
} finally {
analytics.settle();
}
expect(result).toBe('完成');
expect(attempts).toEqual([first, last]);
expect(invoke).toHaveBeenCalledTimes(1);
expect(invoke).toHaveBeenCalledWith('settle_direct_run_analytics', {
attemptId: last,
discard: false,
});
analytics.settle();
expect(invoke).toHaveBeenCalledTimes(1);
});
it('最终 UUID 失败不能回退确认第一次失败', () => {
vi.spyOn(crypto, 'randomUUID')
.mockReturnValueOnce('11111111-1111-4111-8111-111111111111')
.mockImplementationOnce(() => {
throw new Error('UUID unavailable');
});
const invoke = vi.fn();
const analytics = beginDirectRunAnalytics(invoke as TauriInvoke, () => 1);
expect(analytics.nextAttempt()).toBeDefined();
expect(analytics.nextAttempt()).toBeUndefined();
analytics.settle();
expect(invoke).not.toHaveBeenCalled();
});
it('账号代次变化只丢弃候选,不提交成功失败结论', () => {
let generation = 1;
const invoke = vi.fn(async () => undefined);
const analytics = beginDirectRunAnalytics(
invoke as TauriInvoke,
() => generation,
);
const attemptId = analytics.nextAttempt();
generation = 2;
analytics.settle();
expect(invoke).toHaveBeenCalledWith('settle_direct_run_analytics', {
attemptId,
discard: true,
});
});
it.each(['sync', 'async'])(
'确认桥接 %s 失败不会覆盖最终业务错误',
async (mode) => {
const invoke = vi.fn(() => {
if (mode === 'sync') throw new Error('bridge');
return Promise.reject(new Error('bridge'));
});
const analytics = beginDirectRunAnalytics(invoke as TauriInvoke, () => 1);
const failure = new Error('最终执行失败');
const operation = async () => {
try {
analytics.nextAttempt();
throw failure;
} finally {
analytics.settle();
}
};
await expect(operation()).rejects.toBe(failure);
expect(invoke).toHaveBeenCalledTimes(1);
},
);