/** * Scenario Test Runner * Validates that rendered events match expected layout */ export class ScenarioTestRunner { /** * Validate a scenario's rendered output * @param {string} scenarioId - e.g., "scenario-1" * @param {Array} expectedResults - Array of {eventId, stackLevel, cols?, type: 'grid'|'stacked'} * @returns {object} - {passed: boolean, results: Array, message: string} */ static validateScenario(scenarioId, expectedResults) { const results = []; let allPassed = true; for (const expected of expectedResults) { const result = this.validateEvent(expected.eventId, expected); results.push(result); if (!result.passed) { allPassed = false; } } return { passed: allPassed, results, message: allPassed ? 'All tests passed ✅' : 'Some tests failed ❌' }; } /** * Validate a single event */ static validateEvent(eventId, expected) { const eventEl = document.querySelector(`swp-event[data-event-id="${eventId}"]`); if (!eventEl) { return { passed: false, eventId, message: `Event ${eventId} not found in DOM` }; } const errors = []; // Check if in grid group const gridGroup = eventEl.closest('swp-event-group'); if (expected.type === 'grid') { if (!gridGroup) { errors.push(`Expected to be in grid group, but found as stacked event`); } else { // Validate grid group properties const groupStackLevel = this.getStackLevel(gridGroup); if (groupStackLevel !== expected.stackLevel) { errors.push(`Grid group stack level: expected ${expected.stackLevel}, got ${groupStackLevel}`); } if (expected.cols) { const cols = this.getColumnCount(gridGroup); if (cols !== expected.cols) { errors.push(`Grid columns: expected ${expected.cols}, got ${cols}`); } } } } else if (expected.type === 'stacked') { if (gridGroup) { errors.push(`Expected to be stacked, but found in grid group`); } else { // Validate stacked event properties const stackLevel = this.getStackLevel(eventEl); if (stackLevel !== expected.stackLevel) { errors.push(`Stack level: expected ${expected.stackLevel}, got ${stackLevel}`); } } } return { passed: errors.length === 0, eventId, message: errors.length === 0 ? '✅' : errors.join('; ') }; } /** * Get stack level from element */ static getStackLevel(element) { const stackLink = element.getAttribute('data-stack-link'); if (stackLink) { try { const parsed = JSON.parse(stackLink); return parsed.stackLevel; } catch (e) { return null; } } // Try class name fallback const classMatch = element.className.match(/stack-level-(\d+)/); return classMatch ? parseInt(classMatch[1]) : null; } /** * Get column count from grid group */ static getColumnCount(gridGroup) { const classMatch = gridGroup.className.match(/cols-(\d+)/); return classMatch ? parseInt(classMatch[1]) : null; } /** * Display test results in the DOM */ static displayResults(containerId, results) { const container = document.getElementById(containerId); if (!container) return; const badge = document.createElement('span'); badge.className = `test-badge ${results.passed ? 'test-passed' : 'test-failed'}`; badge.textContent = results.message; container.appendChild(badge); // Add detailed results const details = document.createElement('div'); details.className = 'test-details'; details.innerHTML = '