mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 06:51:12 -05:00
295 lines
10 KiB
TypeScript
295 lines
10 KiB
TypeScript
/**
|
|
* 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<TestResult> => {
|
|
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<TestResult> => {
|
|
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<TestResult> => {
|
|
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()
|
|
};
|
|
}
|
|
}
|
|
}
|
|
]
|
|
};
|