Files
thrilltrack-explorer/tests/e2e/moderation/approval-flow.spec.ts
2025-10-30 15:42:28 +00:00

140 lines
4.8 KiB
TypeScript

/**
* Moderation Approval Flow E2E Tests
*
* Tests the complete submission approval process.
*/
import { test, expect } from '@playwright/test';
import { ModerationQueuePage } from '../../helpers/page-objects/ModerationQueuePage';
import { ParkCreationPage } from '../../helpers/page-objects/ParkCreationPage';
import { generateParkData, generateTestId } from '../../fixtures/test-data';
import { queryDatabase, cleanupTestData, waitForVersion } from '../../fixtures/database';
test.describe('Submission Approval Flow', () => {
test.afterAll(async () => {
await cleanupTestData();
});
test('should approve park submission and create entity', async ({ browser }) => {
// Step 1: Create submission as regular user
const userContext = await browser.newContext({ storageState: '.auth/user.json' });
const userPage = await userContext.newPage();
const parkData = generateParkData({
name: `Test Park ${generateTestId()}`,
});
const parkCreationPage = new ParkCreationPage(userPage);
await parkCreationPage.goto();
await parkCreationPage.fillBasicInfo(parkData.name, parkData.description);
await parkCreationPage.submitForm();
await parkCreationPage.expectSuccess();
await userContext.close();
// Step 2: Approve as moderator
const modContext = await browser.newContext({ storageState: '.auth/moderator.json' });
const modPage = await modContext.newPage();
const moderationPage = new ModerationQueuePage(modPage);
await moderationPage.goto();
// Find the submission
await moderationPage.expectSubmissionVisible(parkData.name);
// Claim it
await moderationPage.claimSubmission(0);
// Approve it
await moderationPage.approveSubmission('Looks good!');
// Step 3: Verify entity created in database
await modPage.waitForTimeout(2000); // Give DB time to process
const parks = await queryDatabase('parks', (qb) =>
qb.select('*').eq('name', parkData.name)
);
expect(parks).toHaveLength(1);
expect(parks[0].is_test_data).toBe(true);
// Step 4: Verify version created
const versions = await queryDatabase('park_versions', (qb) =>
qb.select('*').eq('park_id', parks[0].id).eq('version_number', 1)
);
expect(versions).toHaveLength(1);
expect(versions[0].change_type).toBe('created');
// Step 5: Verify submission marked as approved
const submissions = await queryDatabase('content_submissions', (qb) =>
qb.select('*').eq('entity_type', 'park').contains('submission_data', { name: parkData.name })
);
expect(submissions[0].status).toBe('approved');
expect(submissions[0].approved_by).toBeTruthy();
expect(submissions[0].approved_at).toBeTruthy();
// Step 6: Verify lock released
expect(submissions[0].assigned_to).toBeNull();
expect(submissions[0].locked_until).toBeNull();
await modContext.close();
});
test('should show change comparison for edits', async ({ browser }) => {
// This test would require:
// 1. Creating and approving a park
// 2. Editing the park
// 3. Viewing the edit in moderation queue
// 4. Verifying change comparison displays
// Left as TODO - requires more complex setup
});
test('should send notification to submitter on approval', async ({ browser }) => {
// This test would verify that Novu notification is sent
// Left as TODO - requires Novu testing setup
});
test('should prevent approval without lock', async ({ browser }) => {
// Create submission as user
const userContext = await browser.newContext({ storageState: '.auth/user.json' });
const userPage = await userContext.newPage();
const parkData = generateParkData({
name: `Test Park ${generateTestId()}`,
});
const parkCreationPage = new ParkCreationPage(userPage);
await parkCreationPage.goto();
await parkCreationPage.fillBasicInfo(parkData.name, parkData.description);
await parkCreationPage.submitForm();
await parkCreationPage.expectSuccess();
await userContext.close();
// Try to approve as moderator WITHOUT claiming
const modContext = await browser.newContext({ storageState: '.auth/moderator.json' });
const modPage = await modContext.newPage();
const moderationPage = new ModerationQueuePage(modPage);
await moderationPage.goto();
// Approve button should be disabled or not visible
const approveButton = modPage.locator('button:has-text("Approve")').first();
await expect(approveButton).toBeDisabled();
await modContext.close();
});
});
test.describe('Bulk Approval', () => {
test('should approve all items in submission', async ({ browser }) => {
// TODO: Test approving all submission items at once
});
test('should allow selective item approval', async ({ browser }) => {
// TODO: Test approving only specific items from a submission
});
});