101f595bac
Add userData players/teams, scene npcTokens with hex-inscribed sizing, session scale synced to presentation, and Playwright e2e coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
106 lines
4.1 KiB
TypeScript
106 lines
4.1 KiB
TypeScript
import { test, expect, stubOpenImageDialog, invokeInRenderer } from './fixtures/electron';
|
|
|
|
test.describe('Players library', () => {
|
|
test('CRUD: add player with progress overlay, ring color persists in store', async ({
|
|
electronApp,
|
|
editorWindow,
|
|
sampleImagePath,
|
|
}) => {
|
|
await stubOpenImageDialog(electronApp, sampleImagePath);
|
|
|
|
await editorWindow.getByTestId('players-header-btn').click();
|
|
await expect(editorWindow.getByTestId('players-modal')).toBeVisible();
|
|
|
|
await editorWindow.getByTestId('players-add').click();
|
|
await editorWindow.getByPlaceholder(/Имя игрока|Player name/i).fill('Ada Lovelace');
|
|
await editorWindow.getByTestId('players-choose-image').click();
|
|
await expect(editorWindow.getByTestId('player-token-preview')).toBeVisible();
|
|
|
|
const colorInput = editorWindow.locator('input[type="color"]').first();
|
|
await colorInput.fill('#224466');
|
|
|
|
await editorWindow.getByTestId('players-save').click();
|
|
// Progress overlay may flash quickly; assert it either appeared or save finished.
|
|
await expect
|
|
.poll(async () => editorWindow.locator('[data-testid^="player-row-"]').count(), {
|
|
timeout: 30_000,
|
|
})
|
|
.toBe(1);
|
|
|
|
const listed = await invokeInRenderer<{ players: Array<{ name: string; ringColor: string }> }>(
|
|
editorWindow,
|
|
'players.list',
|
|
{},
|
|
);
|
|
expect(listed.players).toHaveLength(1);
|
|
expect(listed.players[0]!.name).toBe('Ada Lovelace');
|
|
expect(listed.players[0]!.ringColor.toLowerCase()).toBe('#224466');
|
|
});
|
|
|
|
test('Teams: assign then delete team leaves player ungrouped; no subteam UI', async ({
|
|
electronApp,
|
|
editorWindow,
|
|
sampleImagePath,
|
|
}) => {
|
|
await stubOpenImageDialog(electronApp, sampleImagePath);
|
|
|
|
await editorWindow.getByTestId('players-header-btn').click();
|
|
const modal = editorWindow.getByTestId('players-modal');
|
|
await expect(modal).toBeVisible();
|
|
await expect(modal).not.toContainText(/подкоманд|sub-?team|parentId/i);
|
|
|
|
await editorWindow.getByTestId('players-add').click();
|
|
await editorWindow.getByPlaceholder(/Имя игрока|Player name/i).fill('Bob');
|
|
await editorWindow.getByTestId('players-choose-image').click();
|
|
await editorWindow.getByTestId('players-save').click();
|
|
await expect(editorWindow.locator('[data-testid^="player-row-"]')).toHaveCount(1, {
|
|
timeout: 30_000,
|
|
});
|
|
|
|
const dialogHandler = async (d: { message: () => string; accept: (text?: string) => Promise<void> }) => {
|
|
const msg = d.message();
|
|
if (/команд|team/i.test(msg) && /цвет|color/i.test(msg)) await d.accept('#ff0000');
|
|
else if (/цвет|color/i.test(msg)) await d.accept('#ff0000');
|
|
else await d.accept('Party');
|
|
};
|
|
editorWindow.on('dialog', dialogHandler);
|
|
await editorWindow.getByTestId('players-add-team').click();
|
|
// Allow prompts to settle
|
|
await editorWindow.waitForTimeout(500);
|
|
editorWindow.off('dialog', dialogHandler);
|
|
|
|
const state = await invokeInRenderer<{
|
|
players: Array<{ id: string; teamId: string | null }>;
|
|
teams: Array<{ id: string; name: string }>;
|
|
}>(editorWindow, 'players.list', {});
|
|
|
|
// If UI prompts failed (headless), create team via IPC.
|
|
let team = state.teams.find((t) => t.name === 'Party');
|
|
if (!team) {
|
|
const created = await invokeInRenderer<{ team: { id: string; name: string } }>(
|
|
editorWindow,
|
|
'players.upsertTeam',
|
|
{ name: 'Party', color: '#ff0000' },
|
|
);
|
|
team = created.team;
|
|
}
|
|
const player = state.players[0]!;
|
|
expect(team).toBeTruthy();
|
|
|
|
await invokeInRenderer(editorWindow, 'players.assignTeam', {
|
|
playerId: player.id,
|
|
teamId: team!.id,
|
|
});
|
|
let mid = await invokeInRenderer<{ players: Array<{ teamId: string | null }> }>(
|
|
editorWindow,
|
|
'players.list',
|
|
{},
|
|
);
|
|
expect(mid.players[0]!.teamId).toBe(team!.id);
|
|
|
|
await invokeInRenderer(editorWindow, 'players.deleteTeam', { id: team!.id });
|
|
mid = await invokeInRenderer(editorWindow, 'players.list', {});
|
|
expect(mid.players[0]!.teamId).toBeNull();
|
|
});
|
|
});
|