import { beforeEach, describe, expect, it, vi } from 'vitest'; const apiClientMocks = vi.hoisted(() => ({ requestJson: vi.fn(), })); vi.mock('./apiClient', async () => { const actual = await vi.importActual('./apiClient'); return { ...actual, requestJson: apiClientMocks.requestJson, }; }); import { startBigFishRun } from './big-fish-runtime/bigFishRuntimeClient'; import { startBarkBattleRun } from './bark-battle-runtime/barkBattleRuntimeClient'; import { startJumpHopRuntimeRun } from './jump-hop/jumpHopClient'; import { startMatch3DRun } from './match3d-runtime/match3dRuntimeClient'; import { advancePuzzleNextLevel, startPuzzleRun, submitPuzzleLeaderboard, } from './puzzle-runtime/puzzleRuntimeClient'; import { startSquareHoleRun } from './square-hole-runtime/squareHoleRuntimeClient'; import { startVisualNovelRun } from './visual-novel-runtime/visualNovelRuntimeClient'; describe('recommended runtime guest launch clients', () => { beforeEach(() => { vi.clearAllMocks(); apiClientMocks.requestJson.mockResolvedValue({ run: {} }); }); it.each([ { name: 'jump-hop', start: () => startJumpHopRuntimeRun('jump-hop-profile-1', { runtimeGuestToken: 'runtime-guest-token', }), expectedUrl: '/api/runtime/jump-hop/runs', }, { name: 'visual-novel', start: () => startVisualNovelRun( 'visual-novel-profile-1', { profileId: 'visual-novel-profile-1', mode: 'play' }, { runtimeGuestToken: 'runtime-guest-token' }, ), expectedUrl: '/api/runtime/visual-novel/works/visual-novel-profile-1/runs', }, { name: 'match3d', start: () => startMatch3DRun('match3d-profile-1', { runtimeGuestToken: 'runtime-guest-token', }), expectedUrl: '/api/runtime/match3d/works/match3d-profile-1/runs', }, { name: 'square-hole', start: () => startSquareHoleRun('square-hole-profile-1', { runtimeGuestToken: 'runtime-guest-token', }), expectedUrl: '/api/runtime/square-hole/works/square-hole-profile-1/runs', }, { name: 'big-fish', start: () => startBigFishRun('big-fish-session-1', { runtimeGuestToken: 'runtime-guest-token', }), expectedUrl: '/api/runtime/big-fish/sessions/big-fish-session-1/runs', }, { name: 'bark-battle', start: () => startBarkBattleRun('bark-battle-work-1', {}, { runtimeGuestToken: 'runtime-guest-token', }), expectedUrl: '/api/runtime/bark-battle/works/bark-battle-work-1/runs', }, { name: 'puzzle', start: () => startPuzzleRun( { profileId: 'puzzle-profile-1', levelId: 'level-1' }, { runtimeGuestToken: 'runtime-guest-token' }, ), expectedUrl: '/api/runtime/puzzle/runs', }, { name: 'puzzle leaderboard', start: () => submitPuzzleLeaderboard( 'run-puzzle-1', { profileId: 'puzzle-profile-1', gridSize: 3, elapsedMs: 18_000, nickname: '玩家', }, { runtimeGuestToken: 'runtime-guest-token' }, ), expectedUrl: '/api/runtime/puzzle/runs/run-puzzle-1/leaderboard', }, ])( '$name start request uses the runtime guest bearer token without touching login auth', async ({ start, expectedUrl }) => { await start(); const [url, init, , options] = apiClientMocks.requestJson.mock.calls[0]; expect(url).toBe(expectedUrl); expect(init).toEqual( expect.objectContaining({ method: 'POST', headers: expect.objectContaining({ Authorization: 'Bearer runtime-guest-token', }), }), ); expect(options).toEqual( expect.objectContaining({ skipAuth: true, skipRefresh: true, }), ); }, ); it('puzzle next level can carry preferSimilarWork through the runtime guest request', async () => { await advancePuzzleNextLevel( 'run-puzzle-1', { preferSimilarWork: true }, { runtimeGuestToken: 'runtime-guest-token' }, ); const [url, init, , options] = apiClientMocks.requestJson.mock.calls[0]; expect(url).toBe('/api/runtime/puzzle/runs/run-puzzle-1/next-level'); expect(init).toEqual( expect.objectContaining({ method: 'POST', headers: expect.objectContaining({ Authorization: 'Bearer runtime-guest-token', 'Content-Type': 'application/json', }), body: JSON.stringify({ preferSimilarWork: true }), }), ); expect(options).toEqual( expect.objectContaining({ skipAuth: true, skipRefresh: true, }), ); }); it('puzzle leaderboard submission does not retry unsafe writes', async () => { await submitPuzzleLeaderboard( 'run-puzzle-1', { profileId: 'puzzle-profile-1', gridSize: 3, elapsedMs: 18_000, nickname: '玩家', }, { runtimeGuestToken: 'runtime-guest-token' }, ); const [url, init, , options] = apiClientMocks.requestJson.mock.calls[0]; expect(url).toBe('/api/runtime/puzzle/runs/run-puzzle-1/leaderboard'); expect(init).toEqual( expect.objectContaining({ method: 'POST', headers: expect.objectContaining({ Authorization: 'Bearer runtime-guest-token', 'Content-Type': 'application/json', }), }), ); expect(options).toEqual( expect.objectContaining({ retry: expect.objectContaining({ maxRetries: 0, }), }), ); }); });