import { expect, test } from '@playwright/test'; import { fetchFleetSecret, loginToDashboard } from './fixtures'; import { connectStubAgent, E2E_STUB_AGENT_HOSTNAME, E2E_STUB_LOTL_BADGE, E2E_WHOAMI_RESPONSE, } from './stub-agent'; const baseURL = process.env.AETHERFORGE_URL || 'http://127.0.0.1:8989'; let serverReady = false; let disconnectStub: (() => void) | null = null; test.describe('Crucible remote command', () => { test.beforeAll(async ({ request }) => { try { const res = await request.get('/api/v1/health'); serverReady = res.ok(); } catch { serverReady = false; } if (!serverReady) return; const fleetSecret = await fetchFleetSecret(request); disconnectStub = await connectStubAgent(baseURL, fleetSecret); // Allow agent_online, stats_batch (250ms coalesce), and DB upsert to settle. await new Promise((r) => setTimeout(r, 1_500)); }); test.afterAll(() => { disconnectStub?.(); disconnectStub = null; }); test.beforeEach(async ({ page }) => { test.skip( !serverReady, 'Requires live E2E server (test-suite phase 8 on :18989 or AETHERFORGE_URL)', ); await loginToDashboard(page); await page.getByRole('link', { name: /Crucible/i }).click(); await expect(page.getByRole('heading', { name: 'Crucible' })).toBeVisible({ timeout: 10_000 }); await expect(page.getByText(E2E_STUB_AGENT_HOSTNAME)).toBeVisible({ timeout: 15_000 }); }); test('whoami on selected online node shows terminal output', async ({ page }) => { await page.getByText(E2E_STUB_AGENT_HOSTNAME).click(); await expect(page.getByText(new RegExp(`→ 1 node.*${E2E_STUB_AGENT_HOSTNAME}`))).toBeVisible(); await page.getByRole('button', { name: 'whoami' }).click(); const terminal = page.locator('.crucible-terminal'); await expect(terminal.getByText('whoami', { exact: true })).toBeVisible({ timeout: 10_000 }); await expect(terminal.getByText(E2E_WHOAMI_RESPONSE)).toBeVisible({ timeout: 15_000 }); }); test('shows LOTL tier badge when stub sends lotl_tier', async ({ page }) => { const card = page.locator('.crucible-node-card').filter({ hasText: E2E_STUB_AGENT_HOSTNAME }); await expect(card.getByText(E2E_STUB_LOTL_BADGE)).toBeVisible({ timeout: 15_000 }); }); test('exec echo via master terminal shows output', async ({ page }) => { await page.getByText(E2E_STUB_AGENT_HOSTNAME).click(); await page.getByRole('button', { name: 'CMD', exact: true }).click(); const input = page.locator('.crucible-term-input'); await expect(input).toBeEnabled(); await input.fill('echo crucible-e2e-ping'); await page.getByRole('button', { name: 'SEND' }).click(); const terminal = page.locator('.crucible-terminal'); await expect(terminal.getByText('echo crucible-e2e-ping')).toBeVisible({ timeout: 10_000 }); await expect(terminal.getByText('crucible-e2e-ping')).toBeVisible({ timeout: 15_000 }); }); });