![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.quebec/private_html/src/components/ |
import React, { useState, useEffect } from 'react';
import {
TestTube,
CheckCircle,
XCircle,
AlertCircle,
Play,
Square,
RefreshCw,
Zap,
Database,
Globe,
Smartphone,
Monitor,
Bug,
Shield,
Users,
MessageSquare,
Bell
} from 'lucide-react';
interface TestResult {
id: string;
name: string;
category: 'profile' | 'social' | 'real-time' | 'privacy' | 'performance' | 'accessibility';
status: 'pending' | 'running' | 'passed' | 'failed' | 'skipped';
duration?: number;
error?: string;
details?: string;
timestamp: Date;
}
interface ProfileTestingSuiteProps {
userId: string;
onTestComplete: (results: TestResult[]) => void;
}
const ProfileTestingSuite: React.FC<ProfileTestingSuiteProps> = ({ userId, onTestComplete }) => {
const [tests, setTests] = useState<TestResult[]>([]);
const [isRunning, setIsRunning] = useState(false);
const [currentTest, setCurrentTest] = useState<string | null>(null);
const [summary, setSummary] = useState({
total: 0,
passed: 0,
failed: 0,
skipped: 0,
duration: 0
});
const testDefinitions = [
// Profile Tests
{
id: 'profile_load',
name: 'Profile Data Loading',
category: 'profile' as const,
test: async () => {
const response = await fetch(
if (!response.ok) throw new Error(
const data = await response.json();
if (!data.user) throw new Error('No user data returned');
return 'Profile data loaded successfully';
}
},
{
id: 'profile_stats',
name: 'Profile Statistics',
category: 'profile' as const,
test: async () => {
const response = await fetch(
const data = await response.json();
if (!data.stats) throw new Error('No stats data returned');
return 'Profile statistics loaded successfully';
}
},
{
id: 'profile_cases',
name: 'Case Involvement',
category: 'profile' as const,
test: async () => {
const response = await fetch(
if (!response.ok) throw new Error(
return 'Case involvement data loaded successfully';
}
},
// Social Tests
{
id: 'social_friends',
name: 'Friends List',
category: 'social' as const,
test: async () => {
const response = await fetch(
if (!response.ok) throw new Error(
return 'Friends list loaded successfully';
}
},
{
id: 'social_follow',
name: 'Follow Functionality',
category: 'social' as const,
test: async () => {
const response = await fetch('/api/social/follow', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ targetUserId: userId })
});
if (!response.ok) throw new Error(
return 'Follow functionality working';
}
},
{
id: 'social_endorse',
name: 'Endorsement System',
category: 'social' as const,
test: async () => {
const response = await fetch('/api/social/endorse', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ targetUserId: userId, text: 'Test endorsement' })
});
if (!response.ok) throw new Error(
return 'Endorsement system working';
}
},
// Real-time Tests
{
id: 'realtime_websocket',
name: 'WebSocket Connection',
category: 'real-time' as const,
test: async () => {
return new Promise((resolve, reject) => {
const ws = new WebSocket(
const timeout = setTimeout(() => {
ws.close();
reject(new Error('WebSocket connection timeout'));
}, 5000);
ws.onopen = () => {
clearTimeout(timeout);
ws.close();
resolve('WebSocket connection established');
};
ws.onerror = () => {
clearTimeout(timeout);
reject(new Error('WebSocket connection failed'));
};
});
}
},
{
id: 'realtime_notifications',
name: 'Real-time Notifications',
category: 'real-time' as const,
test: async () => {
const response = await fetch('/api/notifications');
if (!response.ok) throw new Error(
return 'Real-time notifications working';
}
},
// Privacy Tests
{
id: 'privacy_settings',
name: 'Privacy Settings',
category: 'privacy' as const,
test: async () => {
const response = await fetch(
const data = await response.json();
if (!data.user.showFriends !== undefined) throw new Error('Privacy settings not found');
return 'Privacy settings loaded successfully';
}
},
{
id: 'privacy_update',
name: 'Privacy Settings Update',
category: 'privacy' as const,
test: async () => {
const response = await fetch(`/api/users/${userId}
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ showFriends: true })
});
if (!response.ok) throw new Error(
return 'Privacy settings updated successfully';
}
},
// Performance Tests
{
id: 'performance_load_time',
name: 'Profile Load Time',
category: 'performance' as const,
test: async () => {
const start = performance.now();
const response = await fetch(
const end = performance.now();
const duration = end - start;
if (duration > 2000) throw new Error(
return `Profile loaded in ${duration.toFixed(0)}ms
}
},
{
id: 'performance_memory',
name: 'Memory Usage',
category: 'performance' as const,
test: async () => {
if ('memory' in performance) {
const memory = (performance as any).memory;
const usedMB = memory.usedJSHeapSize / 1024 / 1024;
if (usedMB > 100) throw new Error(
return `Memory usage: ${usedMB.toFixed(1)}MB
}
return 'Memory usage monitoring not available';
}
},
// Accessibility Tests
{
id: 'accessibility_contrast',
name: 'Color Contrast',
category: 'accessibility' as const,
test: async () => {
// Basic contrast check
const elements = document.querySelectorAll('*');
let lowContrastCount = 0;
elements.forEach(el => {
const style = window.getComputedStyle(el);
const backgroundColor = style.backgroundColor;
const color = style.color;
// Simple contrast check (this is a basic implementation)
if (backgroundColor && color && backgroundColor !== 'rgba(0, 0, 0, 0)' && color !== 'rgba(0, 0, 0, 0)') {
// This is a simplified check - in a real implementation, you'd use a proper contrast ratio calculator
lowContrastCount++;
}
});
if (lowContrastCount > 10) throw new Error(
return 'Color contrast appears acceptable';
}
},
{
id: 'accessibility_keyboard',
name: 'Keyboard Navigation',
category: 'accessibility' as const,
test: async () => {
const focusableElements = document.querySelectorAll('button, a, input, select, textarea, [tabindex]:not([tabindex="-1"])');
if (focusableElements.length === 0) throw new Error('No focusable elements found');
return `Keyboard navigation ready: ${focusableElements.length} focusable elements
}
}
];
const runTest = async (testDef: typeof testDefinitions[0]): Promise<TestResult> => {
const testResult: TestResult = {
id: testDef.id,
name: testDef.name,
category: testDef.category,
status: 'running',
timestamp: new Date()
};
setTests(prev => prev.map(t => t.id === testDef.id ? testResult : t));
setCurrentTest(testDef.id);
const startTime = Date.now();
try {
const result = await testDef.test();
const duration = Date.now() - startTime;
return {
...testResult,
status: 'passed',
duration,
details: result as string,
timestamp: new Date()
};
} catch (error) {
const duration = Date.now() - startTime;
return {
...testResult,
status: 'failed',
duration,
error: error instanceof Error ? error.message : 'Unknown error',
timestamp: new Date()
};
}
};
const runAllTests = async () => {
setIsRunning(true);
setCurrentTest(null);
const initialTests = testDefinitions.map(def => ({
id: def.id,
name: def.name,
category: def.category,
status: 'pending' as const,
timestamp: new Date()
}));
setTests(initialTests);
const results: TestResult[] = [];
const startTime = Date.now();
for (const testDef of testDefinitions) {
const result = await runTest(testDef);
results.push(result);
setTests(prev => prev.map(t => t.id === result.id ? result : t));
// Small delay between tests
await new Promise(resolve => setTimeout(resolve, 100));
}
const totalDuration = Date.now() - startTime;
const passed = results.filter(r => r.status === 'passed').length;
const failed = results.filter(r => r.status === 'failed').length;
const skipped = results.filter(r => r.status === 'skipped').length;
setSummary({
total: results.length,
passed,
failed,
skipped,
duration: totalDuration
});
setIsRunning(false);
setCurrentTest(null);
onTestComplete(results);
};
const runCategoryTests = async (category: TestResult['category']) => {
setIsRunning(true);
const categoryTests = testDefinitions.filter(def => def.category === category);
const results: TestResult[] = [];
for (const testDef of categoryTests) {
const result = await runTest(testDef);
results.push(result);
setTests(prev => prev.map(t => t.id === result.id ? result : t));
await new Promise(resolve => setTimeout(resolve, 100));
}
setIsRunning(false);
setCurrentTest(null);
};
const getStatusIcon = (status: TestResult['status']) => {
switch (status) {
case 'passed': return <CheckCircle className="h-4 w-4 text-green-500" />;
case 'failed': return <XCircle className="h-4 w-4 text-red-500" />;
case 'running': return <RefreshCw className="h-4 w-4 text-blue-500 animate-spin" />;
case 'pending': return <AlertCircle className="h-4 w-4 text-gray-400" />;
default: return <AlertCircle className="h-4 w-4 text-gray-400" />;
}
};
const getCategoryIcon = (category: TestResult['category']) => {
switch (category) {
case 'profile': return <Users className="h-4 w-4" />;
case 'social': return <MessageSquare className="h-4 w-4" />;
case 'real-time': return <Zap className="h-4 w-4" />;
case 'privacy': return <Shield className="h-4 w-4" />;
case 'performance': return <Monitor className="h-4 w-4" />;
case 'accessibility': return <Globe className="h-4 w-4" />;
default: return <TestTube className="h-4 w-4" />;
}
};
const categories = ['profile', 'social', 'real-time', 'privacy', 'performance', 'accessibility'] as const;
return (
<div className="bg-white rounded-xl shadow p-6">
<div className="flex items-center justify-between mb-6">
<h2 className="text-xl font-semibold flex items-center gap-2">
<TestTube className="h-6 w-6 text-blue-600" />
Profile Testing Suite
</h2>
<div className="flex items-center gap-2">
<button
onClick={runAllTests}
disabled={isRunning}
className="flex items-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 disabled:opacity-50"
>
{isRunning ? <Square className="h-4 w-4" /> : <Play className="h-4 w-4" />}
{isRunning ? 'Running...' : 'Run All Tests'}
</button>
</div>
</div>
{/* Summary */}
{summary.total > 0 && (
<div className="grid grid-cols-2 md:grid-cols-5 gap-4 mb-6">
<div className="bg-gray-50 rounded-lg p-3 text-center">
<div className="text-2xl font-bold text-gray-700">{summary.total}</div>
<div className="text-sm text-gray-600">Total</div>
</div>
<div className="bg-green-50 rounded-lg p-3 text-center">
<div className="text-2xl font-bold text-green-600">{summary.passed}</div>
<div className="text-sm text-green-600">Passed</div>
</div>
<div className="bg-red-50 rounded-lg p-3 text-center">
<div className="text-2xl font-bold text-red-600">{summary.failed}</div>
<div className="text-sm text-red-600">Failed</div>
</div>
<div className="bg-yellow-50 rounded-lg p-3 text-center">
<div className="text-2xl font-bold text-yellow-600">{summary.skipped}</div>
<div className="text-sm text-yellow-600">Skipped</div>
</div>
<div className="bg-blue-50 rounded-lg p-3 text-center">
<div className="text-2xl font-bold text-blue-600">{summary.duration}ms</div>
<div className="text-sm text-blue-600">Duration</div>
</div>
</div>
)}
{/* Category Buttons */}
<div className="flex flex-wrap gap-2 mb-6">
{categories.map(category => (
<button
key={category}
onClick={() => runCategoryTests(category)}
disabled={isRunning}
className="flex items-center gap-2 px-3 py-1 rounded-lg border hover:bg-gray-50 disabled:opacity-50"
>
{getCategoryIcon(category)}
<span className="capitalize">{category}</span>
</button>
))}
</div>
{/* Test Results */}
<div className="space-y-2 max-h-96 overflow-y-auto">
{tests.map(test => (
<div
key={test.id}
className={
test.status === 'passed' ? 'border-green-200 bg-green-50' :
test.status === 'failed' ? 'border-red-200 bg-red-50' :
test.status === 'running' ? 'border-blue-200 bg-blue-50' :
'border-gray-200 bg-gray-50'
}
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
{getStatusIcon(test.status)}
<div>
<div className="font-medium">{test.name}</div>
<div className="text-sm text-gray-600 capitalize">{test.category}</div>
</div>
</div>
<div className="text-right">
{test.duration && (
<div className="text-sm text-gray-600">{test.duration}ms</div>
)}
{currentTest === test.id && (
<div className="text-xs text-blue-600">Running...</div>
)}
</div>
</div>
{test.error && (
<div className="mt-2 p-2 bg-red-100 rounded text-sm text-red-700">
<strong>Error:</strong> {test.error}
</div>
)}
{test.details && (
<div className="mt-2 p-2 bg-green-100 rounded text-sm text-green-700">
{test.details}
</div>
)}
</div>
))}
</div>
{tests.length === 0 && (
<div className="text-center py-8 text-gray-500">
<TestTube className="h-12 w-12 mx-auto mb-4 text-gray-300" />
<p>No tests have been run yet.</p>
<p className="text-sm">Click "Run All Tests" to start testing.</p>
</div>
)}
</div>
);
};
export default ProfileTestingSuite;