Files
Genarrative/apps/ai-game-creator-shell/tests/clientAuthStorage.test.ts
T
kdletters df39d5a16f
Project CI / AI game creator shell Rust shard 1/4 (push) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (push) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (push) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (push) Has been cancelled
Project CI / AI game creator shell Rust smoke (push) Has been cancelled
Project CI / AI game creator shell Rust crates (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Project CI / Frontend 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
修复客户端渠道与错误报告展示
客户端 debug 保留服务器选择,正式包按发布渠道连接服务

修复错误报告时间解析与超时路由脱敏

重做后台错误详情面板并补齐定向测试

同步渠道、诊断与后台展示文档
2026-09-21 01:52:35 +08:00

124 lines
4.4 KiB
TypeScript

/** @vitest-environment jsdom */
import { afterEach, describe, expect, it, vi } from 'vitest';
import {
getStoredAuthAccessToken as getApiAccessToken,
requestClientApi,
} from '../src/services/clientApi';
import {
clearStoredAuthAccessToken,
getStoredAuthAccessToken,
setStoredAuthAccessToken,
} from '../src/services/clientAuth';
import { AGC_DEVELOPMENT_API_BASE_URL } from '../src/services/clientHttp';
vi.mock('@tauri-apps/plugin-http', () => ({ fetch: vi.fn() }));
vi.mock('../src/services/errorReporting', () => ({
captureClientError: vi.fn(),
}));
const tokenKey = 'genarrative.auth.access-token.v1';
const originKey = 'genarrative.auth.access-token-origin.v1';
const selectionKey = 'genarrative.client.server-selection.v1';
describe('AGC platform credential origin', () => {
afterEach(() => {
window.localStorage.clear();
vi.restoreAllMocks();
vi.unstubAllEnvs();
});
it('preserves a credential already marked as dev', () => {
window.localStorage.setItem(tokenKey, 'existing-dev-token');
window.localStorage.setItem(originKey, AGC_DEVELOPMENT_API_BASE_URL);
expect(getStoredAuthAccessToken()).toBe('existing-dev-token');
expect(getApiAccessToken()).toBe('existing-dev-token');
expect(window.localStorage.getItem(originKey)).toBe(
AGC_DEVELOPMENT_API_BASE_URL,
);
});
it.each([
JSON.stringify({ preset: 'dev', customBaseUrl: '' }),
JSON.stringify({
preset: 'custom',
customBaseUrl: `${AGC_DEVELOPMENT_API_BASE_URL}/`,
}),
JSON.stringify({ preset: 'release', customBaseUrl: '' }),
JSON.stringify({ preset: 'custom', customBaseUrl: 'https://example.com' }),
JSON.stringify({
preset: 'custom',
customBaseUrl: 'http://localhost:8082',
}),
JSON.stringify({ preset: 'unknown', customBaseUrl: '' }),
'invalid-json',
'null',
])(
'never infers a legacy credential origin from a saved preference: %s',
async (selection) => {
window.localStorage.setItem(tokenKey, 'other-server-token');
window.localStorage.setItem(selectionKey, selection);
vi.stubEnv('MODE', 'production');
const fetchMock = vi
.spyOn(globalThis, 'fetch')
.mockResolvedValue(
new Response(JSON.stringify({ result: true }), { status: 200 }),
);
await requestClientApi('/api/profile/dashboard', {}, '读取失败');
expect(fetchMock).toHaveBeenCalledTimes(1);
const [url, init] = fetchMock.mock.calls[0];
expect(url).toBe(`${AGC_DEVELOPMENT_API_BASE_URL}/api/profile/dashboard`);
expect(new Headers(init?.headers).get('Authorization')).toBeNull();
expect(window.localStorage.getItem(tokenKey)).toBeNull();
},
);
it.each([true, false])(
'clears an unmarked credential without a preference (development=%s)',
(development) => {
// Vitest 0.34 stores stubbed env values as strings; use a falsy value for DEV=false.
vi.stubEnv('DEV', development ? 'true' : '');
window.localStorage.setItem(tokenKey, 'legacy-token');
expect(getStoredAuthAccessToken()).toBe('');
},
);
it('does not relabel a credential that already belongs to another origin', () => {
window.localStorage.setItem(tokenKey, 'other-origin-token');
window.localStorage.setItem(originKey, 'https://www.genarrative.world');
window.localStorage.setItem(
selectionKey,
JSON.stringify({ preset: 'dev' }),
);
expect(getApiAccessToken()).toBe('');
expect(window.localStorage.getItem(tokenKey)).toBeNull();
expect(window.localStorage.getItem(originKey)).toBeNull();
});
it('stores credentials with their origin and keeps debug server preferences', () => {
setStoredAuthAccessToken('new-token');
window.localStorage.setItem(
selectionKey,
JSON.stringify({ preset: 'release' }),
);
expect(getStoredAuthAccessToken(AGC_DEVELOPMENT_API_BASE_URL)).toBe(
'new-token',
);
expect(getStoredAuthAccessToken('https://www.genarrative.world')).toBe('');
setStoredAuthAccessToken('release-token', 'https://www.genarrative.world');
expect(getStoredAuthAccessToken('https://www.genarrative.world')).toBe(
'release-token',
);
expect(window.localStorage.getItem(selectionKey)).toContain('release');
clearStoredAuthAccessToken();
expect(window.localStorage.getItem(tokenKey)).toBeNull();
expect(window.localStorage.getItem(originKey)).toBeNull();
});
});