extends layout block content div(class='max-w-3xl mx-auto') div(class='flex items-center justify-between mb-4') div h1(class='text-2xl font-bold') Testing URL p(class='text-sm text-gray-500 truncate max-w-xl')= job.url span#status-badge(class='text-xs px-3 py-1 rounded-full bg-yellow-100 text-yellow-800 font-semibold') Queued if error div(class='bg-red-50 border border-red-300 text-red-700 rounded-lg p-4 mb-4') strong Test failed:  = error div(class='bg-gray-900 text-green-400 rounded-xl p-4 h-96 overflow-y-auto text-xs font-mono' id='log-box') p(class='text-gray-500') Waiting for output... div(class='mt-4 text-sm text-gray-500 flex gap-4') span Browser:  strong= job.browser span Runs:  strong= job.runs span Mode:  strong= job.mobile ? 'Mobile' : 'Desktop' script. const jobId = '!{job.id}'; const logBox = document.getElementById('log-box'); const badge = document.getElementById('status-badge'); let firstLine = true; const es = new EventSource(`/status/${jobId}/stream`); es.addEventListener('log', (e) => { const d = JSON.parse(e.data); if (firstLine) { logBox.innerHTML = ''; firstLine = false; } const el = document.createElement('div'); el.className = 'log-line'; el.textContent = d.line; logBox.appendChild(el); logBox.scrollTop = logBox.scrollHeight; }); es.addEventListener('status', (e) => { const d = JSON.parse(e.data); badge.textContent = d.message; badge.className = 'text-xs px-3 py-1 rounded-full font-semibold ' + (d.phase === 'done' ? 'bg-green-100 text-green-800' : d.phase === 'error' ? 'bg-red-100 text-red-800' : d.phase === 'parsing' ? 'bg-blue-100 text-blue-800' : 'bg-yellow-100 text-yellow-800'); }); es.addEventListener('done', (e) => { es.close(); badge.textContent = 'Done! Redirecting...'; badge.className = 'text-xs px-3 py-1 rounded-full bg-green-100 text-green-800 font-semibold'; setTimeout(() => { window.location.href = `/results/${jobId}`; }, 800); }); es.addEventListener('error', (e) => { es.close(); badge.textContent = 'Error'; badge.className = 'text-xs px-3 py-1 rounded-full bg-red-100 text-red-800 font-semibold'; try { const d = JSON.parse(e.data); // Render each line of the error message separately so multi-line errors are readable const lines = d.message.split('\n'); for (const line of lines) { const el = document.createElement('div'); el.className = 'text-red-400 log-line'; el.textContent = line; logBox.appendChild(el); } logBox.scrollTop = logBox.scrollHeight; } catch {} });