añadido karpathy y refactorizacion del proyecto
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tester - Test Plan Editor</title>
|
||||
<style>
|
||||
body { font-family: system-ui, -apple-system, sans-serif; background: #0b1120; color: #e2e8f0; margin: 0; padding: 20px; }
|
||||
.container { max-width: 1400px; margin: 0 auto; }
|
||||
h1 { color: #f59e0b; }
|
||||
.plan-header { background: #1e2937; padding: 16px; border-radius: 8px; margin-bottom: 20px; }
|
||||
.test-card { background: #1e2937; border: 1px solid #334155; border-radius: 8px; padding: 16px; margin-bottom: 16px; }
|
||||
.test-header { font-weight: 600; color: #f59e0b; margin-bottom: 8px; }
|
||||
textarea, select, input { background: #0f172a; border: 1px solid #334155; color: #e2e8f0; padding: 8px; border-radius: 4px; width: 100%; box-sizing: border-box; }
|
||||
.field { margin-bottom: 10px; }
|
||||
.label { font-size: 12px; color: #94a3b8; margin-bottom: 4px; display: block; }
|
||||
.status-pass { color: #4ade80; }
|
||||
.status-fail { color: #f87171; }
|
||||
.auto-save { font-size: 12px; color: #64748b; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="plan-header">
|
||||
<h1 id="planName"></h1>
|
||||
<div id="planMeta" style="font-size:13px; color:#94a3b8;"></div>
|
||||
<div class="auto-save" id="saveStatus"></div>
|
||||
</div>
|
||||
|
||||
<div id="testsContainer"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const planId = urlParams.get('plan');
|
||||
|
||||
let plan = null;
|
||||
let saveTimeout = null;
|
||||
|
||||
async function loadPlan() {
|
||||
if (!planId) {
|
||||
document.body.innerHTML = '<h1>No plan specified. Use ?plan=ID</h1>';
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await fetch(`/api/test-plans/${planId}`);
|
||||
if (!res.ok) {
|
||||
document.body.innerHTML = '<h1>Plan not found</h1>';
|
||||
return;
|
||||
}
|
||||
|
||||
plan = await res.json();
|
||||
document.getElementById('planName').textContent = plan.name;
|
||||
document.getElementById('planMeta').textContent = `Created: ${new Date(plan.createdAt).toLocaleString()} • ${plan.tests.length} tests`;
|
||||
|
||||
renderTests();
|
||||
}
|
||||
|
||||
function renderTests() {
|
||||
const container = document.getElementById('testsContainer');
|
||||
container.innerHTML = '';
|
||||
|
||||
plan.tests.forEach((test, index) => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'test-card';
|
||||
div.innerHTML = `
|
||||
<div class="test-header">${test.id}</div>
|
||||
<div><strong>${test.description}</strong></div>
|
||||
<div style="margin: 8px 0; font-size:12px; color:#94a3b8;">Group: ${test.group}</div>
|
||||
|
||||
<div class="field">
|
||||
<span class="label">Steps</span>
|
||||
<div style="font-size:12px; white-space: pre-line; background:#0f172a; padding:8px; border-radius:4px;">
|
||||
${(test.steps || []).map(s => '• ' + s).join('\n')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<span class="label">Expected Result</span>
|
||||
<textarea data-field="expectedResult" data-index="${index}">${test.expectedResult || ''}</textarea>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; gap:12px;">
|
||||
<div class="field" style="flex:1;">
|
||||
<span class="label">Severity</span>
|
||||
<select data-field="severity" data-index="${index}">
|
||||
<option ${test.severity === 'Low' ? 'selected' : ''}>Low</option>
|
||||
<option ${test.severity === 'Medium' ? 'selected' : ''}>Medium</option>
|
||||
<option ${test.severity === 'High' ? 'selected' : ''}>High</option>
|
||||
<option ${test.severity === 'Critical' ? 'selected' : ''}>Critical</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field" style="flex:1;">
|
||||
<span class="label">Status</span>
|
||||
<select data-field="testerStatus" data-index="${index}">
|
||||
<option ${test.testerStatus === 'N/A' ? 'selected' : ''}>N/A</option>
|
||||
<option ${test.testerStatus === 'Pass' ? 'selected' : ''}>Pass</option>
|
||||
<option ${test.testerStatus === 'Fail' ? 'selected' : ''}>Fail</option>
|
||||
<option ${test.testerStatus === 'Blocked' ? 'selected' : ''}>Blocked</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<span class="label">Actual Result / Comments</span>
|
||||
<textarea data-field="actualResult" data-index="${index}" style="min-height:60px;">${test.actualResult || ''}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<span class="label">Additional Comments</span>
|
||||
<textarea data-field="comments" data-index="${index}">${test.comments || ''}</textarea>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Attach auto-save listeners
|
||||
div.querySelectorAll('textarea, select').forEach(el => {
|
||||
el.addEventListener('input', () => scheduleSave(index, el.dataset.field, el.value));
|
||||
el.addEventListener('change', () => scheduleSave(index, el.dataset.field, el.value));
|
||||
});
|
||||
|
||||
container.appendChild(div);
|
||||
});
|
||||
}
|
||||
|
||||
function scheduleSave(testIndex, field, value) {
|
||||
plan.tests[testIndex][field] = value;
|
||||
|
||||
document.getElementById('saveStatus').textContent = 'Saving...';
|
||||
|
||||
clearTimeout(saveTimeout);
|
||||
saveTimeout = setTimeout(async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/test-plans/${planId}`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(plan)
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
document.getElementById('saveStatus').textContent = `Auto-saved at ${new Date().toLocaleTimeString()}`;
|
||||
setTimeout(() => {
|
||||
const el = document.getElementById('saveStatus');
|
||||
if (el) el.textContent = '';
|
||||
}, 2000);
|
||||
}
|
||||
} catch (e) {
|
||||
document.getElementById('saveStatus').textContent = 'Save failed';
|
||||
}
|
||||
}, 800);
|
||||
}
|
||||
|
||||
loadPlan();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user