25 lines
2.6 KiB
HTML
25 lines
2.6 KiB
HTML
<!doctype html>
|
|
<meta charset="utf-8">
|
|
<title>ProspectOS smoke test</title>
|
|
<style>body{font:16px system-ui;padding:2rem;background:#f7f8fb;color:#172033}li{margin:.5rem 0}.pass{color:#16845b}.fail{color:#b84d55}</style>
|
|
<h1>ProspectOS static smoke test</h1><p id="summary">Running…</p><ul id="checks"></ul>
|
|
<iframe id="app" src="index.html" hidden></iframe>
|
|
<script>
|
|
const frame=document.querySelector('#app');
|
|
frame.onload=async()=>{const d=frame.contentDocument;const js=await fetch('app.js').then(r=>r.text());const checks=[
|
|
['Login screen',()=>!!d.querySelector('#loginScreen')],
|
|
['Email/password login fields',()=>!!d.querySelector('#loginEmail')&&!!d.querySelector('#loginPassword')],
|
|
['Dashboard starts protected',()=>d.querySelector('#dashboardShell').hidden],
|
|
['Logout and user display',()=>!!d.querySelector('#logoutBtn')&&!!d.querySelector('#userIdentity')],
|
|
['Explorer pagination and filters',()=>!!d.querySelector('#pageSize')&&!!d.querySelector('#nextPageBtn')&&!!d.querySelector('#websiteClassFilter')&&!!d.querySelector('#pipelineFilter')],
|
|
['Detail panel contract',()=>!!d.querySelector('#detailPanel')&&js.includes('/api/v1/businesses/${encodeURIComponent(id)}')&&js.includes('contacts')&&js.includes('evidence_timeline')&&js.includes('pipeline_stage')],
|
|
['Manual detail controls',()=>js.includes('contactForm')&&js.includes('noteForm')&&js.includes('pipelineForm')&&js.includes('verifyBtn')],
|
|
['All API requests include cookies',()=>[...js.matchAll(/fetch\([^;]+/g)].every(m=>m[0].includes("credentials:'include'"))],
|
|
['Detail writes use authenticated request helper',()=>['/contacts','/notes','/pipeline','/verify'].every(path=>js.includes(path)&&js.includes('jsonRequest'))],
|
|
['Validation and error states',()=>js.includes('Email is required.')&&js.includes('Note cannot be empty.')&&js.includes('detail-error')&&js.includes('role="alert"')],
|
|
['No hardcoded credentials or demo fallback',()=>!js.includes('demoProspects')&&!/password.{0,30}['\"][^'\"]+['\"]/.test(js)],
|
|
['Safety copy and blocked outreach preserved',()=>js.includes('disabled-action')&&js.includes('Suppressed records cannot be contacted.')&&js.includes('Review this prospect before outreach is available.')],
|
|
['No outreach/send controls',()=>!Array.from(d.querySelectorAll('button')).some(x=>/outreach|send/i.test(x.textContent)&&!x.disabled)]
|
|
];let passed=0;document.querySelector('#checks').innerHTML=checks.map(([name,test])=>{const ok=test();if(ok)passed++;return `<li class="${ok?'pass':'fail'}">${ok?'PASS':'FAIL'} — ${name}</li>`}).join('');document.querySelector('#summary').textContent=`${passed}/${checks.length} checks passed`;};
|
|
</script>
|