Files
core2026/app/game-api/test/router.test.ts
T
Hide_D 1688ca0d23 feat: implement game API with TRPC and Redis transport
- Added GameApiConfig interface and configuration resolver from environment variables.
- Created GameApiContext for managing database and transport dependencies.
- Implemented InMemoryTurnDaemonTransport for testing purposes.
- Developed RedisTurnDaemonTransport for command and status handling via Redis streams.
- Defined TurnDaemonStreamKeys for namespacing Redis streams by profile.
- Established TRPC router with endpoints for health check, world state retrieval, and turn daemon commands (run, pause, resume, status).
- Integrated Fastify server with TRPC and Redis transport.
- Added unit tests for router functionality and stream key generation.
- Configured Vitest for testing environment.
2025-12-30 01:04:52 +00:00

76 lines
2.4 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import type { GameApiContext, GameProfile, WorldStateRow } from '../src/context.js';
import { InMemoryTurnDaemonTransport } from '../src/daemon/inMemoryTransport.js';
import { appRouter } from '../src/router.js';
const profile: GameProfile = {
id: 'che',
scenario: 'default',
name: 'che:default',
};
const buildContext = (options?: {
state?: WorldStateRow | null;
transport?: InMemoryTurnDaemonTransport;
}): GameApiContext => {
const transport = options?.transport ?? new InMemoryTurnDaemonTransport();
const db = {
worldState: {
findFirst: async () => options?.state ?? null,
},
};
return {
db,
turnDaemon: transport,
profile,
};
};
describe('appRouter', () => {
it('queues turn daemon run commands', async () => {
const transport = new InMemoryTurnDaemonTransport();
const caller = appRouter.createCaller(buildContext({ transport }));
const response = await caller.turnDaemon.run({ reason: 'manual' });
expect(response.accepted).toBe(true);
expect(transport.commands).toHaveLength(1);
expect(transport.commands[0]?.command.type).toBe('run');
expect(transport.commands[0]?.requestId).toBe(response.requestId);
});
it('returns world state snapshots', async () => {
const state: WorldStateRow = {
scenarioCode: 'default',
currentYear: 1,
currentMonth: 2,
tickSeconds: 600,
config: { seed: 123 },
meta: { label: 'sample' },
updatedAt: new Date('2026-01-01T00:00:00Z'),
};
const caller = appRouter.createCaller(buildContext({ state }));
const response = await caller.world.getState();
expect(response?.scenarioCode).toBe('default');
expect(response?.currentYear).toBe(1);
expect(response?.updatedAt).toBe('2026-01-01T00:00:00.000Z');
});
it('returns status from transport', async () => {
const transport = new InMemoryTurnDaemonTransport({
state: 'paused',
running: false,
paused: true,
queueDepth: 2,
});
const caller = appRouter.createCaller(buildContext({ transport }));
const response = await caller.turnDaemon.status();
expect(response?.state).toBe('paused');
expect(response?.queueDepth).toBe(2);
});
});