boardgame-core/tests/core/game.test.ts

127 lines
4.4 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { createGameContext, createGameCommand } from '../../src/core/game';
import { createCommandRegistry, parseCommandSchema, type CommandRegistry } from '../../src/utils/command';
import type { IGameContext } from '../../src/core/game';
describe('createGameContext', () => {
it('should create a game context with empty parts and regions', () => {
const registry = createCommandRegistry<IGameContext>();
const ctx = createGameContext(registry);
expect(ctx.parts.collection.value).toEqual({});
expect(ctx.regions.collection.value).toEqual({});
});
it('should wire commands to the context', () => {
const registry = createCommandRegistry<IGameContext>();
const ctx = createGameContext(registry);
expect(ctx.commands).not.toBeNull();
expect(ctx.commands.registry).toBe(registry);
expect(ctx.commands.context).toBe(ctx);
});
it('should forward prompt events to the prompts queue', async () => {
const registry = createCommandRegistry<IGameContext>();
const ctx = createGameContext(registry);
const schema = parseCommandSchema('test <value>');
registry.set('test', {
schema,
run: async function () {
return this.prompt('prompt <answer>');
},
});
const runPromise = ctx.commands.run('test hello');
await new Promise((r) => setTimeout(r, 0));
const promptEvent = await ctx.prompts.pop();
expect(promptEvent).not.toBeNull();
expect(promptEvent.schema.name).toBe('prompt');
promptEvent.resolve({ name: 'prompt', params: ['yes'], options: {}, flags: {} });
const result = await runPromise;
expect(result.success).toBe(true);
if (result.success) {
expect((result.result as any).params[0]).toBe('yes');
}
});
});
describe('createGameCommand', () => {
it('should create a command from a string schema', () => {
const cmd = createGameCommand('test <a>', async function () {
return 1;
});
expect(cmd.schema.name).toBe('test');
expect(cmd.schema.params[0].name).toBe('a');
expect(cmd.schema.params[0].required).toBe(true);
});
it('should create a command from a CommandSchema object', () => {
const schema = parseCommandSchema('foo <x> [y]');
const cmd = createGameCommand(schema, async function () {
return 2;
});
expect(cmd.schema.name).toBe('foo');
expect(cmd.schema.params[0].name).toBe('x');
expect(cmd.schema.params[0].required).toBe(true);
expect(cmd.schema.params[1].name).toBe('y');
expect(cmd.schema.params[1].required).toBe(false);
});
it('should run a command with access to game context', async () => {
const registry = createCommandRegistry<IGameContext>();
const ctx = createGameContext(registry);
const addRegion = createGameCommand('add-region <id>', async function (cmd) {
const id = cmd.params[0] as string;
this.context.regions.add({ id, axes: [], children: [] });
return id;
});
registry.set('add-region', addRegion);
const result = await ctx.commands.run('add-region board');
expect(result.success).toBe(true);
if (result.success) {
expect(result.result).toBe('board');
}
expect(ctx.regions.get('board')).not.toBeNull();
});
it('should run a command that adds parts', async () => {
const registry = createCommandRegistry<IGameContext>();
const ctx = createGameContext(registry);
ctx.regions.add({ id: 'zone', axes: [], children: [] });
const addPart = createGameCommand('add-part <id>', async function (cmd) {
const id = cmd.params[0] as string;
const part = {
id,
sides: 1,
side: 0,
region: this.context.regions.get('zone'),
position: [0],
};
this.context.parts.add(part);
return id;
});
registry.set('add-part', addPart);
const result = await ctx.commands.run('add-part piece-1');
expect(result.success).toBe(true);
if (result.success) {
expect(result.result).toBe('piece-1');
}
expect(ctx.parts.get('piece-1')).not.toBeNull();
});
});