Files
Genarrative/src/services/rpg-entry/rpgProfileClient.test.ts
2026-05-09 18:24:08 +08:00

234 lines
6.3 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
const { requestJsonMock } = vi.hoisted(() => ({
requestJsonMock: vi.fn(),
}));
import {
clearRpgProfileBrowseHistory,
listRpgProfileBrowseHistory,
listRpgProfileSaveArchives,
resumeRpgProfileSaveArchive,
submitRpgProfileFeedback,
syncRpgProfileBrowseHistory,
upsertRpgProfileBrowseHistory,
} from './rpgProfileClient';
vi.mock('../apiClient', () => ({
BACKGROUND_AUTH_REQUEST_OPTIONS: {
authImpact: 'local',
skipRefresh: true,
notifyAuthStateChange: false,
clearAuthOnUnauthorized: false,
},
requestJson: requestJsonMock,
}));
describe('rpgProfileClient browse history routes', () => {
beforeEach(() => {
requestJsonMock.mockReset();
requestJsonMock.mockResolvedValue({ entries: [] });
});
it('reads browse history from the profile route', async () => {
await listRpgProfileBrowseHistory();
expect(requestJsonMock).toHaveBeenCalledWith(
'/api/profile/browse-history',
expect.objectContaining({ method: 'GET' }),
'读取浏览历史失败',
expect.objectContaining({
authImpact: 'local',
retry: expect.objectContaining({ maxRetries: 1 }),
skipRefresh: true,
notifyAuthStateChange: false,
clearAuthOnUnauthorized: false,
}),
);
});
it('writes browse history through the profile route', async () => {
await upsertRpgProfileBrowseHistory({
ownerUserId: 'user-1',
profileId: 'profile-1',
worldName: '测试世界',
subtitle: '测试副标题',
summaryText: '测试摘要',
coverImageSrc: null,
themeMode: 'mythic',
authorDisplayName: '测试作者',
});
expect(requestJsonMock).toHaveBeenCalledWith(
'/api/profile/browse-history',
expect.objectContaining({
method: 'POST',
headers: { 'Content-Type': 'application/json' },
}),
'写入浏览历史失败',
expect.objectContaining({
authImpact: 'local',
retry: expect.objectContaining({
maxRetries: 1,
retryUnsafeMethods: true,
}),
skipRefresh: true,
notifyAuthStateChange: false,
clearAuthOnUnauthorized: false,
}),
);
});
it('syncs browse history through the profile route', async () => {
await syncRpgProfileBrowseHistory([
{
ownerUserId: 'user-1',
profileId: 'profile-1',
worldName: '测试世界',
subtitle: '测试副标题',
summaryText: '测试摘要',
coverImageSrc: null,
themeMode: 'mythic',
authorDisplayName: '测试作者',
},
]);
expect(requestJsonMock).toHaveBeenCalledWith(
'/api/profile/browse-history',
expect.objectContaining({
method: 'POST',
headers: { 'Content-Type': 'application/json' },
}),
'同步浏览历史失败',
expect.any(Object),
);
});
it('clears browse history through the profile route', async () => {
await clearRpgProfileBrowseHistory();
expect(requestJsonMock).toHaveBeenCalledWith(
'/api/profile/browse-history',
expect.objectContaining({ method: 'DELETE' }),
'清空浏览历史失败',
expect.objectContaining({
retry: expect.objectContaining({
maxRetries: 1,
retryUnsafeMethods: true,
}),
}),
);
});
});
describe('rpgProfileClient save archive routes', () => {
beforeEach(() => {
requestJsonMock.mockReset();
requestJsonMock.mockResolvedValue({ entries: [] });
});
it('reads save archives from the profile route', async () => {
await listRpgProfileSaveArchives();
expect(requestJsonMock).toHaveBeenCalledWith(
'/api/profile/save-archives',
expect.objectContaining({ method: 'GET' }),
'读取存档列表失败',
expect.objectContaining({
authImpact: 'local',
retry: expect.objectContaining({ maxRetries: 1 }),
skipRefresh: true,
notifyAuthStateChange: false,
clearAuthOnUnauthorized: false,
}),
);
});
it('resumes a save archive through the profile route', async () => {
requestJsonMock.mockResolvedValueOnce({
entry: {
worldKey: 'custom:world-1',
},
snapshot: {
version: 2,
savedAt: '2026-04-19T10:15:00.000Z',
bottomTab: 'adventure',
currentStory: null,
gameState: {
worldType: 'CUSTOM',
},
},
});
await resumeRpgProfileSaveArchive('custom:world-1');
expect(requestJsonMock).toHaveBeenCalledWith(
'/api/profile/save-archives/custom%3Aworld-1',
expect.objectContaining({ method: 'POST' }),
'恢复存档失败',
expect.objectContaining({
retry: expect.objectContaining({
maxRetries: 1,
retryUnsafeMethods: true,
}),
}),
);
});
});
describe('rpgProfileClient feedback routes', () => {
beforeEach(() => {
requestJsonMock.mockReset();
requestJsonMock.mockResolvedValue({
feedback: {
feedbackId: 'feedback:user-1:1',
status: 'open',
createdAt: '2026-05-08T10:00:00Z',
evidenceItems: [],
},
});
});
it('submits profile feedback through the profile route', async () => {
await submitRpgProfileFeedback({
description: '图片上传后没有展示预览',
contactPhone: null,
evidenceItems: [
{
fileName: 'preview.png',
contentType: 'image/png',
sizeBytes: 128,
dataUrl: 'data:image/png;base64,ZmVlZGJhY2s=',
},
],
});
expect(requestJsonMock).toHaveBeenCalledWith(
'/api/profile/feedback',
expect.objectContaining({
method: 'POST',
headers: { 'Content-Type': 'application/json' },
}),
'提交反馈失败',
expect.objectContaining({
retry: expect.objectContaining({
maxRetries: 1,
retryUnsafeMethods: true,
}),
}),
);
expect(JSON.parse(requestJsonMock.mock.calls[0][1].body)).toEqual({
description: '图片上传后没有展示预览',
contactPhone: null,
evidenceItems: [
{
fileName: 'preview.png',
contentType: 'image/png',
sizeBytes: 128,
dataUrl: 'data:image/png;base64,ZmVlZGJhY2s=',
},
],
});
});
});