Files
Genarrative/apps/ai-game-creator-shell/tests/platformSession.test.ts
T
k88936 594063a1e0 测试:修正 AGC 测试文件的类型错误
- 按 vitest 0.34 的参数元组口径改写 mock 泛型
- 修正 noUncheckedIndexedAccess 下的下标访问
- 补齐与当前类型脱节的测试桩字段
- 按 scripts/*.mjs 的运行时契约补局部类型声明
2026-10-03 17:41:30 +08:00

190 lines
5.6 KiB
TypeScript

// @vitest-environment node
/**
* 平台会话代次的语义。
*
* 渲染层只持有这一个派生计数,用来识别换号/登出后到达的迟到结果。它必须在
* 「同一账号续期」和「同一身份重复采纳(StrictMode 双次 hydrate)」时保持不变——否则
* 在途生成会被自己的续期判成旧账号请求;而换账号、换 origin、登出又必须立刻推进。
*/
import { beforeEach, expect, test, vi } from 'vitest';
import type { AuthUser } from '../../../packages/shared/src/contracts/auth';
const refreshClientAuthSession = vi.hoisted(() => vi.fn());
vi.mock('../src/services/clientAuth', () => ({
refreshClientAuthSession,
subscribeClientAuthState: () => () => {},
}));
import {
beginPlatformSessionTransition,
commitAuthenticatedPlatformSession,
currentPlatformSessionGeneration,
requestPlatformSessionRefresh,
resetPlatformSessionForTests,
subscribePlatformSessionGeneration,
} from '../src/services/platformSession';
const userA: AuthUser = {
id: 'user-a',
publicUserCode: 'tn-a',
displayName: '账号 A',
avatarUrl: null,
phoneNumber: null,
phoneNumberMasked: null,
loginMethod: 'password',
bindingStatus: 'active',
wechatBound: false,
wechatDisplayName: null,
wechatAccount: null,
};
const userB = {
...userA,
id: 'user-b',
publicUserCode: 'tn-b',
displayName: '账号 B',
};
beforeEach(() => {
refreshClientAuthSession.mockReset();
resetPlatformSessionForTests();
});
test('同一身份重复采纳不推进代次,换 origin 或换账号才推进', async () => {
const observed: number[] = [];
const unsubscribe = subscribePlatformSessionGeneration((generation) => {
observed.push(generation);
});
const first = await commitAuthenticatedPlatformSession(
userA,
currentPlatformSessionGeneration(),
'https://a.example.com',
);
expect(first).toBe(1);
// StrictMode 双次 hydrate 或同一账号重新登录:代次必须原地不动。
const again = await commitAuthenticatedPlatformSession(
userA,
currentPlatformSessionGeneration(),
'https://a.example.com',
);
expect(again).toBe(first);
const otherOrigin = await commitAuthenticatedPlatformSession(
userA,
currentPlatformSessionGeneration(),
'https://b.example.com',
);
expect(otherOrigin).toBe(2);
const otherUser = await commitAuthenticatedPlatformSession(
userB,
currentPlatformSessionGeneration(),
'https://b.example.com',
);
expect(otherUser).toBe(3);
expect(observed).toEqual([1, 2, 3]);
unsubscribe();
});
test('期望代次已过期时不采纳身份', async () => {
await commitAuthenticatedPlatformSession(
userA,
currentPlatformSessionGeneration(),
'https://a.example.com',
);
await expect(
commitAuthenticatedPlatformSession(userB, 0, 'https://a.example.com'),
).resolves.toBeNull();
expect(currentPlatformSessionGeneration()).toBe(1);
});
test('登录切换与登出立刻推进代次', () => {
const before = currentPlatformSessionGeneration();
const next = beginPlatformSessionTransition();
expect(next).toBe(before + 1);
expect(currentPlatformSessionGeneration()).toBe(next);
});
test('同一账号续期不推进代次,并发续期只发一次请求', async () => {
await commitAuthenticatedPlatformSession(
userA,
currentPlatformSessionGeneration(),
'https://a.example.com',
);
const generationBefore = currentPlatformSessionGeneration();
refreshClientAuthSession.mockResolvedValue({
status: 'refreshed',
user: userA,
});
const [first, second] = await Promise.all([
requestPlatformSessionRefresh(),
requestPlatformSessionRefresh(),
]);
expect(refreshClientAuthSession).toHaveBeenCalledTimes(1);
expect(first).toEqual({
status: 'refreshed',
user: userA,
generation: generationBefore,
});
expect(second).toEqual(first);
expect(currentPlatformSessionGeneration()).toBe(generationBefore);
});
test('续期发现未登录时采纳空身份并给出权威失败', async () => {
await commitAuthenticatedPlatformSession(
userA,
currentPlatformSessionGeneration(),
'https://a.example.com',
);
const generationBefore = currentPlatformSessionGeneration();
refreshClientAuthSession.mockResolvedValue({ status: 'unauthenticated' });
const result = await requestPlatformSessionRefresh();
expect(result.status).toBe('failed');
if (result.status === 'failed') {
expect(result.authoritative).toBe(true);
expect(String(result.error)).toContain('登录已失效');
}
expect(currentPlatformSessionGeneration()).toBe(generationBefore + 1);
});
test('续期期间换号时返回 stale,不覆盖新身份', async () => {
await commitAuthenticatedPlatformSession(
userA,
currentPlatformSessionGeneration(),
'https://a.example.com',
);
refreshClientAuthSession.mockImplementation(async () => {
beginPlatformSessionTransition();
return { status: 'refreshed', user: userA };
});
await expect(requestPlatformSessionRefresh()).resolves.toEqual({
status: 'stale',
});
});
test('网络类续期失败保持会话且不标记为权威失败', async () => {
await commitAuthenticatedPlatformSession(
userA,
currentPlatformSessionGeneration(),
'https://a.example.com',
);
const generationBefore = currentPlatformSessionGeneration();
refreshClientAuthSession.mockRejectedValue(new Error('网络不可达'));
const result = await requestPlatformSessionRefresh();
expect(result.status).toBe('failed');
if (result.status === 'failed') {
expect(result.authoritative).toBe(false);
}
expect(currentPlatformSessionGeneration()).toBe(generationBefore);
});