Files
Genarrative/apps/ai-game-creator-shell/tests/directRunAnalytics.test.ts
T
lhk229 1e186369c9
Project CI / AI game creator shell Rust crates (push) Successful in 1m24s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m56s
Project CI / AI game creator shell Rust lane 1/2 (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
客户端埋点设置 (#446)
Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/446
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-09-23 00:09:12 +08: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);
},
);