sprint/2-simulations #5
@@ -167,7 +167,7 @@ test.describe('US-11 — workflow transitions', () => {
|
|||||||
}) => {
|
}) => {
|
||||||
const rtClient = makeClient(redteamToken);
|
const rtClient = makeClient(redteamToken);
|
||||||
|
|
||||||
// pending → "Marquer en revue" visible for redteam; "Clôturer" hidden
|
// pending → "Mark for review" visible for redteam; "Close" hidden
|
||||||
const simPending = await createSimulation(
|
const simPending = await createSimulation(
|
||||||
redteamToken,
|
redteamToken,
|
||||||
engagementId,
|
engagementId,
|
||||||
@@ -175,34 +175,34 @@ test.describe('US-11 — workflow transitions', () => {
|
|||||||
);
|
);
|
||||||
await seedTokenInStorage(context, redteamToken);
|
await seedTokenInStorage(context, redteamToken);
|
||||||
await page.goto(`/engagements/${engagementId}/simulations/${simPending.id}/edit`);
|
await page.goto(`/engagements/${engagementId}/simulations/${simPending.id}/edit`);
|
||||||
await expect(page.getByRole('button', { name: /marquer en revue/i })).toBeVisible();
|
await expect(page.getByRole('button', { name: /mark for review/i })).toBeVisible();
|
||||||
await expect(page.getByRole('button', { name: /clôturer/i })).toHaveCount(0);
|
await expect(page.getByRole('button', { name: /^close$/i })).toHaveCount(0);
|
||||||
|
|
||||||
// in_progress → "Marquer en revue" visible
|
// in_progress → "Mark for review" visible
|
||||||
const simIP = await createSimulation(redteamToken, engagementId, 'AC-11.4 in_progress UI');
|
const simIP = await createSimulation(redteamToken, engagementId, 'AC-11.4 in_progress UI');
|
||||||
await rtClient.patch(`/simulations/${simIP.id}`, { name: 'trigger' });
|
await rtClient.patch(`/simulations/${simIP.id}`, { name: 'trigger' });
|
||||||
await page.goto(`/engagements/${engagementId}/simulations/${simIP.id}/edit`);
|
await page.goto(`/engagements/${engagementId}/simulations/${simIP.id}/edit`);
|
||||||
await expect(page.getByRole('button', { name: /marquer en revue/i })).toBeVisible();
|
await expect(page.getByRole('button', { name: /mark for review/i })).toBeVisible();
|
||||||
await expect(page.getByRole('button', { name: /clôturer/i })).toHaveCount(0);
|
await expect(page.getByRole('button', { name: /^close$/i })).toHaveCount(0);
|
||||||
|
|
||||||
// review_required → "Clôturer" visible for redteam; "Marquer en revue" hidden
|
// review_required → "Close" visible for redteam; "Mark for review" hidden
|
||||||
const simRR = await createSimulation(redteamToken, engagementId, 'AC-11.4 review UI');
|
const simRR = await createSimulation(redteamToken, engagementId, 'AC-11.4 review UI');
|
||||||
await rtClient.post(`/simulations/${simRR.id}/transition`, { to: 'review_required' });
|
await rtClient.post(`/simulations/${simRR.id}/transition`, { to: 'review_required' });
|
||||||
await page.goto(`/engagements/${engagementId}/simulations/${simRR.id}/edit`);
|
await page.goto(`/engagements/${engagementId}/simulations/${simRR.id}/edit`);
|
||||||
await expect(page.getByRole('button', { name: /clôturer/i })).toBeVisible();
|
await expect(page.getByRole('button', { name: /^close$/i })).toBeVisible();
|
||||||
await expect(page.getByRole('button', { name: /marquer en revue/i })).toHaveCount(0);
|
await expect(page.getByRole('button', { name: /mark for review/i })).toHaveCount(0);
|
||||||
|
|
||||||
// review_required → "Clôturer" also visible for SOC
|
// review_required → "Close" also visible for SOC
|
||||||
await seedTokenInStorage(context, socToken);
|
await seedTokenInStorage(context, socToken);
|
||||||
await page.goto(`/engagements/${engagementId}/simulations/${simRR.id}/edit`);
|
await page.goto(`/engagements/${engagementId}/simulations/${simRR.id}/edit`);
|
||||||
await expect(page.getByRole('button', { name: /clôturer/i })).toBeVisible();
|
await expect(page.getByRole('button', { name: /^close$/i })).toBeVisible();
|
||||||
|
|
||||||
// done → both buttons hidden
|
// done → both buttons hidden
|
||||||
await rtClient.post(`/simulations/${simRR.id}/transition`, { to: 'done' });
|
await rtClient.post(`/simulations/${simRR.id}/transition`, { to: 'done' });
|
||||||
await seedTokenInStorage(context, redteamToken);
|
await seedTokenInStorage(context, redteamToken);
|
||||||
await page.goto(`/engagements/${engagementId}/simulations/${simRR.id}/edit`);
|
await page.goto(`/engagements/${engagementId}/simulations/${simRR.id}/edit`);
|
||||||
await expect(page.getByRole('button', { name: /marquer en revue/i })).toHaveCount(0);
|
await expect(page.getByRole('button', { name: /mark for review/i })).toHaveCount(0);
|
||||||
await expect(page.getByRole('button', { name: /clôturer/i })).toHaveCount(0);
|
await expect(page.getByRole('button', { name: /^close$/i })).toHaveCount(0);
|
||||||
|
|
||||||
await deleteSimulation(redteamToken, simPending.id);
|
await deleteSimulation(redteamToken, simPending.id);
|
||||||
await deleteSimulation(redteamToken, simIP.id);
|
await deleteSimulation(redteamToken, simIP.id);
|
||||||
@@ -223,14 +223,14 @@ test.describe('US-11 — workflow transitions', () => {
|
|||||||
const badge = page.getByTestId('simulation-status-badge');
|
const badge = page.getByTestId('simulation-status-badge');
|
||||||
await expect(badge).toHaveAttribute('data-status', 'pending');
|
await expect(badge).toHaveAttribute('data-status', 'pending');
|
||||||
|
|
||||||
// Click "Marquer en revue"
|
// Click "Mark for review"
|
||||||
await page.getByRole('button', { name: /marquer en revue/i }).click();
|
await page.getByRole('button', { name: /mark for review/i }).click();
|
||||||
|
|
||||||
// Badge updates to review_required without page reload
|
// Badge updates to review_required without page reload
|
||||||
await expect(badge).toHaveAttribute('data-status', 'review_required', { timeout: 5_000 });
|
await expect(badge).toHaveAttribute('data-status', 'review_required', { timeout: 5_000 });
|
||||||
|
|
||||||
// "Clôturer" now visible; click it
|
// "Close" now visible; click it
|
||||||
await page.getByRole('button', { name: /clôturer/i }).click();
|
await page.getByRole('button', { name: /^close$/i }).click();
|
||||||
await expect(badge).toHaveAttribute('data-status', 'done', { timeout: 5_000 });
|
await expect(badge).toHaveAttribute('data-status', 'done', { timeout: 5_000 });
|
||||||
|
|
||||||
// Verify list is also updated: navigate to engagement detail and check badge there
|
// Verify list is also updated: navigate to engagement detail and check badge there
|
||||||
|
|||||||
@@ -123,26 +123,26 @@ test.describe('US-12 — simulation delete', () => {
|
|||||||
await page.goto(`/engagements/${engagementId}/simulations/${sim.id}/edit`);
|
await page.goto(`/engagements/${engagementId}/simulations/${sim.id}/edit`);
|
||||||
|
|
||||||
// Delete button is visible for redteam
|
// Delete button is visible for redteam
|
||||||
const deleteBtn = page.getByRole('button', { name: /supprimer/i });
|
const deleteBtn = page.getByRole('button', { name: /^delete$/i });
|
||||||
await expect(deleteBtn).toBeVisible();
|
await expect(deleteBtn).toBeVisible();
|
||||||
|
|
||||||
// SOC should NOT see delete button
|
// SOC should NOT see delete button
|
||||||
await seedTokenInStorage(context, socToken);
|
await seedTokenInStorage(context, socToken);
|
||||||
await page.goto(`/engagements/${engagementId}/simulations/${sim.id}/edit`);
|
await page.goto(`/engagements/${engagementId}/simulations/${sim.id}/edit`);
|
||||||
await expect(page.getByRole('button', { name: /supprimer/i })).toHaveCount(0);
|
await expect(page.getByRole('button', { name: /^delete$/i })).toHaveCount(0);
|
||||||
|
|
||||||
// Back to redteam — click delete, confirm modal appears
|
// Back to redteam — click delete, confirm modal appears
|
||||||
await seedTokenInStorage(context, redteamToken);
|
await seedTokenInStorage(context, redteamToken);
|
||||||
await page.goto(`/engagements/${engagementId}/simulations/${sim.id}/edit`);
|
await page.goto(`/engagements/${engagementId}/simulations/${sim.id}/edit`);
|
||||||
await page.getByRole('button', { name: /supprimer/i }).click();
|
await page.getByRole('button', { name: /^delete$/i }).click();
|
||||||
|
|
||||||
// Confirmation dialog must appear
|
// Confirmation dialog must appear
|
||||||
const dialog = page.getByRole('dialog');
|
const dialog = page.getByRole('dialog');
|
||||||
await expect(dialog).toBeVisible();
|
await expect(dialog).toBeVisible();
|
||||||
await expect(dialog.getByText(/supprimer la simulation/i)).toBeVisible();
|
await expect(dialog.getByText(/delete simulation/i)).toBeVisible();
|
||||||
|
|
||||||
// Confirm deletion
|
// Confirm deletion
|
||||||
await dialog.getByRole('button', { name: /supprimer/i }).click();
|
await dialog.getByRole('button', { name: /^delete$/i }).click();
|
||||||
|
|
||||||
// Should navigate back to engagement detail
|
// Should navigate back to engagement detail
|
||||||
await page.waitForURL(new RegExp(`/engagements/${engagementId}$`));
|
await page.waitForURL(new RegExp(`/engagements/${engagementId}$`));
|
||||||
|
|||||||
@@ -265,9 +265,9 @@ test.describe('US-4 — engagement CRUD', () => {
|
|||||||
await expect(page.getByRole('heading', { name: /AC-4.9 detail target/i })).toBeVisible();
|
await expect(page.getByRole('heading', { name: /AC-4.9 detail target/i })).toBeVisible();
|
||||||
// Sprint 2 replaced the placeholder with the real SimulationList — covered by AC-7.5.
|
// Sprint 2 replaced the placeholder with the real SimulationList — covered by AC-7.5.
|
||||||
await expect(page.getByRole('heading', { name: /simulations/i })).toBeVisible();
|
await expect(page.getByRole('heading', { name: /simulations/i })).toBeVisible();
|
||||||
// admin/redteam see the "Nouvelle simulation" button
|
// admin/redteam see the "New simulation" button
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('link', { name: /nouvelle simulation/i }),
|
page.getByRole('link', { name: /new simulation/i }),
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -156,15 +156,15 @@ test.describe('US-7 — simulation create', () => {
|
|||||||
// The created simulation row is visible
|
// The created simulation row is visible
|
||||||
await expect(page.getByRole('row', { name: /Visible sim/i })).toBeVisible();
|
await expect(page.getByRole('row', { name: /Visible sim/i })).toBeVisible();
|
||||||
|
|
||||||
// "Nouvelle simulation" button visible for redteam
|
// "New simulation" button visible for redteam
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('link', { name: /nouvelle simulation/i }),
|
page.getByRole('link', { name: /new simulation/i }),
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
|
|
||||||
// SOC should NOT see "Nouvelle simulation" button
|
// SOC should NOT see "New simulation" button
|
||||||
await seedTokenInStorage(context, socToken);
|
await seedTokenInStorage(context, socToken);
|
||||||
await page.goto(`/engagements/${engagementId}`);
|
await page.goto(`/engagements/${engagementId}`);
|
||||||
await expect(page.getByRole('link', { name: /nouvelle simulation/i })).toHaveCount(0);
|
await expect(page.getByRole('link', { name: /new simulation/i })).toHaveCount(0);
|
||||||
|
|
||||||
await deleteSimulation(redteamToken, sim.id);
|
await deleteSimulation(redteamToken, sim.id);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ test.describe('US-9 — SOC restricted edit', () => {
|
|||||||
// Banner must be visible
|
// Banner must be visible
|
||||||
await expect(page.getByTestId('soc-blocked-banner')).toBeVisible();
|
await expect(page.getByTestId('soc-blocked-banner')).toBeVisible();
|
||||||
await expect(
|
await expect(
|
||||||
page.getByText(/simulation pas encore en revue/i),
|
page.getByText(/simulation not yet ready for review/i),
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
|
|
||||||
// SOC fields are disabled
|
// SOC fields are disabled
|
||||||
|
|||||||
Reference in New Issue
Block a user