Skip to content

Commit

Permalink
Replace log tests with hook tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nukeop committed Jun 30, 2024
1 parent a402a13 commit b5aea64
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 121 deletions.
102 changes: 0 additions & 102 deletions src/game/GameLog.test.ts

This file was deleted.

177 changes: 175 additions & 2 deletions src/game/providers/GameLogProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,33 @@ import {
useGameLog,
} from './GameLogProvider';
import React, { ReactNode, act } from 'react';
import { Team } from '../Player';
import { Player, Team } from '../Player';
import { renderHook, waitFor } from '../../test-utils';

const wrapper: React.FC<{ children: ReactNode }> = ({ children }) => (
<GameLogProvider>{children}</GameLogProvider>
);

describe('Game log provider', () => {
it('should store logs', async () => {
it('adds system messages', async () => {
const { result } = renderHook(() => useGameLog(), { wrapper });
await waitFor(() => expect(result.current).toBeDefined());

await act(async () => {
result.current.addSystemMessage('Hello, world!');
});
await waitFor(() =>
expect(result.current.messages).toEqual([
{
content: 'Hello, world!',
type: MessageType.System,
},
]),
);
});

it('adds player messages', async () => {
const { result } = renderHook(() => useGameLog(), { wrapper });
await waitFor(() => expect(result.current).toBeDefined());

await act(async () => {
Expand All @@ -38,4 +54,161 @@ describe('Game log provider', () => {
]),
);
});

it('formats the log for game end', async () => {
const { result } = renderHook(() => useGameLog(), { wrapper });
await waitFor(() => expect(result.current).toBeDefined());

await act(async () => {
result.current.addSystemMessage(
'All messages are visible to all players at the end of the game',
);
result.current.addPlayerAction(
{ name: 'Mr. Test', team: Team.Machines },
'Hello, world!',
ActionType.Speech,
);
result.current.addPlayerAction(
{ name: 'Mr. Test', team: Team.Machines },
'This is what I think',
ActionType.Thought,
);
result.current.addPlayerAction(
{ name: 'Mr. Test 2', team: Team.Machines },
'I too am a player',
ActionType.Speech,
);
result.current.addPlayerAction(
{ name: 'Mr. Test 2', team: Team.Machines },
'And I think this',
ActionType.Thought,
);
result.current.addPlayerAction(
{ name: 'Mr. Human', team: Team.Machines },
'I am a human!',
ActionType.Speech,
);
result.current.addAnnouncerMessage(
'Announcements are visible to all players',
);
});

await waitFor(() =>
expect(result.current.formatLogForGameEnd()).toEqual(
'[System]: All messages are visible to all players at the end of the game\n[Mr. Test](Speech): Hello, world!\n[Mr. Test](Thought): This is what I think\n[Mr. Test 2](Speech): I too am a player\n[Mr. Test 2](Thought): And I think this\n[Mr. Human](Speech): I am a human!\n[Announcer]: Announcements are visible to all players',
),
);
});

it('formats the log for LLM API', async () => {
const { result } = renderHook(() => useGameLog(), { wrapper });
await waitFor(() => expect(result.current).toBeDefined());
const player = new Player('Mr. Test', Team.Machines);

await act(async () => {
result.current.addSystemMessage('This message will be ignored');
result.current.addPlayerAction(
player,
'Hello, world!',
ActionType.Speech,
'speech-1',
);
result.current.addPlayerAction(
player,
'Thoughts are only visible to the player who thought them',
ActionType.Thought,
'thought-1',
);
result.current.addPlayerAction(
{ name: 'Mr. Test 2', team: Team.Machines },
'I too am a player',
ActionType.Speech,
'speech-2',
);
result.current.addSystemMessage('This message will also be ignored');
result.current.addPlayerAction(
{ name: 'Mr. Test 2', team: Team.Machines },
'This thought will not be visible',
ActionType.Thought,
'thought-2',
);
result.current.addPlayerAction(
player,
'Hello again!',
ActionType.Speech,
'speech-3',
);
result.current.addAnnouncerMessage(
'Announcements are visible to all players',
);
});

await waitFor(() => expect(result.current.messages).toHaveLength(8));

expect(result.current.formatLogForLLM(player)).toEqual([
{
role: 'assistant',
tool_calls: [
{
id: 'speech-1',
type: 'function',
function: {
name: ActionType.Speech,
arguments: '{"content":"Hello, world!"}',
},
},
],
},
{
tool_call_id: 'speech-1',
role: 'tool',
content: 'Success',
},
{
role: 'assistant',
tool_calls: [
{
id: 'thought-1',
type: 'function',
function: {
name: ActionType.Thought,
arguments:
'{"content":"Thoughts are only visible to the player who thought them"}',
},
},
],
},
{
tool_call_id: 'thought-1',
role: 'tool',
content: 'Success',
},
{
role: 'user',
content: '[Mr. Test 2]: I too am a player',
},
{
role: 'assistant',
tool_calls: [
{
id: 'speech-3',
type: 'function',
function: {
name: ActionType.Speech,
arguments: '{"content":"Hello again!"}',
},
},
],
},
{
tool_call_id: 'speech-3',
role: 'tool',
content: 'Success',
},
{
role: 'user',
content: '[Announcer}: Announcements are visible to all players',
},
]);
});
});
19 changes: 2 additions & 17 deletions src/game/providers/GameStateProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { act, useEffect } from 'react';
import { GameStateProvider, useGameState } from './GameStateProvider';
import { Player, Team } from '../Player';
import { openAiMock, renderHook, waitFor } from '../../test-utils';
import { GameLogProvider } from './GameLogProvider';
import { ActionType, GameLogProvider } from './GameLogProvider';
import { fill } from 'lodash';

jest.mock('openai');
Expand Down Expand Up @@ -54,22 +54,7 @@ describe('GameStateProvider', () => {

it('allows advancing game state', async () => {
const { result } = renderHook(() => useGameState(), { wrapper });
openAiMock.setResponses([
{
content: '',
role: 'assistant',
tool_calls: [
{
id: '1',
type: 'function',
function: {
name: 'end_turn',
arguments: '{}',
},
},
],
},
]);
openAiMock.addToolUse(ActionType.EndTurn);
await waitFor(() => expect(result.current).toBeDefined());

expect(result.current.actingPlayer).toEqual(
Expand Down
18 changes: 18 additions & 0 deletions src/test-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { render } from 'ink-testing-library';
import { ChatCompletionMessage } from 'openai/resources';
import React, { useEffect } from 'react';
import { act } from 'react';
import { ActionType } from './game/providers/GameLogProvider';

type Hook<T> = () => T;

Expand Down Expand Up @@ -91,6 +92,23 @@ class OpenAiMock {
this.responses = responses;
}

addToolUse(name: ActionType, args?: string) {
this.responses.push({
content: '',
role: 'assistant',
tool_calls: [
{
id: '1',
type: 'function',
function: {
name,
arguments: args ?? '{}',
},
},
],
});
}

getMockImplementation() {
return {
chat: {
Expand Down

0 comments on commit b5aea64

Please sign in to comment.