test(e2e): sprint 2 acceptance tests — US-7 through US-12
Covers AC-7.1→AC-7.6, AC-8.1→AC-8.6, AC-9.1→AC-9.4, AC-10.1→AC-10.5, AC-11.1→AC-11.5, AC-12.1→AC-12.4 (32 new tests, all passing). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
153
e2e/tests/us12-simulation-delete.spec.ts
Normal file
153
e2e/tests/us12-simulation-delete.spec.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* US-12 — simulation delete (RBAC + cascade + confirm modal).
|
||||
* Covers AC-12.1 → AC-12.4.
|
||||
*/
|
||||
import { test, expect } from '@playwright/test';
|
||||
import {
|
||||
adminToken,
|
||||
createEngagement,
|
||||
deleteEngagement,
|
||||
deleteUserByUsername,
|
||||
ensureUser,
|
||||
login,
|
||||
makeClient,
|
||||
} from '../fixtures/api';
|
||||
import { seedTokenInStorage } from '../fixtures/auth';
|
||||
|
||||
const REDTEAM_USER = 'us12-redteam';
|
||||
const SOC_USER = 'us12-soc';
|
||||
const PASS = 'us12-pass-strong';
|
||||
|
||||
interface Simulation {
|
||||
id: number;
|
||||
engagement_id: number;
|
||||
name: string;
|
||||
status: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
async function createSimulation(
|
||||
token: string,
|
||||
engagementId: number,
|
||||
name = 'US-12 sim',
|
||||
): Promise<Simulation> {
|
||||
const client = makeClient(token);
|
||||
const r = await client.post(`/engagements/${engagementId}/simulations`, { name });
|
||||
if (r.status !== 201) {
|
||||
throw new Error(`create simulation failed: ${r.status} ${JSON.stringify(r.data)}`);
|
||||
}
|
||||
return r.data as Simulation;
|
||||
}
|
||||
|
||||
test.describe('US-12 — simulation delete', () => {
|
||||
let redteamToken: string;
|
||||
let socToken: string;
|
||||
let engagementId: number;
|
||||
|
||||
test.beforeAll(async () => {
|
||||
await ensureUser(REDTEAM_USER, PASS, 'redteam');
|
||||
await ensureUser(SOC_USER, PASS, 'soc');
|
||||
redteamToken = (await login(REDTEAM_USER, PASS)).token;
|
||||
socToken = (await login(SOC_USER, PASS)).token;
|
||||
const eng = await createEngagement(redteamToken, {
|
||||
name: 'US-12 Test Engagement',
|
||||
start_date: '2026-01-01',
|
||||
});
|
||||
engagementId = eng.id;
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
try {
|
||||
const tok = await adminToken();
|
||||
await deleteEngagement(tok, engagementId);
|
||||
for (const u of [REDTEAM_USER, SOC_USER]) {
|
||||
await deleteUserByUsername(tok, u);
|
||||
}
|
||||
} catch {
|
||||
/* noop */
|
||||
}
|
||||
});
|
||||
|
||||
test('AC-12.1 — DELETE /api/simulations/<sid> (redteam) → 204, then 404', async () => {
|
||||
const sim = await createSimulation(redteamToken, engagementId, 'AC-12.1 to delete');
|
||||
const client = makeClient(redteamToken);
|
||||
|
||||
const rDel = await client.delete(`/simulations/${sim.id}`);
|
||||
expect(rDel.status).toBe(204);
|
||||
|
||||
const rGet = await client.get(`/simulations/${sim.id}`);
|
||||
expect(rGet.status).toBe(404);
|
||||
});
|
||||
|
||||
test('AC-12.2 — soc → 403 on DELETE', async () => {
|
||||
const sim = await createSimulation(redteamToken, engagementId, 'AC-12.2 soc blocked');
|
||||
const socClient = makeClient(socToken);
|
||||
|
||||
const r = await socClient.delete(`/simulations/${sim.id}`);
|
||||
expect(r.status).toBe(403);
|
||||
|
||||
// Clean up
|
||||
const rtClient = makeClient(redteamToken);
|
||||
await rtClient.delete(`/simulations/${sim.id}`);
|
||||
});
|
||||
|
||||
test('AC-12.3 — cascade: deleting engagement deletes its simulations', async () => {
|
||||
const adminTok = await adminToken();
|
||||
const adminClient = makeClient(adminTok);
|
||||
|
||||
// Create a fresh engagement with simulations
|
||||
const eng = await createEngagement(redteamToken, {
|
||||
name: 'US-12 cascade test',
|
||||
start_date: '2026-01-01',
|
||||
});
|
||||
const s1 = await createSimulation(redteamToken, eng.id, 'cascade sim 1');
|
||||
const s2 = await createSimulation(redteamToken, eng.id, 'cascade sim 2');
|
||||
|
||||
// Delete the engagement
|
||||
await deleteEngagement(redteamToken, eng.id);
|
||||
|
||||
// Simulations must be gone
|
||||
const rS1 = await adminClient.get(`/simulations/${s1.id}`);
|
||||
expect(rS1.status).toBe(404);
|
||||
const rS2 = await adminClient.get(`/simulations/${s2.id}`);
|
||||
expect(rS2.status).toBe(404);
|
||||
});
|
||||
|
||||
test('AC-12.4 — delete button visible for redteam, confirmation modal, deletes and redirects', async ({
|
||||
page,
|
||||
context,
|
||||
}) => {
|
||||
const sim = await createSimulation(redteamToken, engagementId, 'AC-12.4 UI delete');
|
||||
|
||||
await seedTokenInStorage(context, redteamToken);
|
||||
await page.goto(`/engagements/${engagementId}/simulations/${sim.id}/edit`);
|
||||
|
||||
// Delete button is visible for redteam
|
||||
const deleteBtn = page.getByRole('button', { name: /supprimer/i });
|
||||
await expect(deleteBtn).toBeVisible();
|
||||
|
||||
// SOC should NOT see delete button
|
||||
await seedTokenInStorage(context, socToken);
|
||||
await page.goto(`/engagements/${engagementId}/simulations/${sim.id}/edit`);
|
||||
await expect(page.getByRole('button', { name: /supprimer/i })).toHaveCount(0);
|
||||
|
||||
// Back to redteam — click delete, confirm modal appears
|
||||
await seedTokenInStorage(context, redteamToken);
|
||||
await page.goto(`/engagements/${engagementId}/simulations/${sim.id}/edit`);
|
||||
await page.getByRole('button', { name: /supprimer/i }).click();
|
||||
|
||||
// Confirmation dialog must appear
|
||||
const dialog = page.getByRole('dialog');
|
||||
await expect(dialog).toBeVisible();
|
||||
await expect(dialog.getByText(/supprimer la simulation/i)).toBeVisible();
|
||||
|
||||
// Confirm deletion
|
||||
await dialog.getByRole('button', { name: /supprimer/i }).click();
|
||||
|
||||
// Should navigate back to engagement detail
|
||||
await page.waitForURL(new RegExp(`/engagements/${engagementId}$`));
|
||||
|
||||
// Simulation no longer in list
|
||||
await expect(page.getByRole('row', { name: /AC-12.4 UI delete/i })).toHaveCount(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user