7dd53e95d8
统一推荐页各玩法正式 runtime 的游客鉴权透传。 收口推荐页首页展示队列和嵌入运行态切换队列。 补齐未登录读档、签名资产和个人数据读取的游客态处理。 新增运行态 HUD 小尺寸 logo 资源并更新拼图与抓鹅展示。 补充推荐切换、runtime guest 启动和客户端请求回归测试。 更新玩法链路、后端契约和团队记忆文档。
95 lines
2.4 KiB
TypeScript
95 lines
2.4 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
const apiClientMocks = vi.hoisted(() => ({
|
|
requestJson: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('../apiClient', async () => {
|
|
const actual =
|
|
await vi.importActual<typeof import('../apiClient')>('../apiClient');
|
|
return {
|
|
...actual,
|
|
requestJson: apiClientMocks.requestJson,
|
|
};
|
|
});
|
|
|
|
import {
|
|
getPuzzleRun,
|
|
swapPuzzlePieces,
|
|
updatePuzzleRunPause,
|
|
} from './puzzleRuntimeClient';
|
|
|
|
describe('puzzleRuntimeClient', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
apiClientMocks.requestJson.mockResolvedValue({ runId: 'run-1' });
|
|
});
|
|
|
|
it('reads runs through the shared encoded runtime path', async () => {
|
|
await getPuzzleRun('run/1');
|
|
|
|
expect(apiClientMocks.requestJson).toHaveBeenCalledWith(
|
|
'/api/runtime/puzzle/runs/run%2F1',
|
|
{ method: 'GET' },
|
|
'读取拼图运行快照失败',
|
|
expect.objectContaining({
|
|
retry: expect.objectContaining({ maxRetries: 1 }),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('submits puzzle swaps through the shared json request skeleton', async () => {
|
|
await swapPuzzlePieces('run/1', {
|
|
firstPieceId: 'piece-a',
|
|
secondPieceId: 'piece-b',
|
|
});
|
|
|
|
expect(apiClientMocks.requestJson).toHaveBeenCalledWith(
|
|
'/api/runtime/puzzle/runs/run%2F1/swap',
|
|
expect.objectContaining({
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
firstPieceId: 'piece-a',
|
|
secondPieceId: 'piece-b',
|
|
}),
|
|
}),
|
|
'交换拼图块失败',
|
|
expect.objectContaining({
|
|
retry: expect.objectContaining({ retryUnsafeMethods: true }),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('uses runtime guest auth for pause requests when provided', async () => {
|
|
await updatePuzzleRunPause(
|
|
'run/1',
|
|
{ paused: true },
|
|
{
|
|
authImpact: 'local',
|
|
runtimeGuestToken: 'runtime-guest-token',
|
|
skipRefresh: true,
|
|
},
|
|
);
|
|
|
|
const [, init, , options] = apiClientMocks.requestJson.mock.calls[0];
|
|
expect(init).toEqual(
|
|
expect.objectContaining({
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Authorization: 'Bearer runtime-guest-token',
|
|
},
|
|
body: JSON.stringify({ paused: true }),
|
|
}),
|
|
);
|
|
expect(options).toEqual(
|
|
expect.objectContaining({
|
|
authImpact: 'local',
|
|
skipAuth: true,
|
|
skipRefresh: true,
|
|
}),
|
|
);
|
|
});
|
|
});
|