153 lines
4.3 KiB
JavaScript
153 lines
4.3 KiB
JavaScript
|
|
/**
|
||
|
|
* 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 = '<h4>Test Results:</h4>';
|
||
|
|
|
||
|
|
results.results.forEach(r => {
|
||
|
|
const line = document.createElement('div');
|
||
|
|
line.className = `test-result-line ${r.passed ? 'passed' : 'failed'}`;
|
||
|
|
line.textContent = `${r.eventId}: ${r.message}`;
|
||
|
|
details.appendChild(line);
|
||
|
|
});
|
||
|
|
|
||
|
|
container.appendChild(details);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Auto-run tests if window.scenarioTests is defined
|
||
|
|
window.addEventListener('DOMContentLoaded', () => {
|
||
|
|
if (window.scenarioTests) {
|
||
|
|
const results = ScenarioTestRunner.validateScenario(
|
||
|
|
window.scenarioTests.id,
|
||
|
|
window.scenarioTests.expected
|
||
|
|
);
|
||
|
|
|
||
|
|
ScenarioTestRunner.displayResults('test-results', results);
|
||
|
|
}
|
||
|
|
});
|