mirror of
https://github.com/HeyPuter/puter.git
synced 2026-11-14 18:01:21 +00:00
Docker Image CI / build-and-push-image (push) Has been cancelled
Maintain Release Merge PR / update-release-pr (push) Has been cancelled
release-please / release-please (push) Has been cancelled
test / test (18.x) (push) Has been cancelled
test / test (20.x) (push) Has been cancelled
test / test (22.x) (push) Has been cancelled
- Introduced a "Reset results" button to clear test container backgrounds and remove error messages. - Implemented hover styles for the reset button to enhance user interaction. - Ensured the reset functionality hides the progress panel and resets progress tracking.
760 lines
28 KiB
HTML
760 lines
28 KiB
HTML
<html>
|
|
<head>
|
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
|
<script src="https://js.puter.com/v2/"></script>
|
|
<script src="./kv.test.js"></script>
|
|
<script src="./fs.test.js"></script>
|
|
<script src="./ai.test.js"></script>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
}
|
|
nav {
|
|
z-index: 1000;
|
|
display: flex;
|
|
align-items: center;
|
|
position: fixed;
|
|
top: 0;
|
|
width: 100%;
|
|
background: #EEE;
|
|
left: 0;
|
|
padding-left: 10px;
|
|
}
|
|
#tests {
|
|
padding-top: 50px;
|
|
}
|
|
#run-tests {
|
|
margin-top: 20px;
|
|
margin-bottom: 20px;
|
|
background-color: #4c84af;
|
|
border: none;
|
|
color: white;
|
|
padding: 10px 20px;
|
|
text-align: center;
|
|
text-decoration: none;
|
|
display: inline-block;
|
|
font-size: 16px;
|
|
cursor: pointer;
|
|
}
|
|
#unselect-all {
|
|
margin-left: 20px;
|
|
cursor: pointer;
|
|
}
|
|
#select-all {
|
|
margin-left: 20px;
|
|
cursor: pointer;
|
|
}
|
|
.test-container{
|
|
margin-bottom: 10px;
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
}
|
|
.test-container{
|
|
font-family: monospace;
|
|
}
|
|
.test-checkbox-container{
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
.test-container:hover{
|
|
background-color: #f0f0f0;
|
|
}
|
|
.test-container label{
|
|
display: block;
|
|
margin-left: 5px;
|
|
}
|
|
.test-container input{
|
|
float: left;
|
|
}
|
|
.test-name {
|
|
color: #727272;
|
|
}
|
|
.test-description {
|
|
font-size: 12px;
|
|
color: #262626;
|
|
margin-top: 2px;
|
|
}
|
|
.test-run-button {
|
|
margin-left: 10px;
|
|
background-color: #4c84af;
|
|
border: none;
|
|
color: white;
|
|
padding: 5px 10px;
|
|
text-align: center;
|
|
text-decoration: none;
|
|
display: inline-block;
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
border-radius: 3px;
|
|
opacity: 0;
|
|
transition: opacity 0.2s ease;
|
|
}
|
|
.test-container:hover .test-run-button {
|
|
opacity: 1;
|
|
}
|
|
.test-run-button:hover {
|
|
background-color: #3a6a8a;
|
|
}
|
|
.test-run-button:disabled {
|
|
background-color: #999;
|
|
cursor: not-allowed;
|
|
opacity: 1;
|
|
}
|
|
.test-run-button:disabled:hover {
|
|
background-color: #999;
|
|
}
|
|
|
|
/* Make h2 headers sticky */
|
|
#tests h2 {
|
|
position: sticky;
|
|
top: 78px; /* Position below the fixed nav */
|
|
background-color: white;
|
|
padding: 20px 0;
|
|
margin: 20px 0 10px 0;
|
|
border-bottom: 2px solid #ddd;
|
|
z-index: 10;
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
/* Adjust sticky headings when progress panel is visible */
|
|
#progress-panel.show ~ #tests h2 {
|
|
top: 158px; /* 78px + 80px to account for progress panel */
|
|
}
|
|
|
|
/* Style for h2 checkboxes */
|
|
#tests h2 input[type="checkbox"] {
|
|
margin-right: 18px;
|
|
transform: scale(1.2);
|
|
}
|
|
|
|
#tests h2 label {
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
padding-left: 10px;
|
|
font-size: 25px;
|
|
}
|
|
#test-counter {
|
|
font-size: 14px;
|
|
color: #666;
|
|
margin-right: 10px;
|
|
font-size: 20px;
|
|
}
|
|
|
|
/* Progress panel styles */
|
|
#progress-panel {
|
|
position: fixed;
|
|
top: 78px;
|
|
left: 0;
|
|
right: 0;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
padding: 15px 20px;
|
|
z-index: 999;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
transform: translateY(-100%);
|
|
transition: transform 0.3s ease-in-out;
|
|
border-bottom: 3px solid #4c84af;
|
|
}
|
|
|
|
#progress-panel.show {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
#progress-panel.show ~ #tests {
|
|
padding-top: 120px !important;
|
|
}
|
|
|
|
.progress-content {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.progress-left {
|
|
flex: 1;
|
|
}
|
|
|
|
.progress-right {
|
|
display: flex;
|
|
gap: 30px;
|
|
align-items: center;
|
|
}
|
|
|
|
.progress-stats {
|
|
display: flex;
|
|
gap: 20px;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.progress-stat {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
min-width: 80px;
|
|
}
|
|
|
|
.progress-stat-number {
|
|
font-size: 24px;
|
|
font-weight: bold;
|
|
line-height: 1;
|
|
}
|
|
|
|
.progress-stat-label {
|
|
font-size: 11px;
|
|
opacity: 0.9;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.current-test {
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.progress-bar-container {
|
|
background: rgba(255,255,255,0.2);
|
|
border-radius: 10px;
|
|
height: 8px;
|
|
overflow: hidden;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.progress-bar {
|
|
background: linear-gradient(90deg, #00c851 0%, #00ff88 100%);
|
|
height: 100%;
|
|
border-radius: 10px;
|
|
transition: width 0.3s ease;
|
|
width: 0%;
|
|
}
|
|
|
|
.progress-percentage {
|
|
font-size: 28px;
|
|
font-weight: bold;
|
|
color: #fff;
|
|
}
|
|
|
|
.stat-passed {
|
|
color: #00ff88;
|
|
}
|
|
|
|
.stat-failed {
|
|
color: #ff6b6b;
|
|
}
|
|
|
|
.stat-total {
|
|
color: #fff;
|
|
}
|
|
|
|
.elapsed-time {
|
|
font-size: 12px;
|
|
opacity: 0.8;
|
|
margin-top: 2px;
|
|
}
|
|
|
|
#reset-results:hover {
|
|
color: #333;
|
|
text-decoration: none;
|
|
}
|
|
</style>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
|
|
// Progress tracking variables
|
|
let testProgress = {
|
|
total: 0,
|
|
completed: 0,
|
|
passed: 0,
|
|
failed: 0,
|
|
startTime: null,
|
|
currentTest: '',
|
|
timerInterval: null
|
|
};
|
|
|
|
// Progress panel functions
|
|
function showProgressPanel() {
|
|
$('#progress-panel').addClass('show');
|
|
$('#run-tests').prop('disabled', true).text('Running Tests...');
|
|
startProgressTimer();
|
|
}
|
|
|
|
function hideProgressPanel() {
|
|
$('#progress-panel').removeClass('show');
|
|
$('#run-tests').prop('disabled', false).text('Run Tests');
|
|
stopProgressTimer();
|
|
}
|
|
|
|
function updateProgressPanel() {
|
|
const { total, completed, passed, failed, currentTest } = testProgress;
|
|
const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;
|
|
|
|
$('#current-test').text(currentTest || 'Preparing tests...');
|
|
$('#progress-bar').css('width', percentage + '%');
|
|
$('#progress-percentage').text(percentage + '%');
|
|
$('#passed-count').text(passed);
|
|
$('#failed-count').text(failed);
|
|
$('#total-count').text(total);
|
|
}
|
|
|
|
function startProgressTimer() {
|
|
testProgress.startTime = Date.now();
|
|
testProgress.timerInterval = setInterval(() => {
|
|
const elapsed = Math.floor((Date.now() - testProgress.startTime) / 1000);
|
|
$('#elapsed-time').text(`Elapsed: ${elapsed}s`);
|
|
}, 1000);
|
|
}
|
|
|
|
function stopProgressTimer() {
|
|
if (testProgress.timerInterval) {
|
|
clearInterval(testProgress.timerInterval);
|
|
testProgress.timerInterval = null;
|
|
}
|
|
}
|
|
|
|
function resetProgress() {
|
|
testProgress.total = 0;
|
|
testProgress.completed = 0;
|
|
testProgress.passed = 0;
|
|
testProgress.failed = 0;
|
|
testProgress.currentTest = '';
|
|
testProgress.startTime = null;
|
|
}
|
|
|
|
function getSelectedTestsCount() {
|
|
return $('.test-checkbox:checked').length;
|
|
}
|
|
|
|
// Small delay to make progress visible
|
|
function delay(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
window.pass = function(msg) {
|
|
// $('#tests').append(`<p style="color:green;">${msg}</p>`);
|
|
}
|
|
|
|
window.fail = function(msg, error) {
|
|
// Include the full error information in the thrown error
|
|
let fullMessage = msg;
|
|
if (error) {
|
|
if (typeof error === 'string') {
|
|
fullMessage += ' ' + error;
|
|
} else if (error.message) {
|
|
fullMessage += ' ' + error.message;
|
|
} else {
|
|
fullMessage += ' ' + JSON.stringify(error);
|
|
}
|
|
}
|
|
const err = new Error(fullMessage);
|
|
// Attach the original error for detailed display
|
|
err.originalError = error;
|
|
throw err;
|
|
}
|
|
|
|
// Function to get test name and description
|
|
function getTestInfo(test) {
|
|
if (typeof test === 'function') {
|
|
return {
|
|
name: test.name,
|
|
description: test.description || 'No description provided'
|
|
};
|
|
} else if (typeof test === 'object' && test.name && test.test) {
|
|
return {
|
|
name: test.name,
|
|
description: test.description || 'No description provided'
|
|
};
|
|
}
|
|
return {
|
|
name: 'Unknown Test',
|
|
description: 'No description provided'
|
|
};
|
|
}
|
|
|
|
// Function to execute a test
|
|
async function executeTest(test) {
|
|
if (typeof test === 'function') {
|
|
return await test();
|
|
} else if (typeof test === 'object' && test.test) {
|
|
return await test.test();
|
|
}
|
|
throw new Error('Invalid test format');
|
|
}
|
|
|
|
// print the test name with checkbox for each test
|
|
$('#tests').append('<h2><label><input type="checkbox" id="fsTests-group" checked> FileSystem</label></h2>');
|
|
for (let i = 0; i < fsTests.length; i++) {
|
|
const testInfo = getTestInfo(fsTests[i]);
|
|
$('#tests').append(`<div class="test-container" id="fsTests-container-${i}">
|
|
<div class="test-checkbox-container">
|
|
<input type="checkbox" class="test-checkbox fsTests-checkbox" id="fsTests${i}" checked>
|
|
<label for="fsTests${i}">
|
|
<div class="test-name">${testInfo.name}</div>
|
|
<div class="test-description">${testInfo.description}</div>
|
|
</label><br>
|
|
<button class="test-run-button" onclick="runSingleTest('fs', ${i})">Run Test</button>
|
|
</div>
|
|
</div>`);
|
|
}
|
|
|
|
$('#tests').append('<h2><label><input type="checkbox" id="kvTests-group" checked> Key Value Store</label></h2>');
|
|
for (let i = 0; i < kvTests.length; i++) {
|
|
const testInfo = getTestInfo(kvTests[i]);
|
|
$('#tests').append(`<div class="test-container" id="kvTests-container-${i}">
|
|
<div class="test-checkbox-container">
|
|
<input type="checkbox" class="test-checkbox kvTests-checkbox" id="kvTests${i}" checked>
|
|
<label for="kvTests${i}">
|
|
<div class="test-name">${testInfo.name}</div>
|
|
<div class="test-description">${testInfo.description}</div>
|
|
</label><br>
|
|
<button class="test-run-button" onclick="runSingleTest('kv', ${i})">Run Test</button>
|
|
</div>
|
|
</div>`);
|
|
}
|
|
|
|
$('#tests').append('<h2><label><input type="checkbox" id="aiTests-group" checked> AI</label></h2>');
|
|
for (let i = 0; i < aiTests.length; i++) {
|
|
const testInfo = getTestInfo(aiTests[i]);
|
|
$('#tests').append(`<div class="test-container" id="aiTests-container-${i}">
|
|
<div class="test-checkbox-container">
|
|
<input type="checkbox" class="test-checkbox aiTests-checkbox" id="aiTests${i}" checked>
|
|
<label for="aiTests${i}">
|
|
<div class="test-name">${testInfo.name}</div>
|
|
<div class="test-description">${testInfo.description}</div>
|
|
</label><br>
|
|
<button class="test-run-button" onclick="runSingleTest('ai', ${i})">Run Test</button>
|
|
</div>
|
|
</div>`);
|
|
}
|
|
|
|
// Add event listeners for group checkboxes
|
|
$('#fsTests-group').change(function() {
|
|
const isChecked = $(this).prop('checked');
|
|
$('.fsTests-checkbox').prop('checked', isChecked);
|
|
});
|
|
|
|
$('#kvTests-group').change(function() {
|
|
const isChecked = $(this).prop('checked');
|
|
$('.kvTests-checkbox').prop('checked', isChecked);
|
|
});
|
|
|
|
$('#aiTests-group').change(function() {
|
|
const isChecked = $(this).prop('checked');
|
|
$('.aiTests-checkbox').prop('checked', isChecked);
|
|
});
|
|
|
|
// Add event listeners for individual checkboxes to update group checkbox state
|
|
$(document).on('change', '.fsTests-checkbox', function() {
|
|
const totalFsTests = $('.fsTests-checkbox').length;
|
|
const checkedFsTests = $('.fsTests-checkbox:checked').length;
|
|
|
|
if (checkedFsTests === 0) {
|
|
$('#fsTests-group').prop('checked', false).prop('indeterminate', false);
|
|
} else if (checkedFsTests === totalFsTests) {
|
|
$('#fsTests-group').prop('checked', true).prop('indeterminate', false);
|
|
} else {
|
|
$('#fsTests-group').prop('checked', false).prop('indeterminate', true);
|
|
}
|
|
});
|
|
|
|
$(document).on('change', '.kvTests-checkbox', function() {
|
|
const totalKvTests = $('.kvTests-checkbox').length;
|
|
const checkedKvTests = $('.kvTests-checkbox:checked').length;
|
|
|
|
if (checkedKvTests === 0) {
|
|
$('#kvTests-group').prop('checked', false).prop('indeterminate', false);
|
|
} else if (checkedKvTests === totalKvTests) {
|
|
$('#kvTests-group').prop('checked', true).prop('indeterminate', false);
|
|
} else {
|
|
$('#kvTests-group').prop('checked', false).prop('indeterminate', true);
|
|
}
|
|
});
|
|
|
|
$(document).on('change', '.aiTests-checkbox', function() {
|
|
const totalAiTests = $('.aiTests-checkbox').length;
|
|
const checkedAiTests = $('.aiTests-checkbox:checked').length;
|
|
|
|
if (checkedAiTests === 0) {
|
|
$('#aiTests-group').prop('checked', false).prop('indeterminate', false);
|
|
} else if (checkedAiTests === totalAiTests) {
|
|
$('#aiTests-group').prop('checked', true).prop('indeterminate', false);
|
|
} else {
|
|
$('#aiTests-group').prop('checked', false).prop('indeterminate', true);
|
|
}
|
|
});
|
|
|
|
window.assert = function(condition, message) {
|
|
if (!condition) {
|
|
throw new Error(message || "Assertion failed");
|
|
}
|
|
}
|
|
|
|
async function runSingleTest(testType, index) {
|
|
const testSuites = {
|
|
'fs': fsTests,
|
|
'kv': kvTests,
|
|
'ai': aiTests
|
|
};
|
|
|
|
const tests = testSuites[testType];
|
|
const containerId = `${testType}Tests-container-${index}`;
|
|
const buttonSelector = `#${containerId} .test-run-button`;
|
|
|
|
// Disable the button and show it while running
|
|
$(buttonSelector).prop('disabled', true).text('Running...');
|
|
|
|
// Clear previous results
|
|
$(`#${containerId}`).css('background-color', '');
|
|
$(`#${containerId} pre`).remove();
|
|
|
|
try {
|
|
await executeTest(tests[index]);
|
|
// make this test's container green
|
|
$(`#${containerId}`).css('background-color', '#85e085');
|
|
} catch (e) {
|
|
const testInfo = getTestInfo(tests[index]);
|
|
console.error(`${testType.toUpperCase()} Test failed:`, testInfo.name, e);
|
|
// make this test's container red
|
|
$(`#${containerId}`).css('background-color', '#ffbfbf');
|
|
// message - show full error information including JSON details
|
|
let errorMessage = e.message || e.toString();
|
|
if (e.originalError) {
|
|
errorMessage += '\n\nOriginal Error:\n' + JSON.stringify(e.originalError, null, 2);
|
|
}
|
|
$(`#${containerId}`).append(`<pre style="color:#c00000; white-space: pre-wrap; font-size: 12px; margin: 5px 0; padding: 10px; background-color: #f8f8f8; border-radius: 3px;">${errorMessage}</pre>`);
|
|
} finally {
|
|
// Re-enable the button
|
|
$(buttonSelector).prop('disabled', false).text('Run Test');
|
|
}
|
|
}
|
|
|
|
window.runSingleTest = runSingleTest;
|
|
|
|
async function runTests() {
|
|
// Reset and initialize progress tracking
|
|
resetProgress();
|
|
testProgress.total = getSelectedTestsCount();
|
|
|
|
// Show progress panel
|
|
showProgressPanel();
|
|
updateProgressPanel();
|
|
|
|
// Clear previous test results
|
|
$('.test-container').css('background-color', '');
|
|
$('.test-container pre').remove();
|
|
|
|
// go through fsTests and run each test
|
|
for (let i = 0; i < fsTests.length; i++) {
|
|
if (document.getElementById(`fsTests${i}`).checked) {
|
|
const testInfo = getTestInfo(fsTests[i]);
|
|
testProgress.currentTest = `FileSystem: ${testInfo.name}`;
|
|
updateProgressPanel();
|
|
|
|
try{
|
|
await executeTest(fsTests[i]);
|
|
// make this test's container green
|
|
$(`#fsTests-container-${i}`).css('background-color', '#85e085');
|
|
testProgress.passed++;
|
|
} catch (e) {
|
|
console.error('FS Test failed:', testInfo.name, e);
|
|
// make this test's container red
|
|
$(`#fsTests-container-${i}`).css('background-color', '#ffbfbf');
|
|
// message - show full error information including JSON details
|
|
let errorMessage = e.message || e.toString();
|
|
if (e.originalError) {
|
|
errorMessage += '\n\nOriginal Error:\n' + JSON.stringify(e.originalError, null, 2);
|
|
}
|
|
$(`#fsTests-container-${i}`).append(`<pre style="color:#c00000; white-space: pre-wrap; font-size: 12px; margin: 5px 0; padding: 10px; background-color: #f8f8f8; border-radius: 3px;">${errorMessage}</pre>`);
|
|
testProgress.failed++;
|
|
}
|
|
|
|
testProgress.completed++;
|
|
updateProgressPanel();
|
|
|
|
// Small delay to make progress visible
|
|
await delay(100);
|
|
}
|
|
}
|
|
|
|
for (let i = 0; i < kvTests.length; i++) {
|
|
if (document.getElementById(`kvTests${i}`).checked) {
|
|
const testInfo = getTestInfo(kvTests[i]);
|
|
testProgress.currentTest = `Key-Value Store: ${testInfo.name}`;
|
|
updateProgressPanel();
|
|
|
|
try{
|
|
await executeTest(kvTests[i]);
|
|
// make this test's container green
|
|
$(`#kvTests-container-${i}`).css('background-color', '#85e085');
|
|
testProgress.passed++;
|
|
} catch (e) {
|
|
console.error('KV Test failed:', testInfo.name, e);
|
|
// make this test's container red
|
|
$(`#kvTests-container-${i}`).css('background-color', '#ff8484');
|
|
// message - show full error information including JSON details
|
|
let errorMessage = e.message || e.toString();
|
|
if (e.originalError) {
|
|
errorMessage += '\n\nOriginal Error:\n' + JSON.stringify(e.originalError, null, 2);
|
|
}
|
|
$(`#kvTests-container-${i}`).append(`<pre style="color:red; white-space: pre-wrap; font-size: 12px; margin: 5px 0; padding: 10px; background-color: #f8f8f8; border-radius: 3px;">${errorMessage}</pre>`);
|
|
testProgress.failed++;
|
|
}
|
|
|
|
testProgress.completed++;
|
|
updateProgressPanel();
|
|
|
|
// Small delay to make progress visible
|
|
await delay(100);
|
|
}
|
|
}
|
|
|
|
for (let i = 0; i < aiTests.length; i++) {
|
|
if (document.getElementById(`aiTests${i}`).checked) {
|
|
const testInfo = getTestInfo(aiTests[i]);
|
|
testProgress.currentTest = `AI: ${testInfo.name}`;
|
|
updateProgressPanel();
|
|
|
|
try{
|
|
await executeTest(aiTests[i]);
|
|
// make this test's container green
|
|
$(`#aiTests-container-${i}`).css('background-color', '#85e085');
|
|
testProgress.passed++;
|
|
} catch (e) {
|
|
console.error('AI Test failed:', testInfo.name, e);
|
|
// make this test's container red
|
|
$(`#aiTests-container-${i}`).css('background-color', '#ff8484');
|
|
// message - show full error information including JSON details
|
|
let errorMessage = e.message || e.toString();
|
|
if (e.originalError) {
|
|
errorMessage += '\n\nOriginal Error:\n' + JSON.stringify(e.originalError, null, 2);
|
|
}
|
|
$(`#aiTests-container-${i}`).append(`<pre style="color:red; white-space: pre-wrap; font-size: 12px; margin: 5px 0; padding: 10px; background-color: #f8f8f8; border-radius: 3px;">${errorMessage}</pre>`);
|
|
testProgress.failed++;
|
|
}
|
|
|
|
testProgress.completed++;
|
|
updateProgressPanel();
|
|
|
|
// Small delay to make progress visible
|
|
await delay(100);
|
|
}
|
|
}
|
|
|
|
// Show completion message
|
|
testProgress.currentTest = `Complete! ${testProgress.passed} passed, ${testProgress.failed} failed`;
|
|
updateProgressPanel();
|
|
|
|
// Stop the elapsed timer but keep panel visible
|
|
stopProgressTimer();
|
|
|
|
// Re-enable the run tests button
|
|
$('#run-tests').prop('disabled', false).text('Run Tests');
|
|
}
|
|
|
|
$('#run-tests').click(() => {
|
|
runTests();
|
|
});
|
|
|
|
// Reset results functionality
|
|
$('#reset-results').click(() => {
|
|
// Clear all test container background colors
|
|
$('.test-container').css('background-color', '');
|
|
// Remove all error message pre elements
|
|
$('.test-container pre').remove();
|
|
// Hide progress panel if it's showing
|
|
hideProgressPanel();
|
|
// Reset progress tracking
|
|
resetProgress();
|
|
});
|
|
|
|
// Master checkbox functionality
|
|
$('#master-checkbox').change(function() {
|
|
const isChecked = $(this).prop('checked');
|
|
$('.test-checkbox').prop('checked', isChecked);
|
|
$('#fsTests-group, #kvTests-group, #aiTests-group').prop('checked', isChecked);
|
|
// Update the counter display
|
|
updateMasterCheckboxState();
|
|
});
|
|
|
|
// Function to update master checkbox state
|
|
function updateMasterCheckboxState() {
|
|
const totalCheckboxes = $('.test-checkbox').length;
|
|
const checkedCheckboxes = $('.test-checkbox:checked').length;
|
|
|
|
// Update the counter display
|
|
$('#test-counter').text(`${checkedCheckboxes} / ${totalCheckboxes}`);
|
|
|
|
if (checkedCheckboxes === 0) {
|
|
$('#master-checkbox').prop('checked', false).prop('indeterminate', false);
|
|
} else if (checkedCheckboxes === totalCheckboxes) {
|
|
$('#master-checkbox').prop('checked', true).prop('indeterminate', false);
|
|
} else {
|
|
$('#master-checkbox').prop('checked', false).prop('indeterminate', true);
|
|
}
|
|
}
|
|
|
|
// Update master checkbox state when individual checkboxes change
|
|
$(document).on('change', '.test-checkbox', function() {
|
|
updateMasterCheckboxState();
|
|
});
|
|
|
|
// Update master checkbox state when group checkboxes change
|
|
$('#fsTests-group, #kvTests-group, #aiTests-group').change(function() {
|
|
updateMasterCheckboxState();
|
|
});
|
|
|
|
// Initialize the counter display
|
|
updateMasterCheckboxState();
|
|
|
|
});
|
|
|
|
</script>
|
|
</head>
|
|
<body>
|
|
|
|
<nav>
|
|
<label style="margin-left: 8px; margin-right: 10px; cursor: pointer; display: inline-flex; align-items: center;">
|
|
<input type="checkbox" id="master-checkbox" checked style="margin-right: 5px; transform: scale(1.2);">
|
|
</label>
|
|
<span id="test-counter"></span>
|
|
<div style="flex: 1; text-align: right;">
|
|
<span id="reset-results" style="margin-right: 20px; cursor: pointer; color: #666; text-decoration: underline; font-size: 14px;">Reset results</span>
|
|
<button id="run-tests" style="margin-right: 30px;">Run Tests</button>
|
|
</div>
|
|
</nav>
|
|
|
|
<div id="progress-panel">
|
|
<div class="progress-content">
|
|
<div class="progress-left">
|
|
<div class="current-test" id="current-test">Preparing tests...</div>
|
|
<div class="progress-bar-container">
|
|
<div class="progress-bar" id="progress-bar"></div>
|
|
</div>
|
|
<div class="elapsed-time" id="elapsed-time">Elapsed: 0s</div>
|
|
</div>
|
|
<div class="progress-right">
|
|
<div class="progress-stats">
|
|
<div class="progress-stat">
|
|
<div class="progress-stat-number stat-passed" id="passed-count">0</div>
|
|
<div class="progress-stat-label">Passed</div>
|
|
</div>
|
|
<div class="progress-stat">
|
|
<div class="progress-stat-number stat-failed" id="failed-count">0</div>
|
|
<div class="progress-stat-label">Failed</div>
|
|
</div>
|
|
<div class="progress-stat">
|
|
<div class="progress-stat-number stat-total" id="total-count">0</div>
|
|
<div class="progress-stat-label">Total</div>
|
|
</div>
|
|
</div>
|
|
<div class="progress-percentage" id="progress-percentage">0%</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="tests"></div>
|
|
</body>
|
|
</html> |