Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Restore P1/P2/fleet/erasure COVERED rows in PROBLEMS.md with refreshed counts; drop fixed poll-duplication and Vitest-noise items. Silence ECONNREFUSED stderr in Vitest setup, alias download mock exports, and expand erasure/Path Tracer test coverage.
112 lines
4.5 KiB
TypeScript
112 lines
4.5 KiB
TypeScript
/**
|
|
* @vitest-environment happy-dom
|
|
*/
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { cleanup, render, screen, waitFor } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { MemoryRouter } from 'react-router-dom';
|
|
import MissionDeckPage from './MissionDeckPage';
|
|
import { ForgeProvider } from '../context/ForgeContext';
|
|
import { routerFuture } from '../routerFuture';
|
|
import { mockServerConfig, mockServerInfo } from '../test/fixtures';
|
|
import { api } from '../api/client';
|
|
|
|
vi.mock('../context/PresenceContext', () => ({
|
|
usePresence: () => ({
|
|
othersOnPage: [],
|
|
comrades: [],
|
|
comradesHere: () => [],
|
|
othersOnline: false,
|
|
}),
|
|
}));
|
|
|
|
function renderMissionDeck() {
|
|
return render(
|
|
<MemoryRouter initialEntries={['/mission-deck']} future={routerFuture}>
|
|
<ForgeProvider>
|
|
<MissionDeckPage />
|
|
</ForgeProvider>
|
|
</MemoryRouter>,
|
|
);
|
|
}
|
|
|
|
describe('MissionDeckPage', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
localStorage.clear();
|
|
vi.spyOn(api, 'getConfig').mockResolvedValue(mockServerConfig());
|
|
vi.spyOn(api, 'getServerInfo').mockResolvedValue(mockServerInfo);
|
|
vi.spyOn(api, 'listBuilds').mockResolvedValue([]);
|
|
vi.spyOn(api, 'buildAgent').mockResolvedValue({
|
|
success: true,
|
|
build_id: 'deck-build-1',
|
|
file_name: 'worker-deck.exe',
|
|
file_size: 4096,
|
|
download_url: '/api/v1/builds/deck-build-1/download',
|
|
});
|
|
vi.spyOn(api, 'exportSpreadKit').mockResolvedValue(undefined);
|
|
vi.stubGlobal('navigator', {
|
|
clipboard: { writeText: vi.fn().mockResolvedValue(undefined) },
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
cleanup();
|
|
});
|
|
|
|
it('shows loading state then mission deck hero', async () => {
|
|
renderMissionDeck();
|
|
expect(screen.getByText(/Loading loadout defaults/)).toBeInTheDocument();
|
|
expect(await screen.findByRole('heading', { level: 1, name: /Mission Deck/i })).toBeInTheDocument();
|
|
expect(screen.getByText('FAST PATH')).toBeInTheDocument();
|
|
expect(await screen.findByText(/Pick a preset loadout/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders Ghost / Loud / Spread mode chips in loadout layout', async () => {
|
|
renderMissionDeck();
|
|
await screen.findByRole('region', { name: 'Mission loadout' });
|
|
expect(screen.getByRole('region', { name: 'Mission loadout' })).toBeInTheDocument();
|
|
const loadout = screen.getByRole('region', { name: 'Mission loadout' });
|
|
expect(loadout).toHaveTextContent('Ghost');
|
|
expect(loadout).toHaveTextContent('Loud');
|
|
expect(loadout).toHaveTextContent('Spread');
|
|
expect(screen.getByRole('heading', { level: 2, name: /Ghost|Loud|Spread/ })).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows spread profile chips and campaign slug on the right panel', async () => {
|
|
renderMissionDeck();
|
|
await screen.findByRole('region', { name: 'Mission loadout' });
|
|
expect(screen.getByRole('heading', { level: 3, name: /Spread profile/i })).toBeInTheDocument();
|
|
expect(screen.getByRole('button', { name: 'LAN Kindling' })).toBeInTheDocument();
|
|
expect(document.getElementById('md-campaign')).toBeInTheDocument();
|
|
});
|
|
|
|
it('links to Forge, Emberwake, Builds, and field guide', async () => {
|
|
renderMissionDeck();
|
|
await screen.findByRole('region', { name: 'Mission loadout' });
|
|
expect(screen.getAllByRole('link', { name: /^Forge$/i }).length).toBeGreaterThan(0);
|
|
expect(screen.getAllByRole('link', { name: /^Emberwake$/i }).length).toBeGreaterThan(0);
|
|
expect(screen.getAllByRole('link', { name: /^Builds$/i }).length).toBeGreaterThan(0);
|
|
expect(screen.getByRole('link', { name: /Field guide/i })).toHaveAttribute('href', '/docs/#mission-deck');
|
|
expect(screen.getByRole('link', { name: /Full Forge/i })).toHaveAttribute('href', '/forge');
|
|
});
|
|
|
|
it('equips and strikes using runForgeMission pipeline', async () => {
|
|
const user = userEvent.setup();
|
|
const buildSpy = vi.spyOn(api, 'buildAgent');
|
|
const exportSpy = vi.spyOn(api, 'exportSpreadKit');
|
|
renderMissionDeck();
|
|
await screen.findByRole('region', { name: 'Mission loadout' });
|
|
await user.click(screen.getByRole('button', { name: 'LAN Kindling' }));
|
|
await user.click(screen.getByRole('button', { name: /Equip & Strike/i }));
|
|
await waitFor(() => {
|
|
expect(buildSpy).toHaveBeenCalled();
|
|
});
|
|
expect(exportSpy).toHaveBeenCalled();
|
|
expect(await screen.findByText(/Forge complete/i)).toBeInTheDocument();
|
|
expect(screen.getByRole('link', { name: /View install commands in Builds/i })).toHaveAttribute('href', '/builds');
|
|
});
|
|
});
|
|
|