统一推荐页游客运行态与切换队列
统一推荐页各玩法正式 runtime 的游客鉴权透传。 收口推荐页首页展示队列和嵌入运行态切换队列。 补齐未登录读档、签名资产和个人数据读取的游客态处理。 新增运行态 HUD 小尺寸 logo 资源并更新拼图与抓鹅展示。 补充推荐切换、runtime guest 启动和客户端请求回归测试。 更新玩法链路、后端契约和团队记忆文档。
This commit is contained in:
@@ -7810,6 +7810,113 @@ test('logged out home recommendation next starts the next puzzle work', async ()
|
||||
});
|
||||
});
|
||||
|
||||
test('home recommendation next follows the same scored queue shown in preview', async () => {
|
||||
const user = userEvent.setup();
|
||||
const quietWork = {
|
||||
workId: 'puzzle-work-public-quiet',
|
||||
profileId: 'puzzle-profile-public-quiet',
|
||||
ownerUserId: 'user-2',
|
||||
sourceSessionId: 'puzzle-session-public-quiet',
|
||||
authorDisplayName: '拼图作者',
|
||||
levelName: '安静拼图',
|
||||
summary: '列表里排在前面但热度较低。',
|
||||
themeTags: ['安静', '拼图'],
|
||||
coverImageSrc: null,
|
||||
coverAssetId: null,
|
||||
publicationStatus: 'published',
|
||||
updatedAt: '2026-04-25T10:00:00.000Z',
|
||||
publishedAt: '2026-04-25T10:00:00.000Z',
|
||||
playCount: 40,
|
||||
likeCount: 0,
|
||||
publishReady: true,
|
||||
} satisfies PuzzleWorkSummary;
|
||||
const hotWork = {
|
||||
...quietWork,
|
||||
workId: 'puzzle-work-public-hot',
|
||||
profileId: 'puzzle-profile-public-hot',
|
||||
sourceSessionId: 'puzzle-session-public-hot',
|
||||
levelName: '热门拼图',
|
||||
summary: '推荐评分更高,应该先展示。',
|
||||
playCount: 120,
|
||||
updatedAt: '2026-04-25T09:00:00.000Z',
|
||||
publishedAt: '2026-04-25T09:00:00.000Z',
|
||||
} satisfies PuzzleWorkSummary;
|
||||
const middleWork = {
|
||||
...quietWork,
|
||||
workId: 'puzzle-work-public-middle',
|
||||
profileId: 'puzzle-profile-public-middle',
|
||||
sourceSessionId: 'puzzle-session-public-middle',
|
||||
levelName: '中间拼图',
|
||||
summary: '推荐评分排在后面。',
|
||||
playCount: 0,
|
||||
updatedAt: '2026-04-25T08:00:00.000Z',
|
||||
publishedAt: '2026-04-25T08:00:00.000Z',
|
||||
} satisfies PuzzleWorkSummary;
|
||||
|
||||
vi.mocked(listPuzzleGallery).mockResolvedValue({
|
||||
items: [quietWork, hotWork, middleWork],
|
||||
});
|
||||
vi.mocked(getPuzzleGalleryDetail).mockImplementation(async (profileId) => ({
|
||||
item:
|
||||
profileId === hotWork.profileId
|
||||
? hotWork
|
||||
: profileId === middleWork.profileId
|
||||
? middleWork
|
||||
: quietWork,
|
||||
}));
|
||||
vi.mocked(startPuzzleRun).mockImplementation(async (payload) => ({
|
||||
run: buildMockPuzzleRun(
|
||||
payload.profileId,
|
||||
payload.profileId === hotWork.profileId
|
||||
? hotWork.levelName
|
||||
: payload.profileId === middleWork.profileId
|
||||
? middleWork.levelName
|
||||
: quietWork.levelName,
|
||||
),
|
||||
}));
|
||||
|
||||
render(<TestWrapper withAuth />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(startPuzzleRun).toHaveBeenCalledWith(
|
||||
{
|
||||
profileId: hotWork.profileId,
|
||||
levelId: null,
|
||||
},
|
||||
LOGGED_IN_RECOMMEND_RUNTIME_AUTH_OPTIONS,
|
||||
);
|
||||
});
|
||||
expect(
|
||||
await screen.findByLabelText('热门拼图 作品信息', undefined, {
|
||||
timeout: 3000,
|
||||
}),
|
||||
).toBeTruthy();
|
||||
const nextPreview = document.querySelector(
|
||||
'.platform-recommend-swipe-page--next',
|
||||
);
|
||||
expect(nextPreview).toBeTruthy();
|
||||
expect(
|
||||
within(nextPreview as HTMLElement).getByLabelText('安静拼图 作品信息'),
|
||||
).toBeTruthy();
|
||||
|
||||
await user.click(await screen.findByRole('button', { name: '下一个' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(startPuzzleRun).toHaveBeenCalledWith(
|
||||
{
|
||||
profileId: quietWork.profileId,
|
||||
levelId: null,
|
||||
},
|
||||
LOGGED_IN_RECOMMEND_RUNTIME_AUTH_OPTIONS,
|
||||
);
|
||||
});
|
||||
expect(
|
||||
await screen.findByLabelText('安静拼图 作品信息', undefined, {
|
||||
timeout: 3000,
|
||||
}),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
test('home recommendation keeps cover while switching during a pending puzzle start', async () => {
|
||||
const user = userEvent.setup();
|
||||
const firstWork = {
|
||||
@@ -8142,6 +8249,54 @@ test('home recommendation Match3D runtime keeps profile generated models when ca
|
||||
});
|
||||
});
|
||||
|
||||
test('logged out home recommendation Match3D runtime skips protected detail and starts with guest auth', async () => {
|
||||
const match3dCard: Match3DWorkSummary = {
|
||||
workId: 'match3d-work-card-guest',
|
||||
profileId: 'match3d-profile-card-guest',
|
||||
ownerUserId: 'user-2',
|
||||
sourceSessionId: 'match3d-session-card-guest',
|
||||
gameName: '游客抓大鹅',
|
||||
themeText: '游客果园',
|
||||
summary: '游客可直接游玩。',
|
||||
tags: ['果园', '抓大鹅'],
|
||||
coverImageSrc: null,
|
||||
referenceImageSrc: null,
|
||||
clearCount: 3,
|
||||
difficulty: 5,
|
||||
publicationStatus: 'published',
|
||||
playCount: 3,
|
||||
updatedAt: '2026-04-25T10:30:00.000Z',
|
||||
publishedAt: '2026-04-25T10:30:00.000Z',
|
||||
publishReady: true,
|
||||
generatedItemAssets: [],
|
||||
};
|
||||
|
||||
vi.mocked(listMatch3DGallery).mockResolvedValue({
|
||||
items: [match3dCard],
|
||||
});
|
||||
vi.mocked(getMatch3DWorkDetail).mockResolvedValue({
|
||||
item: match3dCard,
|
||||
});
|
||||
match3dServerRuntimeAdapterMock.startRun.mockResolvedValue({
|
||||
run: buildMockMatch3DRun(match3dCard.profileId),
|
||||
});
|
||||
|
||||
render(<TestWrapper />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(match3dServerRuntimeAdapterMock.startRun).toHaveBeenCalledWith(
|
||||
'match3d-profile-card-guest',
|
||||
expect.objectContaining({
|
||||
runtimeGuestToken: 'runtime-guest-token',
|
||||
skipRefresh: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
expect(getMatch3DWorkDetail).not.toHaveBeenCalledWith(
|
||||
'match3d-profile-card-guest',
|
||||
);
|
||||
});
|
||||
|
||||
test('home recommendation Match3D runtime keeps image, music and UI assets without requiring models', async () => {
|
||||
const match3dCard: Match3DWorkSummary = {
|
||||
workId: 'match3d-work-card-image-only',
|
||||
@@ -9357,6 +9512,7 @@ test('formal puzzle runtime uses frontend move merge logic and backend leaderboa
|
||||
elapsedMs: 18_000,
|
||||
nickname: '测试玩家',
|
||||
},
|
||||
LOGGED_IN_RECOMMEND_RUNTIME_AUTH_OPTIONS,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -9377,6 +9533,7 @@ test('formal puzzle runtime uses frontend move merge logic and backend leaderboa
|
||||
expect(advancePuzzleNextLevel).toHaveBeenCalledWith(
|
||||
clearedFirstLevel.runId,
|
||||
{},
|
||||
LOGGED_IN_RECOMMEND_RUNTIME_AUTH_OPTIONS,
|
||||
);
|
||||
});
|
||||
expect(
|
||||
@@ -9539,6 +9696,7 @@ test('formal puzzle similar work keeps current run level progression', async ()
|
||||
expect(advancePuzzleNextLevel).toHaveBeenCalledWith(
|
||||
clearedThirdLevel.runId,
|
||||
{ targetProfileId: 'puzzle-profile-similar-2' },
|
||||
LOGGED_IN_RECOMMEND_RUNTIME_AUTH_OPTIONS,
|
||||
);
|
||||
});
|
||||
expect(startPuzzleRun).not.toHaveBeenCalled();
|
||||
|
||||
Reference in New Issue
Block a user