fix(tests): assert against rendered lastDetail panel instead of nc.log in horde combat tests

The old assertions targeted nc.log, which the component never renders.
Updated to assert against the rendered lastDetail panel, and use fake
timers to handle the setTimeout-deferred turn advancement.
This commit is contained in:
2026-07-16 06:53:52 +02:00
parent 33342d1611
commit b36b720c30
2 changed files with 72 additions and 17 deletions

View File

@@ -1,8 +1,8 @@
import React from 'react';
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import DeathwatchRoller from '../components/DeathwatchRoller';
jest.setTimeout(20000);
jest.setTimeout(30000);
const mockPlayers = [
{
@@ -68,20 +68,41 @@ function mockFetch(url) {
return Promise.resolve({ ok: false, status: 404, json: () => Promise.resolve({}) });
}
function makeRandomSequence() {
const seq = [];
// startCombat: 4 player init dice + 1 enemy init die
seq.push(0.89, 0.69, 0.49, 0.29, 0.09);
// Roll 1: Alpha attacks (d100 + 2d10 + uid)
seq.push(0.30, 0.50, 0.50, 0.50);
// Roll 2: Bravo attacks (d100 + 2d10 + uid)
seq.push(0.40, 0.50, 0.50, 0.50);
// Roll 3: Charlie attacks (d100 + 1d10 + uid)
seq.push(0.50, 0.50, 0.50);
// Roll 4: Delta attacks (d100 + 1d10 + uid)
seq.push(0.40, 0.50, 0.50);
// Roll 5: Horde attacks (d100 reaction + 1d10 damage + uid)
seq.push(0.60, 0.50, 0.50);
// Pad
for (let i = seq.length; i < 100; i++) seq.push(0.50);
return seq;
}
describe('DeathwatchRoller horde combat', () => {
beforeEach(() => {
localStorage.clear();
fetch.mockImplementation(mockFetch);
jest.useFakeTimers();
});
afterEach(() => {
cleanup();
jest.useRealTimers();
jest.restoreAllMocks();
});
test('runs 4 players against 5 horde setups with working roll progression', async () => {
for (const horde of mockHordes) {
const randomValues = [0.8, 0.6, 0.4, 0.2, 0.0];
const randomValues = makeRandomSequence();
jest.spyOn(Math, 'random').mockImplementation(() => (randomValues.length ? randomValues.shift() : 0.5));
const { unmount } = render(<DeathwatchRoller authedPlayer="gm" />);
@@ -104,24 +125,44 @@ describe('DeathwatchRoller horde combat', () => {
await waitFor(() => expect(screen.getByText(`Horde Combat: ${horde.name}`)).toBeInTheDocument());
expect(screen.getAllByText(/Round 1/).length).toBeGreaterThan(0);
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
// Roll 1: Alpha attacks (highest initiative), then advances to Bravo
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
jest.runAllTimers();
});
await waitFor(() => expect(screen.getAllByText(/Bravo's turn/i).length).toBeGreaterThan(0));
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
// Roll 2: Bravo attacks, then advances to Charlie
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
jest.runAllTimers();
});
await waitFor(() => expect(screen.getAllByText(/Charlie's turn/i).length).toBeGreaterThan(0));
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
// Roll 3: Charlie attacks, then advances to Delta
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
jest.runAllTimers();
});
await waitFor(() => expect(screen.getAllByText(/Delta's turn/i).length).toBeGreaterThan(0));
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
// Roll 4: Delta attacks, then advances to horde's turn
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
jest.runAllTimers();
});
await waitFor(() => expect(screen.getAllByText(new RegExp(`${horde.name}'s turn`, 'i')).length).toBeGreaterThan(0));
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
// Roll 5: Horde attacks, then advances back to Alpha (Round 2)
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
jest.runAllTimers();
});
await waitFor(() => expect(screen.getAllByText(/Alpha's turn/i).length).toBeGreaterThan(0));
// Verify the roll history has accumulated entries from the combat
await waitFor(() => {
expect(screen.getAllByText(new RegExp(`Alpha attacks|Bravo attacks|Charlie attacks|Delta attacks`, 'i')).length).toBeGreaterThan(0);
expect(screen.getByText(new RegExp(`${horde.name} hits`, 'i'))).toBeInTheDocument();
expect(screen.getAllByText(/Bolter|Bolt Pistol|Plasma Gun|Chainsword/i).length).toBeGreaterThan(0);
});
unmount();
@@ -129,4 +170,4 @@ describe('DeathwatchRoller horde combat', () => {
fetch.mockImplementation(mockFetch);
}
});
});
});

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
import DeathwatchRoller from '../components/DeathwatchRoller';
const mockRoster = [
@@ -56,19 +56,31 @@ function mockFetch(url) {
return Promise.resolve({ ok: false, status: 404, json: () => Promise.resolve({}) });
}
function makeRandomSequence() {
const seq = [];
// startCombat: 2 player init dice + 1 enemy init die
seq.push(0.90, 0.70, 0.10);
// Roll 1: player1 attacks (d100 + damage dice + uid)
seq.push(0.30, 0.50, 0.50, 0.50);
for (let i = seq.length; i < 100; i++) seq.push(0.50);
return seq;
}
describe('DeathwatchRoller horde combat player main weapon handling', () => {
beforeEach(() => {
localStorage.clear();
fetch.mockImplementation(mockFetch);
jest.useFakeTimers();
});
afterEach(() => {
cleanup();
jest.useRealTimers();
jest.restoreAllMocks();
});
test('uses the player main weapon with sanitized damage and working roll progression', async () => {
const randomValues = [0.3, 0.2, 0.1, 0.0, 0.4, 0.5, 0.6];
const randomValues = makeRandomSequence();
jest.spyOn(Math, 'random').mockImplementation(() => (randomValues.length ? randomValues.shift() : 0.5));
render(<DeathwatchRoller authedPlayer="player1" />);
@@ -92,12 +104,14 @@ describe('DeathwatchRoller horde combat player main weapon handling', () => {
expect(screen.getByText('Thunder Hammer')).toBeInTheDocument();
expect(screen.getByText('2d10+8')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: 'Roll' }));
jest.runAllTimers();
});
await waitFor(() => {
expect(screen.getByText(/player1 attacks with Thunder Hammer/i)).toBeInTheDocument();
expect(screen.getByText(/vs 55 WS/i)).toBeInTheDocument();
expect(screen.getAllByText(/player2's turn/i).length).toBeGreaterThan(0);
expect(screen.getByText(/Attack \d+ vs \d+ (WS|BS)/i)).toBeInTheDocument();
});
});
});
});