/** * Moderation Lock Management Integration Tests * * Tests for submission locking, claiming, extending, and release mechanisms */ import { supabase } from '@/lib/supabaseClient'; import type { TestSuite, TestResult } from '../testRunner'; export const moderationLockTestSuite: TestSuite = { id: 'moderation-locks', name: 'Moderation Lock Management', description: 'Tests for submission locking, claiming, and release mechanisms', tests: [ { id: 'lock-001', name: 'Claim Submission Creates Active Lock', description: 'Verifies that claiming a submission creates a lock with correct expiry', run: async (): Promise => { const startTime = Date.now(); try { const { data: userData } = await supabase.auth.getUser(); if (!userData.user) throw new Error('No authenticated user'); // 1. Create test submission const { data: submission, error: createError } = await supabase .from('content_submissions') .insert({ user_id: userData.user.id, submission_type: 'park', status: 'pending', content: { test: true } }) .select() .single(); if (createError) throw createError; // 2. Claim the submission (manual update for testing) const { error: lockError } = await supabase .from('content_submissions') .update({ assigned_to: userData.user.id, locked_until: new Date(Date.now() + 15 * 60 * 1000).toISOString() }) .eq('id', submission.id); if (lockError) throw new Error(`Claim failed: ${lockError.message}`); // 3. Verify lock exists const { data: lockedSubmission, error: fetchError } = await supabase .from('content_submissions') .select('assigned_to, locked_until') .eq('id', submission.id) .single(); if (fetchError) throw fetchError; // 4. Assertions if (lockedSubmission.assigned_to !== userData.user.id) { throw new Error('Submission not assigned to current user'); } if (!lockedSubmission.locked_until) { throw new Error('locked_until not set'); } const lockedUntil = new Date(lockedSubmission.locked_until); const now = new Date(); const diffMinutes = (lockedUntil.getTime() - now.getTime()) / (1000 * 60); if (diffMinutes < 14 || diffMinutes > 16) { throw new Error(`Lock duration incorrect: ${diffMinutes} minutes`); } // Cleanup await supabase.from('content_submissions').delete().eq('id', submission.id); return { id: 'lock-001', name: 'Claim Submission Creates Active Lock', suite: 'Moderation Lock Management', status: 'pass', duration: Date.now() - startTime, timestamp: new Date().toISOString(), details: { submissionId: submission.id, lockDurationMinutes: diffMinutes, assignedTo: lockedSubmission.assigned_to } }; } catch (error) { return { id: 'lock-001', name: 'Claim Submission Creates Active Lock', suite: 'Moderation Lock Management', status: 'fail', duration: Date.now() - startTime, error: error instanceof Error ? error.message : String(error), timestamp: new Date().toISOString() }; } } }, { id: 'lock-002', name: 'Release Lock Clears Assignment', description: 'Verifies that releasing a lock clears assigned_to and locked_until', run: async (): Promise => { const startTime = Date.now(); try { const { data: userData } = await supabase.auth.getUser(); if (!userData.user) throw new Error('No authenticated user'); // Create and claim submission const { data: submission, error: createError } = await supabase .from('content_submissions') .insert({ user_id: userData.user.id, submission_type: 'park', status: 'pending', content: { test: true } }) .select() .single(); if (createError) throw createError; await supabase .from('content_submissions') .update({ assigned_to: userData.user.id, locked_until: new Date(Date.now() + 15 * 60 * 1000).toISOString() }) .eq('id', submission.id); // Release lock const { error: releaseError } = await supabase .from('content_submissions') .update({ assigned_to: null, locked_until: null }) .eq('id', submission.id); if (releaseError) throw new Error(`release_lock failed: ${releaseError.message}`); // Verify lock cleared const { data: releasedSubmission, error: fetchError } = await supabase .from('content_submissions') .select('assigned_to, locked_until') .eq('id', submission.id) .single(); if (fetchError) throw fetchError; if (releasedSubmission.assigned_to !== null) { throw new Error('assigned_to not cleared'); } if (releasedSubmission.locked_until !== null) { throw new Error('locked_until not cleared'); } // Cleanup await supabase.from('content_submissions').delete().eq('id', submission.id); return { id: 'lock-002', name: 'Release Lock Clears Assignment', suite: 'Moderation Lock Management', status: 'pass', duration: Date.now() - startTime, timestamp: new Date().toISOString() }; } catch (error) { return { id: 'lock-002', name: 'Release Lock Clears Assignment', suite: 'Moderation Lock Management', status: 'fail', duration: Date.now() - startTime, error: error instanceof Error ? error.message : String(error), timestamp: new Date().toISOString() }; } } }, { id: 'lock-003', name: 'Extend Lock Adds 15 Minutes', description: 'Verifies that extending a lock adds correct duration', run: async (): Promise => { const startTime = Date.now(); try { const { data: userData } = await supabase.auth.getUser(); if (!userData.user) throw new Error('No authenticated user'); // Create and claim submission const { data: submission, error: createError } = await supabase .from('content_submissions') .insert({ user_id: userData.user.id, submission_type: 'park', status: 'pending', content: { test: true } }) .select() .single(); if (createError) throw createError; const initialLockTime = new Date(Date.now() + 15 * 60 * 1000); await supabase .from('content_submissions') .update({ assigned_to: userData.user.id, locked_until: initialLockTime.toISOString() }) .eq('id', submission.id); // Get initial lock time const { data: initialLock } = await supabase .from('content_submissions') .select('locked_until') .eq('id', submission.id) .single(); // Extend lock (add 15 more minutes) const extendedLockTime = new Date(initialLockTime.getTime() + 15 * 60 * 1000); const { error: extendError } = await supabase .from('content_submissions') .update({ locked_until: extendedLockTime.toISOString() }) .eq('id', submission.id); if (extendError) throw new Error(`extend_lock failed: ${extendError.message}`); // Verify extended lock const { data: extendedLock, error: fetchError } = await supabase .from('content_submissions') .select('locked_until') .eq('id', submission.id) .single(); if (fetchError) throw fetchError; if (!initialLock?.locked_until || !extendedLock.locked_until) { throw new Error('Lock times not found'); } const initialTime = new Date(initialLock.locked_until); const extendedTime = new Date(extendedLock.locked_until); const diffMinutes = (extendedTime.getTime() - initialTime.getTime()) / (1000 * 60); if (diffMinutes < 14 || diffMinutes > 16) { throw new Error(`Extension duration incorrect: ${diffMinutes} minutes`); } // Cleanup await supabase.from('content_submissions').delete().eq('id', submission.id); return { id: 'lock-003', name: 'Extend Lock Adds 15 Minutes', suite: 'Moderation Lock Management', status: 'pass', duration: Date.now() - startTime, timestamp: new Date().toISOString(), details: { extensionMinutes: diffMinutes } }; } catch (error) { return { id: 'lock-003', name: 'Extend Lock Adds 15 Minutes', suite: 'Moderation Lock Management', status: 'fail', duration: Date.now() - startTime, error: error instanceof Error ? error.message : String(error), timestamp: new Date().toISOString() }; } } } ] };