- Fixed calendar_scripts.html to wait for DOM ready before initialization - Added retry logic if widget not found on first attempt - Changed integration fallback: show ALL events when no calendars configured - Changed behavior: if no calendars selected, show all events (legacy mode) - This ensures backward compatibility with existing events User feedback: Integration wasn't initializing on page load, button '+' didn't work. Solution: Auto-init with retry + always show events (no empty state).
759 lines
26 KiB
HTML
759 lines
26 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ru">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Calendar Frontend Test</title>
|
|
|
|
<!-- Bootstrap CSS (offline fallback) -->
|
|
<style>
|
|
@import url('https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css');
|
|
@import url('https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css');
|
|
</style>
|
|
|
|
<!-- Inline styles as fallback -->
|
|
<style>
|
|
body {
|
|
padding: 20px;
|
|
background: #f8f9fa;
|
|
}
|
|
|
|
.test-section {
|
|
background: white;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin-bottom: 20px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.test-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
padding-bottom: 15px;
|
|
border-bottom: 2px solid #e9ecef;
|
|
}
|
|
|
|
.status-badge {
|
|
padding: 5px 10px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.status-pending { background: #ffc107; color: #000; }
|
|
.status-success { background: #28a745; color: #fff; }
|
|
.status-error { background: #dc3545; color: #fff; }
|
|
|
|
.log-console {
|
|
background: #2d2d2d;
|
|
color: #f8f8f2;
|
|
padding: 15px;
|
|
border-radius: 4px;
|
|
font-family: 'Courier New', monospace;
|
|
font-size: 13px;
|
|
max-height: 400px;
|
|
overflow-y: auto;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
.log-entry {
|
|
margin: 3px 0;
|
|
padding: 2px 0;
|
|
}
|
|
|
|
.log-info { color: #66d9ef; }
|
|
.log-success { color: #a6e22e; }
|
|
.log-error { color: #f92672; }
|
|
.log-warn { color: #e6db74; }
|
|
|
|
#calendarContainer {
|
|
min-height: 600px;
|
|
background: white;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.calendar-list-container {
|
|
max-height: 400px;
|
|
overflow-y: auto;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 4px;
|
|
padding: 10px;
|
|
background: white;
|
|
}
|
|
|
|
.calendar-list-item {
|
|
padding: 10px;
|
|
margin-bottom: 8px;
|
|
border: 1px solid #e9ecef;
|
|
border-radius: 4px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.calendar-list-item:hover {
|
|
background: #f8f9fa;
|
|
border-color: #0d6efd;
|
|
}
|
|
|
|
.calendar-color-indicator {
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 50%;
|
|
border: 2px solid rgba(0,0,0,0.1);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.calendar-list-item-info {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.calendar-list-item-title {
|
|
font-weight: 600;
|
|
font-size: 14px;
|
|
margin: 0;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.calendar-list-item-meta {
|
|
font-size: 12px;
|
|
color: #6c757d;
|
|
margin: 2px 0 0 0;
|
|
}
|
|
|
|
.calendar-list-item-actions {
|
|
display: flex;
|
|
gap: 5px;
|
|
flex-shrink: 0;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container-fluid">
|
|
<h1 class="mb-4">🧪 Calendar Frontend Test Suite</h1>
|
|
|
|
<!-- Test Controls -->
|
|
<div class="test-section">
|
|
<div class="test-header">
|
|
<h3>🎮 Test Controls</h3>
|
|
<div>
|
|
<button id="runAllTests" class="btn btn-primary">
|
|
<i class="bi-play-fill"></i> Run All Tests
|
|
</button>
|
|
<button id="clearLogs" class="btn btn-secondary">
|
|
<i class="bi-trash"></i> Clear Logs
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-3">
|
|
<div class="col-md-4">
|
|
<button id="testApiWrapper" class="btn btn-outline-primary w-100">
|
|
Test 1: API Wrapper
|
|
</button>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<button id="testCalendarManager" class="btn btn-outline-primary w-100">
|
|
Test 2: Calendar Manager
|
|
</button>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<button id="testModalComponent" class="btn btn-outline-primary w-100">
|
|
Test 3: Modal Component
|
|
</button>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<button id="testWidgetIntegration" class="btn btn-outline-primary w-100">
|
|
Test 4: Widget Integration
|
|
</button>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<button id="testEventFiltering" class="btn btn-outline-primary w-100">
|
|
Test 5: Event Filtering
|
|
</button>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<button id="testUserInteractions" class="btn btn-outline-primary w-100">
|
|
Test 6: User Interactions
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Test Results -->
|
|
<div class="test-section">
|
|
<div class="test-header">
|
|
<h3>📊 Test Results</h3>
|
|
<div id="testSummary">
|
|
<span class="badge bg-secondary">Ready</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Test</th>
|
|
<th>Status</th>
|
|
<th>Duration</th>
|
|
<th>Details</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="testResultsTable">
|
|
<tr>
|
|
<td colspan="4" class="text-center text-muted">No tests run yet</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Calendar UI Demo -->
|
|
<div class="test-section">
|
|
<div class="test-header">
|
|
<h3>📅 Calendar UI Demo</h3>
|
|
<button id="btnCreateCalendar" class="btn btn-sm btn-outline-primary" data-action="create-calendar">
|
|
<i class="bi-plus-lg"></i> Create Calendar
|
|
</button>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<h5>My Calendars</h5>
|
|
<div id="calendarListContainer" class="calendar-list-container">
|
|
<div class="text-center text-muted py-3">
|
|
<div class="spinner-border spinner-border-sm" role="status">
|
|
<span class="visually-hidden">Loading...</span>
|
|
</div>
|
|
<p class="mb-0 mt-2">Loading calendars...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-9">
|
|
<div id="calendarContainer"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Console Log -->
|
|
<div class="test-section">
|
|
<div class="test-header">
|
|
<h3>📝 Console Log</h3>
|
|
<button id="toggleConsole" class="btn btn-sm btn-outline-secondary">
|
|
<i class="bi-chevron-up"></i> Collapse
|
|
</button>
|
|
</div>
|
|
<div id="logConsole" class="log-console"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal Template -->
|
|
<div class="modal fade" id="calendarManageModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Manage Calendar</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="calendarForm">
|
|
<div class="mb-3">
|
|
<label for="calendarTitle" class="form-label">Title</label>
|
|
<input type="text" class="form-control" id="calendarTitle" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="calendarDescription" class="form-label">Description</label>
|
|
<textarea class="form-control" id="calendarDescription" rows="3"></textarea>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="calendarColor" class="form-label">Color</label>
|
|
<input type="color" class="form-control form-control-color" id="calendarColor" value="#0d6efd">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Type</label>
|
|
<div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="calendarType" id="typePersonal" value="personal" checked>
|
|
<label class="form-check-label" for="typePersonal">Personal</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="calendarType" id="typePublic" value="public">
|
|
<label class="form-check-label" for="typePublic">Public</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-primary" id="saveCalendarBtn">Save</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bootstrap JS -->
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
<!-- FullCalendar JS -->
|
|
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.8/index.global.min.js"></script>
|
|
|
|
<script>
|
|
// =========================
|
|
// Mock Data & API
|
|
// =========================
|
|
|
|
let mockCalendars = [
|
|
{ id: 1, title: 'Personal', description: 'My personal calendar', color: '#0d6efd', calendar_type: 'personal', user_can_edit: true, user_can_view: true, is_subscribed: true },
|
|
{ id: 2, title: 'Work', description: 'Work events', color: '#198754', calendar_type: 'public', user_can_edit: true, user_can_view: true, is_subscribed: true },
|
|
{ id: 3, title: 'Team Meetings', description: 'Team sync meetings', color: '#ffc107', calendar_type: 'department', user_can_edit: false, user_can_view: true, is_subscribed: true },
|
|
];
|
|
|
|
let mockEvents = [
|
|
{ id: 1, title: 'Morning Standup', start: new Date(2026, 1, 11, 9, 0), end: new Date(2026, 1, 11, 9, 30), color: '#0d6efd', calendar_id: 1 },
|
|
{ id: 2, title: 'Client Meeting', start: new Date(2026, 1, 11, 14, 0), end: new Date(2026, 1, 11, 15, 0), color: '#198754', calendar_id: 2 },
|
|
{ id: 3, title: 'Sprint Planning', start: new Date(2026, 1, 12, 10, 0), end: new Date(2026, 1, 12, 12, 0), color: '#ffc107', calendar_id: 3 },
|
|
{ id: 4, title: 'Code Review', start: new Date(2026, 1, 13, 15, 0), end: new Date(2026, 1, 13, 16, 0), color: '#0d6efd', calendar_id: 1 },
|
|
];
|
|
|
|
// Mock API
|
|
const mockAPI = {
|
|
getMyCalendars: async () => {
|
|
await delay(300);
|
|
log('API: getMyCalendars() → ' + mockCalendars.length + ' calendars', 'info');
|
|
return { ok: true, data: [...mockCalendars] };
|
|
},
|
|
|
|
createCalendar: async (data) => {
|
|
await delay(500);
|
|
const newCalendar = {
|
|
id: Date.now(),
|
|
...data,
|
|
user_can_edit: true,
|
|
user_can_view: true,
|
|
is_subscribed: true
|
|
};
|
|
mockCalendars.push(newCalendar);
|
|
log('API: createCalendar() → Calendar #' + newCalendar.id + ' created', 'success');
|
|
return { ok: true, data: newCalendar };
|
|
},
|
|
|
|
updateCalendar: async (id, data) => {
|
|
await delay(500);
|
|
const index = mockCalendars.findIndex(c => c.id === id);
|
|
if (index !== -1) {
|
|
mockCalendars[index] = { ...mockCalendars[index], ...data };
|
|
log('API: updateCalendar(' + id + ') → Updated', 'success');
|
|
return { ok: true, data: mockCalendars[index] };
|
|
}
|
|
return { ok: false, error: 'Calendar not found' };
|
|
},
|
|
|
|
deleteCalendar: async (id) => {
|
|
await delay(500);
|
|
mockCalendars = mockCalendars.filter(c => c.id !== id);
|
|
log('API: deleteCalendar(' + id + ') → Deleted', 'success');
|
|
return { ok: true };
|
|
},
|
|
|
|
getCalendarEvents: async (params) => {
|
|
await delay(300);
|
|
let events = [...mockEvents];
|
|
if (params.calendar_id) {
|
|
events = events.filter(e => e.calendar_id === params.calendar_id);
|
|
}
|
|
log('API: getCalendarEvents(' + JSON.stringify(params) + ') → ' + events.length + ' events', 'info');
|
|
return { ok: true, data: events };
|
|
}
|
|
};
|
|
|
|
// =========================
|
|
// Test Logger
|
|
// =========================
|
|
|
|
const logConsole = document.getElementById('logConsole');
|
|
const testResultsTable = document.getElementById('testResultsTable');
|
|
let testResults = [];
|
|
|
|
function log(message, type = 'info') {
|
|
const timestamp = new Date().toLocaleTimeString();
|
|
const entry = document.createElement('div');
|
|
entry.className = 'log-entry log-' + type;
|
|
entry.textContent = '[' + timestamp + '] ' + message;
|
|
logConsole.appendChild(entry);
|
|
logConsole.scrollTop = logConsole.scrollHeight;
|
|
|
|
// Also log to real console
|
|
console.log('[Test]', message);
|
|
}
|
|
|
|
function delay(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
function updateTestResult(testName, status, duration, details) {
|
|
testResults.push({ testName, status, duration, details });
|
|
renderTestResults();
|
|
}
|
|
|
|
function renderTestResults() {
|
|
if (testResults.length === 0) {
|
|
testResultsTable.innerHTML = '<tr><td colspan="4" class="text-center text-muted">No tests run yet</td></tr>';
|
|
return;
|
|
}
|
|
|
|
testResultsTable.innerHTML = testResults.map(result => `
|
|
<tr>
|
|
<td>${result.testName}</td>
|
|
<td><span class="badge bg-${result.status === 'passed' ? 'success' : 'danger'}">${result.status}</span></td>
|
|
<td>${result.duration}ms</td>
|
|
<td class="text-muted small">${result.details}</td>
|
|
</tr>
|
|
`).join('');
|
|
|
|
const passed = testResults.filter(r => r.status === 'passed').length;
|
|
const failed = testResults.filter(r => r.status === 'failed').length;
|
|
document.getElementById('testSummary').innerHTML = `
|
|
<span class="badge bg-success">${passed} Passed</span>
|
|
<span class="badge bg-danger">${failed} Failed</span>
|
|
`;
|
|
}
|
|
|
|
// =========================
|
|
// Tests
|
|
// =========================
|
|
|
|
async function testApiWrapper() {
|
|
log('=== Test 1: API Wrapper ===', 'info');
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
// Test getMyCalendars
|
|
const calendars = await mockAPI.getMyCalendars();
|
|
if (!calendars.ok || !Array.isArray(calendars.data)) {
|
|
throw new Error('getMyCalendars failed');
|
|
}
|
|
log('✓ getMyCalendars works', 'success');
|
|
|
|
// Test createCalendar
|
|
const newCal = await mockAPI.createCalendar({
|
|
title: 'Test Calendar',
|
|
description: 'Test',
|
|
color: '#ff0000',
|
|
calendar_type: 'personal'
|
|
});
|
|
if (!newCal.ok || !newCal.data.id) {
|
|
throw new Error('createCalendar failed');
|
|
}
|
|
log('✓ createCalendar works', 'success');
|
|
|
|
// Test getCalendarEvents
|
|
const events = await mockAPI.getCalendarEvents({ calendar_id: 1 });
|
|
if (!events.ok || !Array.isArray(events.data)) {
|
|
throw new Error('getCalendarEvents failed');
|
|
}
|
|
log('✓ getCalendarEvents works', 'success');
|
|
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('API Wrapper', 'passed', duration, 'All API methods working');
|
|
log('✅ Test 1: PASSED', 'success');
|
|
} catch (error) {
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('API Wrapper', 'failed', duration, error.message);
|
|
log('❌ Test 1: FAILED - ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testCalendarManager() {
|
|
log('=== Test 2: Calendar Manager ===', 'info');
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
// Render calendar list
|
|
const calendars = await mockAPI.getMyCalendars();
|
|
const container = document.getElementById('calendarListContainer');
|
|
|
|
container.innerHTML = calendars.data.map(cal => `
|
|
<div class="calendar-list-item" data-calendar-id="${cal.id}">
|
|
<input type="checkbox" class="form-check-input" ${cal.is_subscribed ? 'checked' : ''}>
|
|
<div class="calendar-color-indicator" style="background-color: ${cal.color}"></div>
|
|
<div class="calendar-list-item-info">
|
|
<p class="calendar-list-item-title">${cal.title}</p>
|
|
<p class="calendar-list-item-meta">${cal.calendar_type}</p>
|
|
</div>
|
|
<div class="calendar-list-item-actions">
|
|
${cal.user_can_edit ? '<button class="btn btn-sm btn-outline-secondary"><i class="bi-pencil"></i></button>' : ''}
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
|
|
log('✓ Calendar list rendered', 'success');
|
|
|
|
// Test checkbox interaction
|
|
const firstCheckbox = container.querySelector('input[type="checkbox"]');
|
|
if (!firstCheckbox) {
|
|
throw new Error('Checkbox not found');
|
|
}
|
|
firstCheckbox.click();
|
|
log('✓ Checkbox interaction works', 'success');
|
|
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('Calendar Manager', 'passed', duration, 'List rendering and interaction OK');
|
|
log('✅ Test 2: PASSED', 'success');
|
|
} catch (error) {
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('Calendar Manager', 'failed', duration, error.message);
|
|
log('❌ Test 2: FAILED - ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testModalComponent() {
|
|
log('=== Test 3: Modal Component ===', 'info');
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
const modal = new bootstrap.Modal(document.getElementById('calendarManageModal'));
|
|
|
|
// Test modal open
|
|
modal.show();
|
|
await delay(500);
|
|
log('✓ Modal opens', 'success');
|
|
|
|
// Test form validation
|
|
const titleInput = document.getElementById('calendarTitle');
|
|
titleInput.value = 'Test Calendar';
|
|
if (titleInput.value !== 'Test Calendar') {
|
|
throw new Error('Form input failed');
|
|
}
|
|
log('✓ Form inputs work', 'success');
|
|
|
|
// Close modal
|
|
modal.hide();
|
|
await delay(500);
|
|
log('✓ Modal closes', 'success');
|
|
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('Modal Component', 'passed', duration, 'Modal and form working');
|
|
log('✅ Test 3: PASSED', 'success');
|
|
} catch (error) {
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('Modal Component', 'failed', duration, error.message);
|
|
log('❌ Test 3: FAILED - ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testWidgetIntegration() {
|
|
log('=== Test 4: Widget Integration ===', 'info');
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
// Initialize FullCalendar
|
|
const calendarEl = document.getElementById('calendarContainer');
|
|
const calendar = new FullCalendar.Calendar(calendarEl, {
|
|
initialView: 'dayGridMonth',
|
|
initialDate: '2026-02-11',
|
|
events: async (info, success, failure) => {
|
|
try {
|
|
const events = await mockAPI.getCalendarEvents({});
|
|
success(events.data);
|
|
} catch (e) {
|
|
failure(e);
|
|
}
|
|
}
|
|
});
|
|
|
|
calendar.render();
|
|
await delay(1000);
|
|
log('✓ FullCalendar initialized', 'success');
|
|
|
|
// Check if events loaded
|
|
const eventCount = calendar.getEvents().length;
|
|
if (eventCount === 0) {
|
|
throw new Error('No events loaded');
|
|
}
|
|
log('✓ Events loaded: ' + eventCount, 'success');
|
|
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('Widget Integration', 'passed', duration, eventCount + ' events loaded');
|
|
log('✅ Test 4: PASSED', 'success');
|
|
} catch (error) {
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('Widget Integration', 'failed', duration, error.message);
|
|
log('❌ Test 4: FAILED - ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testEventFiltering() {
|
|
log('=== Test 5: Event Filtering ===', 'info');
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
// Test filtering by calendar_id
|
|
const allEvents = await mockAPI.getCalendarEvents({});
|
|
const filteredEvents = await mockAPI.getCalendarEvents({ calendar_id: 1 });
|
|
|
|
if (filteredEvents.data.length >= allEvents.data.length) {
|
|
throw new Error('Filtering not working');
|
|
}
|
|
log('✓ Calendar filtering works', 'success');
|
|
log(' All events: ' + allEvents.data.length, 'info');
|
|
log(' Filtered (calendar 1): ' + filteredEvents.data.length, 'info');
|
|
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('Event Filtering', 'passed', duration, 'Filtering by calendar_id works');
|
|
log('✅ Test 5: PASSED', 'success');
|
|
} catch (error) {
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('Event Filtering', 'failed', duration, error.message);
|
|
log('❌ Test 5: FAILED - ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function testUserInteractions() {
|
|
log('=== Test 6: User Interactions ===', 'info');
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
// Test create button
|
|
const createBtn = document.getElementById('btnCreateCalendar');
|
|
if (!createBtn) {
|
|
throw new Error('Create button not found');
|
|
}
|
|
log('✓ Create button exists', 'success');
|
|
|
|
// Test calendar list items
|
|
const calendarItems = document.querySelectorAll('.calendar-list-item');
|
|
if (calendarItems.length === 0) {
|
|
throw new Error('No calendar items found');
|
|
}
|
|
log('✓ Calendar items rendered: ' + calendarItems.length, 'success');
|
|
|
|
// Test checkboxes
|
|
const checkboxes = document.querySelectorAll('.calendar-list-item input[type="checkbox"]');
|
|
if (checkboxes.length === 0) {
|
|
throw new Error('No checkboxes found');
|
|
}
|
|
log('✓ Checkboxes present: ' + checkboxes.length, 'success');
|
|
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('User Interactions', 'passed', duration, 'All UI elements interactive');
|
|
log('✅ Test 6: PASSED', 'success');
|
|
} catch (error) {
|
|
const duration = Date.now() - startTime;
|
|
updateTestResult('User Interactions', 'failed', duration, error.message);
|
|
log('❌ Test 6: FAILED - ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
// =========================
|
|
// Event Listeners
|
|
// =========================
|
|
|
|
document.getElementById('runAllTests').addEventListener('click', async () => {
|
|
testResults = [];
|
|
log('🚀 Running all tests...', 'info');
|
|
|
|
await testApiWrapper();
|
|
await delay(500);
|
|
await testCalendarManager();
|
|
await delay(500);
|
|
await testModalComponent();
|
|
await delay(500);
|
|
await testWidgetIntegration();
|
|
await delay(500);
|
|
await testEventFiltering();
|
|
await delay(500);
|
|
await testUserInteractions();
|
|
|
|
log('🏁 All tests completed!', 'success');
|
|
});
|
|
|
|
document.getElementById('clearLogs').addEventListener('click', () => {
|
|
logConsole.innerHTML = '';
|
|
log('Logs cleared', 'info');
|
|
});
|
|
|
|
document.getElementById('toggleConsole').addEventListener('click', () => {
|
|
const console = document.getElementById('logConsole');
|
|
const btn = document.getElementById('toggleConsole');
|
|
if (console.style.display === 'none') {
|
|
console.style.display = 'block';
|
|
btn.innerHTML = '<i class="bi-chevron-up"></i> Collapse';
|
|
} else {
|
|
console.style.display = 'none';
|
|
btn.innerHTML = '<i class="bi-chevron-down"></i> Expand';
|
|
}
|
|
});
|
|
|
|
document.getElementById('testApiWrapper').addEventListener('click', testApiWrapper);
|
|
document.getElementById('testCalendarManager').addEventListener('click', testCalendarManager);
|
|
document.getElementById('testModalComponent').addEventListener('click', testModalComponent);
|
|
document.getElementById('testWidgetIntegration').addEventListener('click', testWidgetIntegration);
|
|
document.getElementById('testEventFiltering').addEventListener('click', testEventFiltering);
|
|
document.getElementById('testUserInteractions').addEventListener('click', testUserInteractions);
|
|
|
|
// Modal save button
|
|
document.getElementById('saveCalendarBtn').addEventListener('click', async () => {
|
|
const title = document.getElementById('calendarTitle').value;
|
|
const description = document.getElementById('calendarDescription').value;
|
|
const color = document.getElementById('calendarColor').value;
|
|
const type = document.querySelector('input[name="calendarType"]:checked').value;
|
|
|
|
if (!title) {
|
|
alert('Title is required');
|
|
return;
|
|
}
|
|
|
|
log('Creating calendar: ' + title, 'info');
|
|
const result = await mockAPI.createCalendar({ title, description, color, calendar_type: type });
|
|
|
|
if (result.ok) {
|
|
log('Calendar created successfully!', 'success');
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById('calendarManageModal'));
|
|
modal.hide();
|
|
|
|
// Refresh calendar list
|
|
await testCalendarManager();
|
|
}
|
|
});
|
|
|
|
// Create calendar button
|
|
document.getElementById('btnCreateCalendar').addEventListener('click', () => {
|
|
log('Opening create calendar modal', 'info');
|
|
const modal = new bootstrap.Modal(document.getElementById('calendarManageModal'));
|
|
|
|
// Reset form
|
|
document.getElementById('calendarTitle').value = '';
|
|
document.getElementById('calendarDescription').value = '';
|
|
document.getElementById('calendarColor').value = '#0d6efd';
|
|
document.getElementById('typePersonal').checked = true;
|
|
|
|
modal.show();
|
|
});
|
|
|
|
// =========================
|
|
// Initialize
|
|
// =========================
|
|
|
|
log('✅ Test suite initialized', 'success');
|
|
log('Click "Run All Tests" to start', 'info');
|
|
|
|
// Auto-load calendar list on startup (wrapped in async IIFE)
|
|
(async function init() {
|
|
try {
|
|
await testCalendarManager();
|
|
await testWidgetIntegration();
|
|
} catch (error) {
|
|
log('Initialization error: ' + error.message, 'error');
|
|
}
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|