skeptic-cli 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{browser-verbs-U54BZACP.mjs → browser-verbs-R7R6PK2G.mjs} +1 -1
- package/dist/{chunk-WBPZGXOC.mjs → chunk-2VGKPSCR.mjs} +1 -1
- package/dist/{daemon-M2J3L6JW.mjs → daemon-7M5HNFD7.mjs} +1 -1
- package/dist/{doctor-WRKNAK3W.mjs → doctor-Q76JEQQI.mjs} +1 -1
- package/dist/index.mjs +3 -3
- package/dist/{init-4PXSHPNW.mjs → init-6RHO2LGR.mjs} +1 -1
- package/dist/{inspect-3XFCCSUL.mjs → inspect-44KF3IPH.mjs} +1 -1
- package/dist/{observe-MHEV7OVP.mjs → observe-EDXYWK6C.mjs} +1 -1
- package/dist/{run-GW3X5ANC.mjs → run-GUWITPL4.mjs} +1 -1
- package/dist/{session-daemon-cmd-23UUK6TD.mjs → session-daemon-cmd-QHVSSKSL.mjs} +1 -1
- package/dist/skeptic.mjs +1 -1
- package/dist/worker.mjs +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {createRequire}from'node:module';import {d}from'./chunk-2ZORFJJP.mjs';import'./chunk-OHVNABCL.mjs';import {e}from'./chunk-RU7M6UGM.mjs';import {h as h$1,q as q$1,m,b}from'./chunk-2VSGDT7T.mjs';import'./chunk-7BFRKEFV.mjs';import'./chunk-IYLF56WL.mjs';import'./chunk-ZN6MI2TU.mjs';import'./chunk-MHNEFL35.mjs';import'./chunk-S3M2RTHJ.mjs';import'./chunk-2YKSIUIN.mjs';import*as O from'fs';import*as h from'net';import {spawn}from'child_process';import {fileURLToPath}from'url';import {setTimeout as setTimeout$1}from'timers/promises';/*! @license skeptic-cli — see LICENSES.md for third-party attributions */
|
|
2
2
|
createRequire(import.meta.url);
|
|
3
|
-
var w=e=>new Promise(n=>{if(process.platform!=="win32"&&!O.existsSync(e)){n(false);return}let s=h.createConnection(b(e)),r=c=>{s.removeAllListeners(),s.destroy(),n(c);},o=setTimeout(()=>r(false),800);s.on("connect",()=>{clearTimeout(o),r(true);}),s.on("error",()=>{clearTimeout(o),r(false);});}),P=()=>{let e=process.env.SKEPTIC_DAEMON_BIN;if(e)return e;let n=process.argv[1];return n||fileURLToPath(new URL("../../dist/skeptic.mjs",import.meta.url))},B=async e=>{m();let n=h$1();if(await w(n))return {ok:true};if(e.autoSpawn===false)return {ok:false,reason:"no-session-daemon"};let s=["session-daemon","--engine",e.engine,e.headed?"--headed":"--headless"],r=spawn(process.execPath,[P(),...s],{detached:true,stdio:"ignore",env:{...process.env}});r.unref(),r.on("error",()=>{});let o=Date.now()+(e.spawnTimeoutMs??15e3);for(;Date.now()<o;){if(await w(n))return {ok:true};await setTimeout$1(100);}return {ok:false,reason:"session-daemon-spawn-timeout"}},x=async(e$1,n,s,r=3e4)=>{let o=await B(s);if(!o.ok)throw new Error(`session daemon: ${o.reason}`);let c=h$1(),d=process.env.SKEPTIC_DAEMON_AUTH_TOKEN,V={engine:s.engine,...d?{authToken:d}:{}},p=await q$1(c,V);if(!p.ok)throw new Error(`session daemon handshake failed: ${p.reason??"unknown"}`);return e(c,{method:e$1,params:d?{...n,authToken:d}:n},r)};var $=e=>({engine:e.platform==="android"?"android":e.platform==="ios-sim"?"ios-sim":"chromium",headed:e.headless!==true,cliVersion:"1.0.
|
|
3
|
+
var w=e=>new Promise(n=>{if(process.platform!=="win32"&&!O.existsSync(e)){n(false);return}let s=h.createConnection(b(e)),r=c=>{s.removeAllListeners(),s.destroy(),n(c);},o=setTimeout(()=>r(false),800);s.on("connect",()=>{clearTimeout(o),r(true);}),s.on("error",()=>{clearTimeout(o),r(false);});}),P=()=>{let e=process.env.SKEPTIC_DAEMON_BIN;if(e)return e;let n=process.argv[1];return n||fileURLToPath(new URL("../../dist/skeptic.mjs",import.meta.url))},B=async e=>{m();let n=h$1();if(await w(n))return {ok:true};if(e.autoSpawn===false)return {ok:false,reason:"no-session-daemon"};let s=["session-daemon","--engine",e.engine,e.headed?"--headed":"--headless"],r=spawn(process.execPath,[P(),...s],{detached:true,stdio:"ignore",env:{...process.env}});r.unref(),r.on("error",()=>{});let o=Date.now()+(e.spawnTimeoutMs??15e3);for(;Date.now()<o;){if(await w(n))return {ok:true};await setTimeout$1(100);}return {ok:false,reason:"session-daemon-spawn-timeout"}},x=async(e$1,n,s,r=3e4)=>{let o=await B(s);if(!o.ok)throw new Error(`session daemon: ${o.reason}`);let c=h$1(),d=process.env.SKEPTIC_DAEMON_AUTH_TOKEN,V={engine:s.engine,...d?{authToken:d}:{}},p=await q$1(c,V);if(!p.ok)throw new Error(`session daemon handshake failed: ${p.reason??"unknown"}`);return e(c,{method:e$1,params:d?{...n,authToken:d}:n},r)};var $=e=>({engine:e.platform==="android"?"android":e.platform==="ios-sim"?"ios-sim":"chromium",headed:e.headless!==true,cliVersion:"1.0.1"}),i=(e,n={})=>({session:e.session??"default",...n}),t=async(e,n,s,r)=>{let o;try{o=await x(e,n,$(s));}catch(c){let d=c instanceof Error?c.message:String(c);s.json?process.stdout.write(`${JSON.stringify({success:false,error:d})}
|
|
4
4
|
`):process.stderr.write(`skeptic: ${d}
|
|
5
5
|
`),process.exitCode=3;return}if(o.error){s.json?process.stdout.write(`${JSON.stringify({success:false,error:o.error})}
|
|
6
6
|
`):process.stderr.write(`skeptic: ${o.error}
|
|
@@ -4,5 +4,5 @@ var U=class{verbose;concurrency;shardLabel;suppressFinalSummary;buffer=new Map;c
|
|
|
4
4
|
`);}},be=async(r,e)=>{try{await e();}catch(t){process.stderr.write(`[skeptic] reporter ${r} threw: ${t instanceof Error?t.message:String(t)}
|
|
5
5
|
`);}},ye=()=>{let r=new URL("./worker.mjs",import.meta.url);try{if(existsSync(fileURLToPath(r)))return r}catch{}return new URL("./worker.ts",import.meta.url)},we=r=>r.map(e=>e.id),Y=r=>({name:r.name,file:r.file,testIndex:r.ordinal}),ke=(r,e)=>r?.use.hardTimeout??e,ve=()=>{try{if(typeof _.availableParallelism=="function")return _.availableParallelism()}catch{}let r=_.cpus?.().length??1;return r>0?r:1},Re=(r,e)=>{if(r.bail||e<=1)return 1;let t=r.concurrency;if(t!==void 0&&t>=1)return Math.min(Math.max(1,Math.floor(t)),e);let n=Math.max(1,Math.ceil(ve()/2));return Math.min(n,e)},B=async(r,e,t)=>{let n=we(e),i=t.workerEntry??ye(),c=new Worker(i,{stderr:false,stdout:false}),s=[],l=new Set,o=new Map(e.map(R=>[R.id,R])),u=new Map,d=t.killGraceMs??ge,g=t.signal,m=false,S,E,M=null,T=false,C=(R=t.config.hardTimeout)=>{E&&clearTimeout(E),E=setTimeout(()=>{m=true,S=R,c.terminate().catch(()=>{process.stderr.write(`[skeptic] worker.terminate() rejected for ${r}
|
|
6
6
|
`);});},R+d);};return new Promise(R=>{let $=false,A=()=>{$=true,c.terminate().catch(()=>{});};g&&(g.aborted?A():g.addEventListener("abort",A,{once:true})),C(),c.on("message",f=>{switch(f.type){case "ready":{let p={type:"start",file:r,allowlist:n,config:t.config};c.postMessage(p);return}case "test:start":{let p=e.find(b=>b.id===f.testId),y={name:f.name,file:f.file,testIndex:f.ordinal};for(let b of t.reporters)F("onTestStart",()=>b.onTestStart(y));C(ke(p,t.config.hardTimeout));return}case "test:action":{let p=o.get(f.testId);if(!p)return;let y=Y(p),b=u.get(f.testId)??0;if(f.status==="started"){let k=b,P=k+1;u.set(f.testId,P);for(let x of t.reporters)F("onStepStart",()=>x.onStepStart?.({command:f.label,args:{}},k,P,y));return}let w=b>0?b-1:0,v=Math.max(b,w+1);u.set(f.testId,v);let I={command:f.label,args:{},status:f.status==="completed"?"passed":"failed",duration_ms:f.durationMs??0,...f.error!==void 0?{error:f.error}:{}};for(let k of t.reporters)F("onStepComplete",()=>k.onStepComplete(I,w,v,y));return}case "test:complete":{l.add(f.testId),s.push(f.result);let p={name:f.result.name,file:f.result.file,testIndex:f.ordinal};for(let y of t.reporters)F("onTestComplete",()=>y.onTestComplete(f.result,p));C(),t.bail&&f.result.status!=="passed"&&(T=true,c.terminate().catch(()=>{}));return}case "step:complete":{let p=o.get(f.testId),y=p?Y(p):{name:"(step)",file:r,testIndex:0};for(let b of t.reporters)F("onStepComplete",()=>b.onStepComplete(f.step,f.index,f.total,y));return}case "log":return;case "fatal":{let p={name:r,file:r,status:"error",duration_ms:0,steps:[{command:"spec:import",args:{file:r},status:"error",duration_ms:0,error:f.message}],artifacts:{}};s.push(p);return}case "file:complete":return}}),c.on("error",f=>{M=f,process.stderr.write(`[skeptic] worker error for ${r}: ${f.message}
|
|
7
|
-
`);}),c.on("exit",f=>{g&&g.removeEventListener("abort",A),E&&clearTimeout(E);let p=e.filter(b=>!l.has(b.id)),y=!m&&!T&&!$&&p.length>0&&(M!==null||f!==0);R({file:r,results:s,remaining:p,workerTerminated:m||y,...S!==void 0?{killTimeoutMs:S}:{},requeueAttempted:false,crashed:y,...M?{crashError:M.message}:{},aborted:$});});})},Se=async(r,e,t)=>e.length===0?{file:r,results:[],remaining:[],workerTerminated:false,requeueAttempted:true}:{...await B(r,e,t),requeueAttempted:true},N=(r,e,t)=>({name:e.name,file:r,status:"error",duration_ms:0,steps:[{command:"test",args:{name:e.name},status:"error",duration_ms:0,error:t}],artifacts:{}}),Q=async(r,e,t)=>{if(e.length===0)return [];let n=await B(r,e,t),i=[...n.results],c=t.config.retries;if(c>0&&!n.workerTerminated&&!n.aborted){let s=e.filter(l=>{let o=i.find(u=>u.file===l.file&&u.name===l.name);return o&&o.status!=="passed"});for(let l of s)for(let o=1;o<=c;o++){let d=(await B(l.file,[l],t)).results.find(m=>m.file===l.file&&m.name===l.name);if(!d)break;d.steps[0]&&(d.steps[0].warnings??=[],d.steps[0].warnings.push(`retry attempt ${o}/${c}`));let g=i.findIndex(m=>m.file===l.file&&m.name===l.name);if(g>=0&&(i[g]=d),d.status==="passed"){d.flaky=true;break}}}if(n.crashed)for(let s of n.remaining)i.push(N(r,s,`worker crashed before this test completed${n.crashError?`: ${n.crashError}`:""}`));else if(n.workerTerminated&&n.remaining.length>0){let s=n.remaining[0];i.push(N(r,s,`test killed worker (${n.killTimeoutMs??t.config.hardTimeout}ms hard ceiling)`));let l=n.remaining.slice(1);if(l.length>0){let o=await Se(r,l,t);if(i.push(...o.results),o.workerTerminated&&o.remaining.length>0){let u=o.remaining[0];i.push(N(r,u,"test killed worker twice"));for(let d of o.remaining.slice(1))i.push(N(r,d,"skipped due to upstream worker kill"));}}}return i},$e=async(r,e,t)=>{let n=new Array(r.length),i=0,c=async()=>{for(;;){if(e.signal?.aborted)return;let l=i;i+=1;let o=r[l];if(!o)return;let[u,d]=o;n[l]=await Q(u,d,e);}},s=Math.min(Math.max(1,t),r.length);return await Promise.all(Array.from({length:s},()=>c())),n.flat()},Z=async r=>{let e=performance.now(),t=[],n=[...r.partition.values()].flat(),i={tests:n.map(o=>({name:o.name,file:o.file,stepCount:0,testIndex:o.ordinal})),totalTests:n.length};for(let o of r.reporters)F("onRunStart",()=>o.onRunStart?.(i));let c=[...r.partition.entries()].filter(([,o])=>o.length>0),s=Re(r,c.length);if(s>1&&c.length>1)t.push(...await $e(c,r,s));else for(let[o,u]of c){if(r.signal?.aborted)break;let d=await Q(o,u,r);if(t.push(...d),r.bail&&t.some(g=>g.status!=="passed"))break}let l={total:t.length,passed:t.filter(o=>o.status==="passed"&&!o.skipped).length,failed:t.filter(o=>o.status!=="passed").length,skipped:t.filter(o=>o.skipped===true).length,duration_ms:Math.round(performance.now()-e),tests:t};return await Promise.all(r.reporters.map(o=>be("onRunComplete",()=>o.onRunComplete(l)))),{results:t,summary:l}};var ee=(r,e,t)=>{if(e<1)throw new Error(`partitionTests: shardCount must be >= 1, got ${e}`);let n=Array.from({length:e},()=>[]);for(let i=0;i<r.length;i++)n[i%e].push(r[i]);return n};var Te=(r,e)=>{if(!e||e.length===0)return true;let t=r.use.tags??[];return e.some(n=>t.includes(n))},xe=(r,e)=>!e||e.length===0?true:e.some(t=>r.name.includes(t)),Ee=r=>{let e=r.filter(t=>t.only);return e.length>0?e:r},Me=(r,e,t)=>Ee(r.filter(n=>Te(n,e)&&xe(n,t))),Ie=(r,e)=>{if(e.shardSplit){let{count:t,index:n}=e.shardSplit;return t<=1?r:ee(r,t)[n-1]??[]}return r},Pe=r=>{let e=new Map;for(let t of r){let n=e.get(t.file)??[];n.push(t),e.set(t.file,n);}for(let t of e.values())t.sort((n,i)=>n.ordinal-i.ordinal);return e},q=async r=>{let e=await G({patterns:r.patterns,cwd:r.cwd}),t=e.flatMap(u=>u.error?[{id:`${u.file}#discovery-error`,file:u.file,ordinal:0,name:`discovery error: ${u.file}`,skip:false,only:false,use:{}}]:u.tests),n=Me(t,r.tagFilter,r.nameFilter),i=Ie(n,r),c=Pe(i),s=new Map;for(let u of e)s.set(u.file,u);if(r.listOnly)return {manifests:e,discoveredCount:n.length,results:[],summary:{total:n.length,passed:0,failed:0,skipped:0,duration_ms:0,tests:[]}};let l={config:r.config,reporters:r.reporters,partition:c,bail:r.bail??false,...r.config.parallel!==void 0?{concurrency:r.config.parallel}:{},...r.signal!==void 0?{signal:r.signal}:{},...r.workerEntry!==void 0?{workerEntry:r.workerEntry}:{},...r.killGraceMs!==void 0?{killGraceMs:r.killGraceMs}:{}};return {...await Z(l),manifests:e,discoveredCount:n.length}},re=async(r,e)=>({manifests:await G({patterns:r,cwd:process.cwd()})});var Ce=r=>{let e=/^(\d+)[xX](\d+)$/.exec(r);if(!e)throw new Error(`--video-size: expected "<width>x<height>" (e.g. 1920x1080), got "${r}"`);let t=Number(e[1]),n=Number(e[2]),i=3840;if(!Number.isInteger(t)||!Number.isInteger(n))throw new Error(`--video-size: dimensions must be integers, got "${r}"`);if(t<1||n<1||t>i||n>i)throw new Error(`--video-size: width and height must be within [1, ${i}], got ${t}x${n}`);return {width:t,height:n}},Ae=(r,e,t)=>{let n=r.observability??false,c$1=(r.observabilityWriteSidecars??false)||n&&e.observability.defaultsForReports!=="none",s=r.device??e.browser.device,l=s?c(s):void 0,o=l?{width:l.width,height:l.height}:e.browser.viewport,u={timeout:r.timeout??e.browser.timeout,hardTimeout:r.hardTimeout??e.browser.timeout,outputDir:r.output??e.output.dir??d,envOverrides:t,observability:{forceAll:n,consoleRedaction:e.observability.consoleRedaction??true,networkCaptureLimit:e.observability.networkCaptureLimit,duplicateWindowMs:e.observability.duplicateWindowMs,consoleCaptureLimit:e.observability.consoleCaptureLimit??200,accessibilityDualEngine:n||e.observability.accessibilityDualEngine,accessibilityHtmlSnippetLimit:e.observability.accessibilityHtmlSnippetLimit,accessibilityStandard:e.observability.accessibilityStandard??"WCAG21AA",autoAccessibilityAudit:n||(e.observability.autoAccessibilityAudit??false),accessibilityMaxRulesPerImpact:e.observability.accessibilityMaxRulesPerImpact??100},artifact:{fullPageScreenshots:r.fullPageScreenshot??n??e.observability.fullPageScreenshots,blankFrameDetection:r.blankFrameDetection??(n?"fail":e.observability.blankFrameDetection??"warn"),writeSidecars:c$1},screenshotOnFailure:e.execution.screenshotOnFailure,video:r.video??false,trace:r.trace??false,har:r.har??false,headed:r.headed??!e.browser.headless,browserEngine:e.browser.engine,viewport:o,retries:r.retries??e.execution.retries};return typeof r.parallel=="number"&&(u.parallel=r.parallel),typeof r.visualSettle=="boolean"&&(u.visualSettle=r.visualSettle),(r.url??e.url)&&(u.baseUrl=r.url??e.url),s&&(u.device=s),r.videoSize&&(u.videoSize=Ce(r.videoSize)),(r.cookies??e.auth.cookies)&&(u.cookies={enabled:r.cookies??e.auth.cookies,...r.cookiesFrom?{browser:r.cookiesFrom}:{}}),r.daemon===false&&(u.noDaemon=true),typeof r.daemonIdleTimeout=="number"&&(u.daemonIdleTimeoutSeconds=r.daemonIdleTimeout),(r.platform==="android"||r.platform==="ios-sim")&&(u.platform=r.platform,r.target&&(u.target=r.target)),u},Fe=(r,e)=>{let t={...e.env};if(r.env)for(let n of r.env){let i=n.indexOf("=");i>0&&(t[n.slice(0,i)]=n.slice(i+1));}return t},Oe=async(r,e,t)=>{let n=[],i,c=new Set;for(let s of r)if(!c.has(s))switch(c.add(s),s){case "console":if(t.useInkTui){let l=await import('./ink-reporter-4EN7CRMK.mjs');i=new l.InkReporter,n.push(i);}else n.push(new U({verbose:t.verbose??false,concurrency:t.concurrency??1}));break;case "json":{let{JsonReporter:l}=await import('./json-reporter-SXWPAXRY.mjs');n.push(new l(e,{silent:t.useInkTui}));break}case "junit":{let{JUnitReporter:l}=await import('./junit-reporter-5AT3OFWV.mjs');n.push(new l(e,{silent:t.useInkTui}));break}case "html":{let{HtmlReporter:l}=await import('./html-reporter-7QHIRHEY.mjs');n.push(new l(e,{silent:t.useInkTui}));break}default:d$2.warn(`Unknown reporter format: ${s}`);}if(n.length===0)if(t.useInkTui){let s=await import('./ink-reporter-4EN7CRMK.mjs');i=new s.InkReporter,n.push(i);}else n.push(new U({verbose:t.verbose??false}));if(t.notifications?.slack){let{SlackReporter:s}=await import('./slack-reporter-EEFO66V6.mjs');n.push(new s(t.notifications.slack,t.runUrl));}if(t.notifications?.webhook){let{WebhookReporter:s}=await import('./webhook-reporter-BXJGZS2I.mjs');n.push(new s(t.notifications.webhook,t.runUrl));}return i?{reporters:n,inkReporter:i}:{reporters:n}},Le=()=>{if(process.env.SKEPTIC_RUN_URL)return process.env.SKEPTIC_RUN_URL;let r=process.env.GITHUB_SERVER_URL,e=process.env.GITHUB_REPOSITORY,t=process.env.GITHUB_RUN_ID;if(r&&e&&t)return `${r}/${e}/actions/runs/${t}`},Ue=(r,e)=>{if(r.tests.filter(n=>{let i=n.artifacts??{};return i.video||i.trace||i.perfTrace||i.accessibilityAudit||i.screenshots&&i.screenshots.length>0}).length!==0){d$2.raw(""),d$2.raw(a.bold(" Artifacts"));for(let[n,i]of [["Report",O.join(e,"report.html")],["JSON",O.join(e,"results.json")],["JUnit",O.join(e,"junit.xml")]])te.existsSync(i)&&d$2.raw(` ${a.dim(n.padEnd(11))} ${a.cyan(i)}`);}},_e=r=>{d$2.raw(""),d$2.raw(a.bold(` ${a$1} Results`)),d$2.raw(a.dim(" "+"-".repeat(40)));let e=[];r.passed>0&&e.push(a.green(`${r.passed} passed`)),r.failed>0&&e.push(a.red(`${r.failed} failed`)),e.push(`${r.total} total`),d$2.raw(` ${e.join(a.dim(", "))}`),d$2.raw(` ${a.dim(`Duration: ${je(r.duration_ms)}`)}`);},je=r=>r<1e3?`${Math.round(r)}ms`:`${(r/1e3).toFixed(2)}s`,Ne=(r,e,t)=>e.watch||e.ci||!e.forceTui||t||process.env.SKEPTIC_DISABLE_INK_TUI==="1"||process.env.TERM==="dumb"||!process.stdout.isTTY||!process.stdin.isTTY?false:r.includes("console"),De=r=>r.includes("console")?r:["console",...r],We=r=>r.includes("json")?r:[...r,"json"],Ge=(r,e,t)=>r?130:e.total===0?t?.active&&t.discoveredTestCount>0?0:1:e.failed>0?1:0,gr=async(r,e)=>{e.verbose&&a$2("debug");let t=a$3(),n=e.ci??t.isCI,i=d$1({configPath:e.config,overrides:{}}),c=Fe(e,i),s=r&&r.length>0?r:i.tests,l=e.output??i.output.dir??d;if(e.list){let{manifests:w}=await re(s),v=0,I=0;for(let k of w){let P=O.relative(process.cwd(),k.file);if(k.error){v+=1,d$2.warn(` ${a.red("\u2717")} ${P} \u2014 ${k.error.message}`);continue}I+=k.tests.length,d$2.raw(` ${a.cyan(P)} (${k.tests.length} test${k.tests.length===1?"":"s"})`);for(let x of k.tests){let ne=x.skip?a.yellow(" [skip]"):x.only?a.green(" [only]"):"";d$2.raw(` ${a.dim(`#${x.ordinal}`)} ${x.name}${ne}`);}}v>0?(d$2.error(`${v} spec file${v===1?"":"s"} failed to load during discovery.`),process.exitCode=1):I===0&&(d$2.error(`No tests found matching ${Array.isArray(s)?s.join(", "):s}`),process.exitCode=1);return}e.shardSplit!==void 0&&e.shardAll!==void 0&&(console.error("--shard-split and --shard-all are mutually exclusive."),process.exit(2));let o=We(e.reporter??i.output.reporters),u=e.forceTui?De(o):o,d$3=Ne(u,e,n),g=Ae(e,i,c);n&&(g.headed=false);let[{reporters:m,inkReporter:S},E]=await Promise.all([Oe(u,l,{verbose:e.verbose??i.output.verbose,concurrency:e.parallel??i.execution.parallel??1,notifications:i.notifications,runUrl:Le(),useInkTui:d$3}),e.platform==="android"||e.platform==="ios-sim"?Promise.resolve(false):b(process.argv,{engine:g.browserEngine,headed:g.headed,cliVersion:"1.0.0",noDaemon:e.daemon===false,...typeof e.daemonIdleTimeout=="number"?{idleTimeoutSeconds:e.daemonIdleTimeout}:{}})]);(e.platform==="android"||e.platform==="ios-sim")&&(g.noDaemon=true),!E&&e.daemon!==false&&(g.noDaemon=true);let M=new AbortController,T=false,C=()=>{T&&process.exit(130),T=true,d$2.warn(`
|
|
7
|
+
`);}),c.on("exit",f=>{g&&g.removeEventListener("abort",A),E&&clearTimeout(E);let p=e.filter(b=>!l.has(b.id)),y=!m&&!T&&!$&&p.length>0&&(M!==null||f!==0);R({file:r,results:s,remaining:p,workerTerminated:m||y,...S!==void 0?{killTimeoutMs:S}:{},requeueAttempted:false,crashed:y,...M?{crashError:M.message}:{},aborted:$});});})},Se=async(r,e,t)=>e.length===0?{file:r,results:[],remaining:[],workerTerminated:false,requeueAttempted:true}:{...await B(r,e,t),requeueAttempted:true},N=(r,e,t)=>({name:e.name,file:r,status:"error",duration_ms:0,steps:[{command:"test",args:{name:e.name},status:"error",duration_ms:0,error:t}],artifacts:{}}),Q=async(r,e,t)=>{if(e.length===0)return [];let n=await B(r,e,t),i=[...n.results],c=t.config.retries;if(c>0&&!n.workerTerminated&&!n.aborted){let s=e.filter(l=>{let o=i.find(u=>u.file===l.file&&u.name===l.name);return o&&o.status!=="passed"});for(let l of s)for(let o=1;o<=c;o++){let d=(await B(l.file,[l],t)).results.find(m=>m.file===l.file&&m.name===l.name);if(!d)break;d.steps[0]&&(d.steps[0].warnings??=[],d.steps[0].warnings.push(`retry attempt ${o}/${c}`));let g=i.findIndex(m=>m.file===l.file&&m.name===l.name);if(g>=0&&(i[g]=d),d.status==="passed"){d.flaky=true;break}}}if(n.crashed)for(let s of n.remaining)i.push(N(r,s,`worker crashed before this test completed${n.crashError?`: ${n.crashError}`:""}`));else if(n.workerTerminated&&n.remaining.length>0){let s=n.remaining[0];i.push(N(r,s,`test killed worker (${n.killTimeoutMs??t.config.hardTimeout}ms hard ceiling)`));let l=n.remaining.slice(1);if(l.length>0){let o=await Se(r,l,t);if(i.push(...o.results),o.workerTerminated&&o.remaining.length>0){let u=o.remaining[0];i.push(N(r,u,"test killed worker twice"));for(let d of o.remaining.slice(1))i.push(N(r,d,"skipped due to upstream worker kill"));}}}return i},$e=async(r,e,t)=>{let n=new Array(r.length),i=0,c=async()=>{for(;;){if(e.signal?.aborted)return;let l=i;i+=1;let o=r[l];if(!o)return;let[u,d]=o;n[l]=await Q(u,d,e);}},s=Math.min(Math.max(1,t),r.length);return await Promise.all(Array.from({length:s},()=>c())),n.flat()},Z=async r=>{let e=performance.now(),t=[],n=[...r.partition.values()].flat(),i={tests:n.map(o=>({name:o.name,file:o.file,stepCount:0,testIndex:o.ordinal})),totalTests:n.length};for(let o of r.reporters)F("onRunStart",()=>o.onRunStart?.(i));let c=[...r.partition.entries()].filter(([,o])=>o.length>0),s=Re(r,c.length);if(s>1&&c.length>1)t.push(...await $e(c,r,s));else for(let[o,u]of c){if(r.signal?.aborted)break;let d=await Q(o,u,r);if(t.push(...d),r.bail&&t.some(g=>g.status!=="passed"))break}let l={total:t.length,passed:t.filter(o=>o.status==="passed"&&!o.skipped).length,failed:t.filter(o=>o.status!=="passed").length,skipped:t.filter(o=>o.skipped===true).length,duration_ms:Math.round(performance.now()-e),tests:t};return await Promise.all(r.reporters.map(o=>be("onRunComplete",()=>o.onRunComplete(l)))),{results:t,summary:l}};var ee=(r,e,t)=>{if(e<1)throw new Error(`partitionTests: shardCount must be >= 1, got ${e}`);let n=Array.from({length:e},()=>[]);for(let i=0;i<r.length;i++)n[i%e].push(r[i]);return n};var Te=(r,e)=>{if(!e||e.length===0)return true;let t=r.use.tags??[];return e.some(n=>t.includes(n))},xe=(r,e)=>!e||e.length===0?true:e.some(t=>r.name.includes(t)),Ee=r=>{let e=r.filter(t=>t.only);return e.length>0?e:r},Me=(r,e,t)=>Ee(r.filter(n=>Te(n,e)&&xe(n,t))),Ie=(r,e)=>{if(e.shardSplit){let{count:t,index:n}=e.shardSplit;return t<=1?r:ee(r,t)[n-1]??[]}return r},Pe=r=>{let e=new Map;for(let t of r){let n=e.get(t.file)??[];n.push(t),e.set(t.file,n);}for(let t of e.values())t.sort((n,i)=>n.ordinal-i.ordinal);return e},q=async r=>{let e=await G({patterns:r.patterns,cwd:r.cwd}),t=e.flatMap(u=>u.error?[{id:`${u.file}#discovery-error`,file:u.file,ordinal:0,name:`discovery error: ${u.file}`,skip:false,only:false,use:{}}]:u.tests),n=Me(t,r.tagFilter,r.nameFilter),i=Ie(n,r),c=Pe(i),s=new Map;for(let u of e)s.set(u.file,u);if(r.listOnly)return {manifests:e,discoveredCount:n.length,results:[],summary:{total:n.length,passed:0,failed:0,skipped:0,duration_ms:0,tests:[]}};let l={config:r.config,reporters:r.reporters,partition:c,bail:r.bail??false,...r.config.parallel!==void 0?{concurrency:r.config.parallel}:{},...r.signal!==void 0?{signal:r.signal}:{},...r.workerEntry!==void 0?{workerEntry:r.workerEntry}:{},...r.killGraceMs!==void 0?{killGraceMs:r.killGraceMs}:{}};return {...await Z(l),manifests:e,discoveredCount:n.length}},re=async(r,e)=>({manifests:await G({patterns:r,cwd:process.cwd()})});var Ce=r=>{let e=/^(\d+)[xX](\d+)$/.exec(r);if(!e)throw new Error(`--video-size: expected "<width>x<height>" (e.g. 1920x1080), got "${r}"`);let t=Number(e[1]),n=Number(e[2]),i=3840;if(!Number.isInteger(t)||!Number.isInteger(n))throw new Error(`--video-size: dimensions must be integers, got "${r}"`);if(t<1||n<1||t>i||n>i)throw new Error(`--video-size: width and height must be within [1, ${i}], got ${t}x${n}`);return {width:t,height:n}},Ae=(r,e,t)=>{let n=r.observability??false,c$1=(r.observabilityWriteSidecars??false)||n&&e.observability.defaultsForReports!=="none",s=r.device??e.browser.device,l=s?c(s):void 0,o=l?{width:l.width,height:l.height}:e.browser.viewport,u={timeout:r.timeout??e.browser.timeout,hardTimeout:r.hardTimeout??e.browser.timeout,outputDir:r.output??e.output.dir??d,envOverrides:t,observability:{forceAll:n,consoleRedaction:e.observability.consoleRedaction??true,networkCaptureLimit:e.observability.networkCaptureLimit,duplicateWindowMs:e.observability.duplicateWindowMs,consoleCaptureLimit:e.observability.consoleCaptureLimit??200,accessibilityDualEngine:n||e.observability.accessibilityDualEngine,accessibilityHtmlSnippetLimit:e.observability.accessibilityHtmlSnippetLimit,accessibilityStandard:e.observability.accessibilityStandard??"WCAG21AA",autoAccessibilityAudit:n||(e.observability.autoAccessibilityAudit??false),accessibilityMaxRulesPerImpact:e.observability.accessibilityMaxRulesPerImpact??100},artifact:{fullPageScreenshots:r.fullPageScreenshot??n??e.observability.fullPageScreenshots,blankFrameDetection:r.blankFrameDetection??(n?"fail":e.observability.blankFrameDetection??"warn"),writeSidecars:c$1},screenshotOnFailure:e.execution.screenshotOnFailure,video:r.video??false,trace:r.trace??false,har:r.har??false,headed:r.headed??!e.browser.headless,browserEngine:e.browser.engine,viewport:o,retries:r.retries??e.execution.retries};return typeof r.parallel=="number"&&(u.parallel=r.parallel),typeof r.visualSettle=="boolean"&&(u.visualSettle=r.visualSettle),(r.url??e.url)&&(u.baseUrl=r.url??e.url),s&&(u.device=s),r.videoSize&&(u.videoSize=Ce(r.videoSize)),(r.cookies??e.auth.cookies)&&(u.cookies={enabled:r.cookies??e.auth.cookies,...r.cookiesFrom?{browser:r.cookiesFrom}:{}}),r.daemon===false&&(u.noDaemon=true),typeof r.daemonIdleTimeout=="number"&&(u.daemonIdleTimeoutSeconds=r.daemonIdleTimeout),(r.platform==="android"||r.platform==="ios-sim")&&(u.platform=r.platform,r.target&&(u.target=r.target)),u},Fe=(r,e)=>{let t={...e.env};if(r.env)for(let n of r.env){let i=n.indexOf("=");i>0&&(t[n.slice(0,i)]=n.slice(i+1));}return t},Oe=async(r,e,t)=>{let n=[],i,c=new Set;for(let s of r)if(!c.has(s))switch(c.add(s),s){case "console":if(t.useInkTui){let l=await import('./ink-reporter-4EN7CRMK.mjs');i=new l.InkReporter,n.push(i);}else n.push(new U({verbose:t.verbose??false,concurrency:t.concurrency??1}));break;case "json":{let{JsonReporter:l}=await import('./json-reporter-SXWPAXRY.mjs');n.push(new l(e,{silent:t.useInkTui}));break}case "junit":{let{JUnitReporter:l}=await import('./junit-reporter-5AT3OFWV.mjs');n.push(new l(e,{silent:t.useInkTui}));break}case "html":{let{HtmlReporter:l}=await import('./html-reporter-7QHIRHEY.mjs');n.push(new l(e,{silent:t.useInkTui}));break}default:d$2.warn(`Unknown reporter format: ${s}`);}if(n.length===0)if(t.useInkTui){let s=await import('./ink-reporter-4EN7CRMK.mjs');i=new s.InkReporter,n.push(i);}else n.push(new U({verbose:t.verbose??false}));if(t.notifications?.slack){let{SlackReporter:s}=await import('./slack-reporter-EEFO66V6.mjs');n.push(new s(t.notifications.slack,t.runUrl));}if(t.notifications?.webhook){let{WebhookReporter:s}=await import('./webhook-reporter-BXJGZS2I.mjs');n.push(new s(t.notifications.webhook,t.runUrl));}return i?{reporters:n,inkReporter:i}:{reporters:n}},Le=()=>{if(process.env.SKEPTIC_RUN_URL)return process.env.SKEPTIC_RUN_URL;let r=process.env.GITHUB_SERVER_URL,e=process.env.GITHUB_REPOSITORY,t=process.env.GITHUB_RUN_ID;if(r&&e&&t)return `${r}/${e}/actions/runs/${t}`},Ue=(r,e)=>{if(r.tests.filter(n=>{let i=n.artifacts??{};return i.video||i.trace||i.perfTrace||i.accessibilityAudit||i.screenshots&&i.screenshots.length>0}).length!==0){d$2.raw(""),d$2.raw(a.bold(" Artifacts"));for(let[n,i]of [["Report",O.join(e,"report.html")],["JSON",O.join(e,"results.json")],["JUnit",O.join(e,"junit.xml")]])te.existsSync(i)&&d$2.raw(` ${a.dim(n.padEnd(11))} ${a.cyan(i)}`);}},_e=r=>{d$2.raw(""),d$2.raw(a.bold(` ${a$1} Results`)),d$2.raw(a.dim(" "+"-".repeat(40)));let e=[];r.passed>0&&e.push(a.green(`${r.passed} passed`)),r.failed>0&&e.push(a.red(`${r.failed} failed`)),e.push(`${r.total} total`),d$2.raw(` ${e.join(a.dim(", "))}`),d$2.raw(` ${a.dim(`Duration: ${je(r.duration_ms)}`)}`);},je=r=>r<1e3?`${Math.round(r)}ms`:`${(r/1e3).toFixed(2)}s`,Ne=(r,e,t)=>e.watch||e.ci||!e.forceTui||t||process.env.SKEPTIC_DISABLE_INK_TUI==="1"||process.env.TERM==="dumb"||!process.stdout.isTTY||!process.stdin.isTTY?false:r.includes("console"),De=r=>r.includes("console")?r:["console",...r],We=r=>r.includes("json")?r:[...r,"json"],Ge=(r,e,t)=>r?130:e.total===0?t?.active&&t.discoveredTestCount>0?0:1:e.failed>0?1:0,gr=async(r,e)=>{e.verbose&&a$2("debug");let t=a$3(),n=e.ci??t.isCI,i=d$1({configPath:e.config,overrides:{}}),c=Fe(e,i),s=r&&r.length>0?r:i.tests,l=e.output??i.output.dir??d;if(e.list){let{manifests:w}=await re(s),v=0,I=0;for(let k of w){let P=O.relative(process.cwd(),k.file);if(k.error){v+=1,d$2.warn(` ${a.red("\u2717")} ${P} \u2014 ${k.error.message}`);continue}I+=k.tests.length,d$2.raw(` ${a.cyan(P)} (${k.tests.length} test${k.tests.length===1?"":"s"})`);for(let x of k.tests){let ne=x.skip?a.yellow(" [skip]"):x.only?a.green(" [only]"):"";d$2.raw(` ${a.dim(`#${x.ordinal}`)} ${x.name}${ne}`);}}v>0?(d$2.error(`${v} spec file${v===1?"":"s"} failed to load during discovery.`),process.exitCode=1):I===0&&(d$2.error(`No tests found matching ${Array.isArray(s)?s.join(", "):s}`),process.exitCode=1);return}e.shardSplit!==void 0&&e.shardAll!==void 0&&(console.error("--shard-split and --shard-all are mutually exclusive."),process.exit(2));let o=We(e.reporter??i.output.reporters),u=e.forceTui?De(o):o,d$3=Ne(u,e,n),g=Ae(e,i,c);n&&(g.headed=false);let[{reporters:m,inkReporter:S},E]=await Promise.all([Oe(u,l,{verbose:e.verbose??i.output.verbose,concurrency:e.parallel??i.execution.parallel??1,notifications:i.notifications,runUrl:Le(),useInkTui:d$3}),e.platform==="android"||e.platform==="ios-sim"?Promise.resolve(false):b(process.argv,{engine:g.browserEngine,headed:g.headed,cliVersion:"1.0.1",noDaemon:e.daemon===false,...typeof e.daemonIdleTimeout=="number"?{idleTimeoutSeconds:e.daemonIdleTimeout}:{}})]);(e.platform==="android"||e.platform==="ios-sim")&&(g.noDaemon=true),!E&&e.daemon!==false&&(g.noDaemon=true);let M=new AbortController,T=false,C=()=>{T&&process.exit(130),T=true,d$2.warn(`
|
|
8
8
|
Interrupted \u2014 stopping workers and writing partial results\u2026`),M.abort();};process.on("SIGINT",C);let R=e.shardIndex??Number(process.env.SKEPTIC_SHARD_INDEX??""),$=Number.isFinite(R)&&R>0?R:1;(e.shardSplit!==void 0||e.shardAll!==void 0)&&(g.shardId=$);let A={patterns:s,reporters:m,config:g,bail:e.bail??i.execution.bail,signal:M.signal,...e.tag?{tagFilter:e.tag}:{},...e.grep?{nameFilter:[e.grep]}:{},...e.shardSplit!==void 0?{shardSplit:{count:e.shardSplit,index:$}}:{},...e.shardAll!==void 0?{shardAll:{count:e.shardAll,index:$}}:{}},f;if(S){let{renderRunTui:w}=await import('./render-MHOBDOSP.mjs');f=w(S,{onAbort:()=>{f?.unmount(),process.exit(130);},onQuit:()=>{f?.unmount();},alternateScreen:process.env.SKEPTIC_TUI_ALT_SCREEN!=="0"});}else d$2.info(`${a$1} \u2014 running ${a.cyan(Array.isArray(s)?s.join(", "):s)}`);let p=await q(A).finally(()=>{process.removeListener("SIGINT",C);});f&&(T?f.unmount():await f.waitUntilExit(),_e(p.summary)),Ue(p.summary,l);let y=e.shardSplit!==void 0||e.shardAll!==void 0,b$1=p.discoveredCount;if(!T&&p.summary.total===0)if(y&&b$1>0){let w=e.shardSplit??e.shardAll,v=`${b$1} test${b$1===1?"":"s"} total across shards`;w!==void 0&&$>w?d$2.info(`shard index ${$} is out of range for ${w} shard${w===1?"":"s"}; nothing to run (${v}).`):d$2.info(`shard ${$}/${w} has no tests (${v}).`);}else d$2.error(`No tests found matching ${Array.isArray(s)?s.join(", "):s}`);if(process.exitCode=Ge(T,p.summary,{active:y,discoveredTestCount:b$1}),e.watch&&!n&&!T){let{startWatching:w}=await import('./watch-A7ZLUYR2.mjs'),v=Array.isArray(s)?s:[s];d$2.info(a.dim("Watching for changes... (Ctrl+C to exit)"));let I=Promise.resolve(),k=await w({patterns:v,onChange:async P=>{d$2.info(`File changed: ${a.cyan(P)}`),await I,I=q(A).then(x=>{process.exitCode=x.summary.failed>0?1:0;});}});process.on("SIGINT",()=>{k.close(),process.exit(process.exitCode??0);}),await new Promise(()=>{});}};export{U as a,Ce as b,Ae as c,We as d,Ge as e,gr as f};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {createRequire}from'node:module';import {c,a}from'./chunk-IXBYLSGB.mjs';import {e}from'./chunk-RU7M6UGM.mjs';import {c as c$1,g,d as d$1}from'./chunk-2VSGDT7T.mjs';import'./chunk-IYLF56WL.mjs';import {d}from'./chunk-ZN6MI2TU.mjs';import'./chunk-MHNEFL35.mjs';import'./chunk-S3M2RTHJ.mjs';import'./chunk-2YKSIUIN.mjs';import*as r from'fs';import'net';/*! @license skeptic-cli — see LICENSES.md for third-party attributions */
|
|
2
2
|
createRequire(import.meta.url);
|
|
3
|
-
var p=new Set(["chromium","firefox","webkit"]),E=async o=>{let e=o.engine??"chromium";if(!p.has(e)){d.error(`daemon start: unknown engine "${e}" (expected chromium|firefox|webkit)`),process.exitCode=2;return}try{let t=await c({engine:e,headed:o.headed===!0,cliVersion:"1.0.
|
|
3
|
+
var p=new Set(["chromium","firefox","webkit"]),E=async o=>{let e=o.engine??"chromium";if(!p.has(e)){d.error(`daemon start: unknown engine "${e}" (expected chromium|firefox|webkit)`),process.exitCode=2;return}try{let t=await c({engine:e,headed:o.headed===!0,cliVersion:"1.0.1",...typeof o.daemonIdleTimeout=="number"?{idleTimeoutSeconds:o.daemonIdleTimeout}:{}});d.info(`[skeptic daemon] listening at ${t.socket.socketPath} (engine=${t.state.engine} headed=${t.state.headed} pw=${t.state.playwrightVersion} cli=${t.state.cliVersion})`),await new Promise(()=>{});}catch(t){d.error(`daemon start failed: ${t instanceof Error?t.message:String(t)}`),process.exitCode=1;}},x=async()=>{let o=c$1();if(!r.existsSync(o)){let e=f();if(e&&a(e)){try{process.kill(e,"SIGTERM"),d.info(`[skeptic daemon] sent SIGTERM to PID ${e}`);}catch(t){d.warn(`daemon stop: kill failed: ${t instanceof Error?t.message:String(t)}`);}return}d.info("[skeptic daemon] not running");return}try{await e(o,{method:"daemon.shutdown"},1500),d.info("[skeptic daemon] shutdown requested");}catch(e){d.warn(`daemon stop: rpc failed: ${e instanceof Error?e.message:String(e)}`);}},D=async()=>{let o=c$1();if(!r.existsSync(o)){d.info("[skeptic daemon] not running");return}try{let e$1=await e(o,{method:"daemon.status"},1500);if(e$1.error){d.warn(`daemon status: ${e$1.error}`);return}let t=e$1.result,i=Math.round(t.uptimeMs/1e3);d.raw(`[skeptic daemon] running \u2014 engine=${t.engine} headed=${t.headed} clients=${t.clients} uptime=${i}s cli=${t.cliVersion} pw=${t.playwrightVersion}`);}catch(e){d.warn(`daemon status: rpc failed: ${e instanceof Error?e.message:String(e)}`);}},I=async o=>{let e=g();if(!r.existsSync(e)){d.info(`[skeptic daemon] no log at ${e}`);return}let t=o.lines??200;try{let c=r.readFileSync(e,"utf8").split(`
|
|
4
4
|
`).slice(-t).join(`
|
|
5
5
|
`);process.stdout.write(c),c.endsWith(`
|
|
6
6
|
`)||process.stdout.write(`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import {createRequire}from'node:module';import {a as a$2}from'./chunk-IXBYLSGB.mjs';import {a as a$3}from'./chunk-QICYK6XT.mjs';import {c}from'./chunk-CWNYWHJ2.mjs';import'./chunk-6U6H22OR.mjs';import {a,m,d as d$1,f as f$1,e,g,c as c$1,i,k,j,h as h$1}from'./chunk-2VSGDT7T.mjs';import {a as a$1}from'./chunk-IYLF56WL.mjs';import {d as d$2}from'./chunk-ZN6MI2TU.mjs';import {d,a as a$4}from'./chunk-MHNEFL35.mjs';import'./chunk-S3M2RTHJ.mjs';import'./chunk-2YKSIUIN.mjs';import*as f from'fs';import*as te from'os';import*as h from'path';import {execFile}from'child_process';import {createRequire as createRequire$1}from'module';import'crypto';import'fs/promises';/*! @license skeptic-cli — see LICENSES.md for third-party attributions */
|
|
2
2
|
createRequire(import.meta.url);
|
|
3
|
-
var se=16e3,ie=new Set(["Locator","ElementHandle","JSHandle","Frame","Page","BrowserContext","Browser","CDPSession"]),L=e=>{try{return String(e)}catch{return "[unserializable]"}},z=(e,n={})=>{let r=new WeakSet,i=n.maxStringLength??se,a=n.spaces??2;return JSON.stringify(e,(u,t)=>{if(t===void 0)return;if(t===null)return null;switch(typeof t){case "bigint":return `${t}n`;case "function":return `[Function: ${t.name||"anonymous"}]`;case "symbol":return L(t);case "string":return t.length>i?`${t.slice(0,i)}... [truncated ${t.length-i} chars]`:t;case "object":break;default:return t}let d=t;if(r.has(d))return "[Circular]";if(r.add(d),Buffer.isBuffer(t))return `[Buffer: ${t.length} bytes]`;if(t instanceof RegExp)return L(t);if(t instanceof Error)return {error:t.name,message:t.message,stack:t.stack};if(t instanceof Map)return Array.from(t.entries());if(t instanceof Set)return Array.from(t.values());let m=t.constructor?.name;return typeof m=="string"&&ie.has(m)?`[${m}: ${L(t)}]`:t},a)};var le=createRequire$1(import.meta.url),o=(e,n,r,i,a,u)=>{e.push({id:n,status:r,title:i,detail:a,...u?{data:u}:{}});},Z=(e,n)=>{try{if(!f.existsSync(e)){if(!n)return {ok:!1,detail:"directory does not exist"};f.mkdirSync(e,{recursive:!0});}return f.accessSync(e,f.constants.W_OK),{ok:!0,detail:"writable"}}catch(r){return {ok:false,detail:r instanceof Error?r.message:String(r)}}},Y=(e,n)=>{try{return le.resolve(n??e),!0}catch{return false}},p=e=>{try{return f.readFileSync(e,"utf-8").split(/\r?\n/,1)[0]??null}catch{return null}},fe=()=>{let e=process.env.ANDROID_HOME??process.env.ANDROID_SDK_ROOT;return e?h.join(e,"platform-tools","adb"):"adb"},ee=(e,n,r=4e3)=>new Promise(i=>{execFile(e,n,{timeout:r},(a,u,t)=>{let d=`${u??""}${t??""}`.split(/\r?\n/).find(m=>m.trim())??"";if(a){i({ok:false,line:d||(a instanceof Error?a.message:String(a))});return}i({ok:true,line:d});});}),ue=async(e$1={})=>{let n=h.resolve(e$1.cwd??process.cwd()),r=[];o(r,"runtime","info","Runtime","Node and OS detected",{node:process.version,platform:`${process.platform}-${process.arch}`,home:te.homedir()});let i$1=null;try{i$1=c({searchCwd:n}),o(r,"config","pass","Config",i$1.configPath?`loaded ${i$1.configPath}`:"no config found; using defaults",{configPath:i$1.configPath,tests:i$1.config.tests,browser:i$1.config.browser.engine});}catch(s){o(r,"config","fail","Config",s instanceof Error?s.message:String(s));}let a$5=i$1?.config,u=a(),t=Z(u,!!e$1.fix);o(r,"home-dir",t.ok?"pass":"warn","Home Directory",`${u}: ${t.detail}${e$1.fix?" (fix enabled)":""}`),e$1.fix&&t.ok&&m();let d$2=h.resolve(n,a$5?.output.dir??d),m$1=Z(d$2,!!e$1.fix);o(r,"output-dir",m$1.ok?"pass":"warn","Output Directory",`${d$2}: ${m$1.detail}`),o(r,"axe-core","pass","axe-core","bundled into skeptic-cli; accessibility audits can run without a project-level @axe-core/playwright install");let N=Y("accessibility-checker-engine","accessibility-checker-engine/ace.js"),B=a$5?.observability.accessibilityDualEngine===true;o(r,"ibm-equal-access",N?"pass":B?"warn":"info","IBM Equal Access",N?"installed":B?"optional dependency missing; dual-engine accessibility will fall back to axe-core":"not installed; only required when observability.accessibilityDualEngine is enabled");let I=Y("better-sqlite3"),q=a$5?.auth.cookies===true;o(r,"better-sqlite3",I?"pass":q?"warn":"info","Cookie SQLite Reader",I?"installed":q?"optional dependency missing; Chromium/Firefox cookie extraction may be limited":"not installed; only required when auth.cookies is enabled");try{let s=await a$1();for(let c of ["chromium","firefox","webkit"])try{let l=s[c].executablePath();o(r,`playwright-${c}`,f.existsSync(l)?"pass":"warn",`Playwright ${c}`,f.existsSync(l)?`browser executable found at ${l}`:`browser executable not found at ${l}; run skeptic browsers install ${c}`,{executablePath:l});}catch(l){o(r,`playwright-${c}`,"warn",`Playwright ${c}`,l instanceof Error?l.message:String(l));}if(!e$1.quick&&a$5)try{await(await s[a$5.browser.engine].launch({headless:a$5.browser.headless})).close(),o(r,"playwright-launch","pass","Browser Launch",`${a$5.browser.engine} launched and closed successfully`);}catch(c){o(r,"playwright-launch","fail","Browser Launch",c instanceof Error?c.message:String(c));}}catch(s){o(r,"playwright","fail","Playwright",s instanceof Error?s.message:String(s));}let P=d$1(),w=p(P),b=w?Number(w):null,T=b!==null&&Number.isFinite(b)&&a$2(b);o(r,"daemon",T?"pass":w?"warn":"info","Daemon",T?`running at PID ${b}`:w?`stale or inaccessible PID sidecar at ${P}`:"not running",{socketPath:c$1(),pidPath:P,versionPath:e(),enginePath:f$1(),logPath:g(),version:p(e()),engine:p(f$1())});let $=i(),y=p($),k$1=y?Number(y):null,F=k$1!==null&&Number.isFinite(k$1)&&a$2(k$1);o(r,"session-daemon",F?"pass":y?"warn":"info","Session Daemon",F?`running at PID ${k$1}`:y?`stale or inaccessible PID sidecar at ${$}`:"not running",{socketPath:h$1(),pidPath:$,versionPath:j(),enginePath:k(),version:p(j()),engine:p(k())});let S=a$3();o(r,"cookies",S.length>0?"pass":"warn","Cookie Profiles",S.length>0?`detected ${S.length} supported browser profile(s)`:"no supported browser profiles detected",{browsers:S.map(s=>({browser:s.browser,profilePath:s.profilePath}))});let D=fe(),x=await ee(D,["version"]);if(o(r,"adb",x.ok?"pass":"info","Android adb",x.ok?`${x.line||"adb available"} (${D})`:`adb not found (${D}); install Android platform-tools or set ANDROID_HOME to enable Android (mobile) QA`,{adbPath:D}),process.platform==="darwin"){let{resolveDeveloperDir:s}=await import('./ios-tools-WK66CQ7Q.mjs'),c=s();o(r,"simctl",c?"pass":"info","iOS simctl",c?`full Xcode found (${c})`:"no full Xcode found; --platform ios-sim needs Xcode (Command Line Tools lack simctl)");let l=await ee("axe",["--version"]);o(r,"axe",l.ok?"pass":"info","iOS axe",l.ok?`axe ${l.line||"available"} (--platform ios-sim)`:"axe not installed; --platform ios-sim needs it \u2014 `brew install cameroncooke/axe/axe`");}let j$1={pass:0,warn:0,fail:0,info:0};for(let s of r)j$1[s.status]+=1;return {product:a$4,version:"1.0.
|
|
3
|
+
var se=16e3,ie=new Set(["Locator","ElementHandle","JSHandle","Frame","Page","BrowserContext","Browser","CDPSession"]),L=e=>{try{return String(e)}catch{return "[unserializable]"}},z=(e,n={})=>{let r=new WeakSet,i=n.maxStringLength??se,a=n.spaces??2;return JSON.stringify(e,(u,t)=>{if(t===void 0)return;if(t===null)return null;switch(typeof t){case "bigint":return `${t}n`;case "function":return `[Function: ${t.name||"anonymous"}]`;case "symbol":return L(t);case "string":return t.length>i?`${t.slice(0,i)}... [truncated ${t.length-i} chars]`:t;case "object":break;default:return t}let d=t;if(r.has(d))return "[Circular]";if(r.add(d),Buffer.isBuffer(t))return `[Buffer: ${t.length} bytes]`;if(t instanceof RegExp)return L(t);if(t instanceof Error)return {error:t.name,message:t.message,stack:t.stack};if(t instanceof Map)return Array.from(t.entries());if(t instanceof Set)return Array.from(t.values());let m=t.constructor?.name;return typeof m=="string"&&ie.has(m)?`[${m}: ${L(t)}]`:t},a)};var le=createRequire$1(import.meta.url),o=(e,n,r,i,a,u)=>{e.push({id:n,status:r,title:i,detail:a,...u?{data:u}:{}});},Z=(e,n)=>{try{if(!f.existsSync(e)){if(!n)return {ok:!1,detail:"directory does not exist"};f.mkdirSync(e,{recursive:!0});}return f.accessSync(e,f.constants.W_OK),{ok:!0,detail:"writable"}}catch(r){return {ok:false,detail:r instanceof Error?r.message:String(r)}}},Y=(e,n)=>{try{return le.resolve(n??e),!0}catch{return false}},p=e=>{try{return f.readFileSync(e,"utf-8").split(/\r?\n/,1)[0]??null}catch{return null}},fe=()=>{let e=process.env.ANDROID_HOME??process.env.ANDROID_SDK_ROOT;return e?h.join(e,"platform-tools","adb"):"adb"},ee=(e,n,r=4e3)=>new Promise(i=>{execFile(e,n,{timeout:r},(a,u,t)=>{let d=`${u??""}${t??""}`.split(/\r?\n/).find(m=>m.trim())??"";if(a){i({ok:false,line:d||(a instanceof Error?a.message:String(a))});return}i({ok:true,line:d});});}),ue=async(e$1={})=>{let n=h.resolve(e$1.cwd??process.cwd()),r=[];o(r,"runtime","info","Runtime","Node and OS detected",{node:process.version,platform:`${process.platform}-${process.arch}`,home:te.homedir()});let i$1=null;try{i$1=c({searchCwd:n}),o(r,"config","pass","Config",i$1.configPath?`loaded ${i$1.configPath}`:"no config found; using defaults",{configPath:i$1.configPath,tests:i$1.config.tests,browser:i$1.config.browser.engine});}catch(s){o(r,"config","fail","Config",s instanceof Error?s.message:String(s));}let a$5=i$1?.config,u=a(),t=Z(u,!!e$1.fix);o(r,"home-dir",t.ok?"pass":"warn","Home Directory",`${u}: ${t.detail}${e$1.fix?" (fix enabled)":""}`),e$1.fix&&t.ok&&m();let d$2=h.resolve(n,a$5?.output.dir??d),m$1=Z(d$2,!!e$1.fix);o(r,"output-dir",m$1.ok?"pass":"warn","Output Directory",`${d$2}: ${m$1.detail}`),o(r,"axe-core","pass","axe-core","bundled into skeptic-cli; accessibility audits can run without a project-level @axe-core/playwright install");let N=Y("accessibility-checker-engine","accessibility-checker-engine/ace.js"),B=a$5?.observability.accessibilityDualEngine===true;o(r,"ibm-equal-access",N?"pass":B?"warn":"info","IBM Equal Access",N?"installed":B?"optional dependency missing; dual-engine accessibility will fall back to axe-core":"not installed; only required when observability.accessibilityDualEngine is enabled");let I=Y("better-sqlite3"),q=a$5?.auth.cookies===true;o(r,"better-sqlite3",I?"pass":q?"warn":"info","Cookie SQLite Reader",I?"installed":q?"optional dependency missing; Chromium/Firefox cookie extraction may be limited":"not installed; only required when auth.cookies is enabled");try{let s=await a$1();for(let c of ["chromium","firefox","webkit"])try{let l=s[c].executablePath();o(r,`playwright-${c}`,f.existsSync(l)?"pass":"warn",`Playwright ${c}`,f.existsSync(l)?`browser executable found at ${l}`:`browser executable not found at ${l}; run skeptic browsers install ${c}`,{executablePath:l});}catch(l){o(r,`playwright-${c}`,"warn",`Playwright ${c}`,l instanceof Error?l.message:String(l));}if(!e$1.quick&&a$5)try{await(await s[a$5.browser.engine].launch({headless:a$5.browser.headless})).close(),o(r,"playwright-launch","pass","Browser Launch",`${a$5.browser.engine} launched and closed successfully`);}catch(c){o(r,"playwright-launch","fail","Browser Launch",c instanceof Error?c.message:String(c));}}catch(s){o(r,"playwright","fail","Playwright",s instanceof Error?s.message:String(s));}let P=d$1(),w=p(P),b=w?Number(w):null,T=b!==null&&Number.isFinite(b)&&a$2(b);o(r,"daemon",T?"pass":w?"warn":"info","Daemon",T?`running at PID ${b}`:w?`stale or inaccessible PID sidecar at ${P}`:"not running",{socketPath:c$1(),pidPath:P,versionPath:e(),enginePath:f$1(),logPath:g(),version:p(e()),engine:p(f$1())});let $=i(),y=p($),k$1=y?Number(y):null,F=k$1!==null&&Number.isFinite(k$1)&&a$2(k$1);o(r,"session-daemon",F?"pass":y?"warn":"info","Session Daemon",F?`running at PID ${k$1}`:y?`stale or inaccessible PID sidecar at ${$}`:"not running",{socketPath:h$1(),pidPath:$,versionPath:j(),enginePath:k(),version:p(j()),engine:p(k())});let S=a$3();o(r,"cookies",S.length>0?"pass":"warn","Cookie Profiles",S.length>0?`detected ${S.length} supported browser profile(s)`:"no supported browser profiles detected",{browsers:S.map(s=>({browser:s.browser,profilePath:s.profilePath}))});let D=fe(),x=await ee(D,["version"]);if(o(r,"adb",x.ok?"pass":"info","Android adb",x.ok?`${x.line||"adb available"} (${D})`:`adb not found (${D}); install Android platform-tools or set ANDROID_HOME to enable Android (mobile) QA`,{adbPath:D}),process.platform==="darwin"){let{resolveDeveloperDir:s}=await import('./ios-tools-WK66CQ7Q.mjs'),c=s();o(r,"simctl",c?"pass":"info","iOS simctl",c?`full Xcode found (${c})`:"no full Xcode found; --platform ios-sim needs Xcode (Command Line Tools lack simctl)");let l=await ee("axe",["--version"]);o(r,"axe",l.ok?"pass":"info","iOS axe",l.ok?`axe ${l.line||"available"} (--platform ios-sim)`:"axe not installed; --platform ios-sim needs it \u2014 `brew install cameroncooke/axe/axe`");}let j$1={pass:0,warn:0,fail:0,info:0};for(let s of r)j$1[s.status]+=1;return {product:a$4,version:"1.0.1",cwd:n,platform:{os:process.platform,arch:process.arch,node:process.version},summary:j$1,checks:r}},de=e=>e==="pass"?"PASS":e==="warn"?"WARN":e==="fail"?"FAIL":"INFO",me=e=>{d$2.raw(`${a$4} doctor`),d$2.raw(`cwd: ${e.cwd}`),d$2.raw(`runtime: ${e.platform.os}-${e.platform.arch}, ${e.platform.node}`),d$2.raw(`summary: ${e.summary.pass} pass, ${e.summary.warn} warn, ${e.summary.fail} fail, ${e.summary.info} info`),d$2.raw("");for(let n of e.checks)d$2.raw(`${de(n.status).padEnd(4)} ${n.title}: ${n.detail}`);},_e=async(e={})=>{let n=await ue(e);e.json?process.stdout.write(`${z(n)}
|
|
4
4
|
`):me(n),n.summary.fail>0&&(process.exitCode=1);};export{ue as collectDoctorReport,_e as runDoctor};
|
package/dist/index.mjs
CHANGED
|
@@ -25,14 +25,14 @@ Expecting one of '${i.join("', '")}'`);return this._lifeCycleHooks[t]?this._life
|
|
|
25
25
|
`),this.outputHelp({error:true}));let i=e||{},n=i.exitCode||1,s=i.code||"commander.error";this._exit(n,s,t);}_parseOptionsEnv(){this.options.forEach(t=>{if(t.envVar&&t.envVar in d.env){let e=t.attributeName();(this.getOptionValue(e)===void 0||["default","config","env"].includes(this.getOptionValueSource(e)))&&(t.required||t.optional?this.emit(`optionEnv:${t.name()}`,d.env[t.envVar]):this.emit(`optionEnv:${t.name()}`));}});}_parseOptionsImplied(){let t=new Gt(this.options),e=i=>this.getOptionValue(i)!==void 0&&!["default","implied"].includes(this.getOptionValueSource(i));this.options.filter(i=>i.implied!==void 0&&e(i.attributeName())&&t.valueFromOption(this.getOptionValue(i.attributeName()),i)).forEach(i=>{Object.keys(i.implied).filter(n=>!e(n)).forEach(n=>{this.setOptionValueWithSource(n,i.implied[n],"implied");});});}missingArgument(t){let e=`error: missing required argument '${t}'`;this.error(e,{code:"commander.missingArgument"});}optionMissingArgument(t){let e=`error: option '${t.flags}' argument missing`;this.error(e,{code:"commander.optionMissingArgument"});}missingMandatoryOptionValue(t){let e=`error: required option '${t.flags}' not specified`;this.error(e,{code:"commander.missingMandatoryOptionValue"});}_conflictingOption(t,e){let i=r=>{let c=r.attributeName(),a=this.getOptionValue(c),u=this.options.find(h=>h.negate&&c===h.attributeName()),l=this.options.find(h=>!h.negate&&c===h.attributeName());return u&&(u.presetArg===void 0&&a===false||u.presetArg!==void 0&&a===u.presetArg)?u:l||r},n=r=>{let c=i(r),a=c.attributeName();return this.getOptionValueSource(a)==="env"?`environment variable '${c.envVar}'`:`option '${c.flags}'`},s=`error: ${n(t)} cannot be used with ${n(e)}`;this.error(s,{code:"commander.conflictingOption"});}unknownOption(t){if(this._allowUnknownOption)return;let e="";if(t.startsWith("--")&&this._showSuggestionAfterError){let n=[],s=this;do{let r=s.createHelp().visibleOptions(s).filter(c=>c.long).map(c=>c.long);n=n.concat(r),s=s.parent;}while(s&&!s._enablePositionalOptions);e=st(t,n);}let i=`error: unknown option '${t}'${e}`;this.error(i,{code:"commander.unknownOption"});}_excessArguments(t){if(this._allowExcessArguments)return;let e=this.registeredArguments.length,i=e===1?"":"s",s=`error: too many arguments${this.parent?` for '${this.name()}'`:""}. Expected ${e} argument${i} but got ${t.length}.`;this.error(s,{code:"commander.excessArguments"});}unknownCommand(){let t=this.args[0],e="";if(this._showSuggestionAfterError){let n=[];this.createHelp().visibleCommands(this).forEach(s=>{n.push(s.name()),s.alias()&&n.push(s.alias());}),e=st(t,n);}let i=`error: unknown command '${t}'${e}`;this.error(i,{code:"commander.unknownCommand"});}version(t,e,i){if(t===void 0)return this._version;this._version=t,e=e||"-V, --version",i=i||"output the version number";let n=this.createOption(e,i);return this._versionOptionName=n.attributeName(),this._registerOption(n),this.on("option:"+n.name(),()=>{this._outputConfiguration.writeOut(`${t}
|
|
26
26
|
`),this._exit(0,"commander.version",t);}),this}description(t,e){return t===void 0&&e===void 0?this._description:(this._description=t,e&&(this._argsDescription=e),this)}summary(t){return t===void 0?this._summary:(this._summary=t,this)}alias(t){if(t===void 0)return this._aliases[0];let e=this;if(this.commands.length!==0&&this.commands[this.commands.length-1]._executableHandler&&(e=this.commands[this.commands.length-1]),t===e._name)throw new Error("Command alias can't be the same as its name");let i=this.parent?._findCommand(t);if(i){let n=[i.name()].concat(i.aliases()).join("|");throw new Error(`cannot add alias '${t}' to command '${this.name()}' as already have command '${n}'`)}return e._aliases.push(t),this}aliases(t){return t===void 0?this._aliases:(t.forEach(e=>this.alias(e)),this)}usage(t){if(t===void 0){if(this._usage)return this._usage;let e=this.registeredArguments.map(i=>Mt(i));return [].concat(this.options.length||this._helpOption!==null?"[options]":[],this.commands.length?"[command]":[],this.registeredArguments.length?e:[]).join(" ")}return this._usage=t,this}name(t){return t===void 0?this._name:(this._name=t,this)}nameFromFilename(t){return this._name=w.basename(t,w.extname(t)),this}executableDir(t){return t===void 0?this._executableDir:(this._executableDir=t,this)}helpInformation(t){let e=this.createHelp(),i=this._getOutputContext(t);e.prepareContext({error:i.error,helpWidth:i.helpWidth,outputHasColors:i.hasColors});let n=e.formatHelp(this,e);return i.hasColors?n:this._outputConfiguration.stripColor(n)}_getOutputContext(t){t=t||{};let e=!!t.error,i,n,s;return e?(i=c=>this._outputConfiguration.writeErr(c),n=this._outputConfiguration.getErrHasColors(),s=this._outputConfiguration.getErrHelpWidth()):(i=c=>this._outputConfiguration.writeOut(c),n=this._outputConfiguration.getOutHasColors(),s=this._outputConfiguration.getOutHelpWidth()),{error:e,write:c=>(n||(c=this._outputConfiguration.stripColor(c)),i(c)),hasColors:n,helpWidth:s}}outputHelp(t){let e;typeof t=="function"&&(e=t,t=void 0);let i=this._getOutputContext(t),n={error:i.error,write:i.write,command:this};this._getCommandAndAncestors().reverse().forEach(r=>r.emit("beforeAllHelp",n)),this.emit("beforeHelp",n);let s=this.helpInformation({error:i.error});if(e&&(s=e(s),typeof s!="string"&&!Buffer.isBuffer(s)))throw new Error("outputHelp callback must return a string or a Buffer");i.write(s),this._getHelpOption()?.long&&this.emit(this._getHelpOption().long),this.emit("afterHelp",n),this._getCommandAndAncestors().forEach(r=>r.emit("afterAllHelp",n));}helpOption(t,e){return typeof t=="boolean"?(t?this._helpOption=this._helpOption??void 0:this._helpOption=null,this):(t=t??"-h, --help",e=e??"display help for command",this._helpOption=this.createOption(t,e),this)}_getHelpOption(){return this._helpOption===void 0&&this.helpOption(void 0,void 0),this._helpOption}addHelpOption(t){return this._helpOption=t,this}help(t){this.outputHelp(t);let e=Number(d.exitCode??0);e===0&&t&&typeof t!="function"&&t.error&&(e=1),this._exit(e,"commander.help","(outputHelp)");}addHelpText(t,e){let i=["beforeAll","before","after","afterAll"];if(!i.includes(t))throw new Error(`Unexpected value for position to addHelpText.
|
|
27
27
|
Expecting one of '${i.join("', '")}'`);let n=`${t}Help`;return this.on(n,s=>{let r;typeof e=="function"?r=e({error:s.error,command:s.command}):r=e,r&&s.write(`${r}
|
|
28
|
-
`);}),this}_outputHelpIfRequested(t){let e=this._getHelpOption();e&&t.find(n=>e.is(n))&&(this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)"));}};function ot(o){return o.map(t=>{if(!t.startsWith("--inspect"))return t;let e,i="127.0.0.1",n="9229",s;return (s=t.match(/^(--inspect(-brk)?)$/))!==null?e=s[1]:(s=t.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))!==null?(e=s[1],/^\d+$/.test(s[3])?n=s[3]:i=s[3]):(s=t.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null&&(e=s[1],i=s[3],n=s[4]),e&&n!=="0"?`${e}=${i}:${parseInt(n)+1}`:t})}function U(){if(d.env.NO_COLOR||d.env.FORCE_COLOR==="0"||d.env.FORCE_COLOR==="false")return false;if(d.env.FORCE_COLOR||d.env.CLICOLOR_FORCE!==void 0)return true}B.Command=M;B.useColor=U;});var ut=b$1(g=>{var{Argument:at}=A(),{Command:G}=rt(),{CommanderError:Jt,InvalidArgumentError:ct}=x(),{Help:Kt}=N(),{Option:lt}=R();g.program=new G;g.createCommand=o=>new G(o);g.createOption=(o,t)=>new lt(o,t);g.createArgument=(o,t)=>new at(o,t);g.Command=G;g.Option=lt;g.Argument=at;g.Help=Kt;g.CommanderError=Jt;g.InvalidArgumentError=ct;g.InvalidOptionArgumentError=ct;});var pt=d(ut(),1),{program:le,createCommand:ue,createArgument:pe,createOption:he,CommanderError:de,InvalidArgumentError:b,InvalidOptionArgumentError:me,Command:ht,Argument:fe,Option:ge,Help:be}=pt.default;var Yt=createRequire$1(import.meta.url),dt=null,S=()=>(dt??=Yt("@playwright/test").expect,dt),mt=new Proxy(((...o)=>S()(...o)),{apply(o,t,e){return Reflect.apply(S(),t,e)},get(o,t,e){return Reflect.get(S(),t,e)},set(o,t,e,i){return Reflect.set(S(),t,e,i)}});var J=class{start;constructor(){this.start=process.hrtime.bigint();}elapsedMs(){return Number(process.hrtime.bigint()-this.start)/1e6}format(){let t=this.elapsedMs();return t<1e3?`${Math.round(t)}ms`:`${(t/1e3).toFixed(2)}s`}};function _(o){if(!/^[1-9]\d*$/.test(o))throw new b(`expected a positive integer, got "${o}"`);return Number(o)}function O(o){if(!/^\d+$/.test(o))throw new b(`expected a non-negative integer, got "${o}"`);return Number(o)}function wt(o){if(o==="load"||o==="domcontentloaded"||o==="networkidle"||o==="commit")return o;throw new b(`expected one of load, domcontentloaded, networkidle, or commit; got "${o}"`)}function Xt(o){if(o==="off"||o==="warn"||o==="fail")return o;throw new b(`expected one of off, warn, or fail; got "${o}"`)}function Qt(o){if(o==="attached"||o==="detached"||o==="visible"||o==="hidden")return o;throw new b(`expected one of attached, detached, visible, or hidden; got "${o}"`)}function K(o){if(o==="web"||o==="android"||o==="ios-sim")return o;throw o==="ios"?new b('use "ios-sim" for the iOS simulator (real iOS devices are out of scope)'):new b(`unknown platform "${o}"; expected one of web, android, ios-sim`)}function ft(o){let t=Number(o);if(!Number.isInteger(t))throw new b(`expected an integer, got "${o}"`);return t}function Zt(o){if(o==="visible"||o==="enabled"||o==="checked")return o;throw new b(`unknown state "${o}"; expected one of visible, enabled, checked`)}var gt=64;function bt(o){let t=_(o);if(t>gt)throw new b(`must be at most ${gt}, got ${t} (use a coordinator if you need more parallelism)`);return t}var p=new ht,_t=(o,t={})=>{let e=o.option("-c, --config <path>","path to config file").option("--headed","run browser in headed mode").option("--verbose","verbose output").option("--ci","force CI mode (headless, no prompts)").option("--bail","stop on first failure").option("--retries <n>","retry failed tests N times",O).option("--timeout <ms>","soft per-action default timeout in ms",_).option("--hard-timeout <ms>","hard per-test ceiling in ms",_).option("--device <id>","device profile for viewport emulation").option("--platform <platform>","web (default) | android | ios-sim \u2014 drive a device/simulator, passing specs a `device` fixture",K).option("--target <serial>","device/emulator serial or simulator UDID for --platform android|ios-sim").option("--reporter <format...>","reporter format(s): console, json, junit, html").option("--output <dir>","output directory for reports").option("--cookies","enable browser cookie extraction (opt-in)").option("--cookies-from <browser>","extract cookies from specific browser only").option("--video","record video of test execution (WebM)").option("--video-size <WxH>","video recording resolution (e.g., 1920x1080); overrides viewport size for video only");return t.includeWatch&&e.option("-w, --watch","watch for file changes and re-run"),e.option("-u, --url <url>","base URL (overrides config)").option("--parallel <n>","run N test files concurrently",_).option("--shard-split <n>","split tests across N runs (each runs disjoint subset)",bt).option("--shard-all <n>","run all tests on each of N runs",bt).option("--shard-index <n>","1-based shard index for --shard-split / --shard-all (also via SKEPTIC_SHARD_INDEX)",_),e.option("--trace","record Playwright trace for each test").option("--har","capture a HAR (HTTP archive) of network traffic per test").option("--observability","enable the full observability bundle: settle + fullPage + perf+net+console+a11y(auto) + sidecar md").option("--full-page-screenshot","force fullPage=true on all screenshot calls").option("--no-full-page-screenshot","force fullPage=false (overrides config)").option("--visual-settle","enable the visual-settle helper before screenshots").option("--no-visual-settle","disable the visual-settle helper").option("--blank-frame-detection <mode>","off | warn | fail",Xt).option("--observability-write-sidecars","write per-test perf-trace.md + console.json + network.json").option("--list","discover tests without running them").option("--tag <tag...>","filter tests by tag (declared via test.use({ tags }))").option("-t, --grep <substring>","run only tests whose name contains this substring").option("--env <KEY=VALUE...>","set environment variables").option("--no-daemon","bypass the persistent BrowserServer daemon").option("--daemon-idle-timeout <seconds>","auto-stop the daemon after N seconds idle (default 300; 0 disables)",O)};p.name(b$2).description(`${a$1} \u2014 CLI-first E2E testing with TypeScript test specs`).version("1.0.
|
|
28
|
+
`);}),this}_outputHelpIfRequested(t){let e=this._getHelpOption();e&&t.find(n=>e.is(n))&&(this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)"));}};function ot(o){return o.map(t=>{if(!t.startsWith("--inspect"))return t;let e,i="127.0.0.1",n="9229",s;return (s=t.match(/^(--inspect(-brk)?)$/))!==null?e=s[1]:(s=t.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))!==null?(e=s[1],/^\d+$/.test(s[3])?n=s[3]:i=s[3]):(s=t.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null&&(e=s[1],i=s[3],n=s[4]),e&&n!=="0"?`${e}=${i}:${parseInt(n)+1}`:t})}function U(){if(d.env.NO_COLOR||d.env.FORCE_COLOR==="0"||d.env.FORCE_COLOR==="false")return false;if(d.env.FORCE_COLOR||d.env.CLICOLOR_FORCE!==void 0)return true}B.Command=M;B.useColor=U;});var ut=b$1(g=>{var{Argument:at}=A(),{Command:G}=rt(),{CommanderError:Jt,InvalidArgumentError:ct}=x(),{Help:Kt}=N(),{Option:lt}=R();g.program=new G;g.createCommand=o=>new G(o);g.createOption=(o,t)=>new lt(o,t);g.createArgument=(o,t)=>new at(o,t);g.Command=G;g.Option=lt;g.Argument=at;g.Help=Kt;g.CommanderError=Jt;g.InvalidArgumentError=ct;g.InvalidOptionArgumentError=ct;});var pt=d(ut(),1),{program:le,createCommand:ue,createArgument:pe,createOption:he,CommanderError:de,InvalidArgumentError:b,InvalidOptionArgumentError:me,Command:ht,Argument:fe,Option:ge,Help:be}=pt.default;var Yt=createRequire$1(import.meta.url),dt=null,S=()=>(dt??=Yt("@playwright/test").expect,dt),mt=new Proxy(((...o)=>S()(...o)),{apply(o,t,e){return Reflect.apply(S(),t,e)},get(o,t,e){return Reflect.get(S(),t,e)},set(o,t,e,i){return Reflect.set(S(),t,e,i)}});var J=class{start;constructor(){this.start=process.hrtime.bigint();}elapsedMs(){return Number(process.hrtime.bigint()-this.start)/1e6}format(){let t=this.elapsedMs();return t<1e3?`${Math.round(t)}ms`:`${(t/1e3).toFixed(2)}s`}};function _(o){if(!/^[1-9]\d*$/.test(o))throw new b(`expected a positive integer, got "${o}"`);return Number(o)}function O(o){if(!/^\d+$/.test(o))throw new b(`expected a non-negative integer, got "${o}"`);return Number(o)}function wt(o){if(o==="load"||o==="domcontentloaded"||o==="networkidle"||o==="commit")return o;throw new b(`expected one of load, domcontentloaded, networkidle, or commit; got "${o}"`)}function Xt(o){if(o==="off"||o==="warn"||o==="fail")return o;throw new b(`expected one of off, warn, or fail; got "${o}"`)}function Qt(o){if(o==="attached"||o==="detached"||o==="visible"||o==="hidden")return o;throw new b(`expected one of attached, detached, visible, or hidden; got "${o}"`)}function K(o){if(o==="web"||o==="android"||o==="ios-sim")return o;throw o==="ios"?new b('use "ios-sim" for the iOS simulator (real iOS devices are out of scope)'):new b(`unknown platform "${o}"; expected one of web, android, ios-sim`)}function ft(o){let t=Number(o);if(!Number.isInteger(t))throw new b(`expected an integer, got "${o}"`);return t}function Zt(o){if(o==="visible"||o==="enabled"||o==="checked")return o;throw new b(`unknown state "${o}"; expected one of visible, enabled, checked`)}var gt=64;function bt(o){let t=_(o);if(t>gt)throw new b(`must be at most ${gt}, got ${t} (use a coordinator if you need more parallelism)`);return t}var p=new ht,_t=(o,t={})=>{let e=o.option("-c, --config <path>","path to config file").option("--headed","run browser in headed mode").option("--verbose","verbose output").option("--ci","force CI mode (headless, no prompts)").option("--bail","stop on first failure").option("--retries <n>","retry failed tests N times",O).option("--timeout <ms>","soft per-action default timeout in ms",_).option("--hard-timeout <ms>","hard per-test ceiling in ms",_).option("--device <id>","device profile for viewport emulation").option("--platform <platform>","web (default) | android | ios-sim \u2014 drive a device/simulator, passing specs a `device` fixture",K).option("--target <serial>","device/emulator serial or simulator UDID for --platform android|ios-sim").option("--reporter <format...>","reporter format(s): console, json, junit, html").option("--output <dir>","output directory for reports").option("--cookies","enable browser cookie extraction (opt-in)").option("--cookies-from <browser>","extract cookies from specific browser only").option("--video","record video of test execution (WebM)").option("--video-size <WxH>","video recording resolution (e.g., 1920x1080); overrides viewport size for video only");return t.includeWatch&&e.option("-w, --watch","watch for file changes and re-run"),e.option("-u, --url <url>","base URL (overrides config)").option("--parallel <n>","run N test files concurrently",_).option("--shard-split <n>","split tests across N runs (each runs disjoint subset)",bt).option("--shard-all <n>","run all tests on each of N runs",bt).option("--shard-index <n>","1-based shard index for --shard-split / --shard-all (also via SKEPTIC_SHARD_INDEX)",_),e.option("--trace","record Playwright trace for each test").option("--har","capture a HAR (HTTP archive) of network traffic per test").option("--observability","enable the full observability bundle: settle + fullPage + perf+net+console+a11y(auto) + sidecar md").option("--full-page-screenshot","force fullPage=true on all screenshot calls").option("--no-full-page-screenshot","force fullPage=false (overrides config)").option("--visual-settle","enable the visual-settle helper before screenshots").option("--no-visual-settle","disable the visual-settle helper").option("--blank-frame-detection <mode>","off | warn | fail",Xt).option("--observability-write-sidecars","write per-test perf-trace.md + console.json + network.json").option("--list","discover tests without running them").option("--tag <tag...>","filter tests by tag (declared via test.use({ tags }))").option("-t, --grep <substring>","run only tests whose name contains this substring").option("--env <KEY=VALUE...>","set environment variables").option("--no-daemon","bypass the persistent BrowserServer daemon").option("--daemon-idle-timeout <seconds>","auto-stop the daemon after N seconds idle (default 300; 0 disables)",O)};p.name(b$2).description(`${a$1} \u2014 CLI-first E2E testing with TypeScript test specs`).version("1.0.1").option("-v, --verbose","enable verbose logging").option("-q, --quiet","suppress all output except errors").option("--features","print build-time feature map and exit").addHelpText("after",`
|
|
29
29
|
Examples:
|
|
30
30
|
$ skeptic tui
|
|
31
31
|
$ skeptic tui tests/login.spec.ts
|
|
32
32
|
$ skeptic run tests/login.spec.ts --observability --video --trace
|
|
33
|
-
$ skeptic inspect https://example.com --interactive --compact`).hook("preAction",(o,t)=>{let e=p.opts(),i="info";e.verbose&&(i="debug"),e.quiet&&(i="error"),a$2(i);});p.command("init").alias("setup").description("Initialize a new skeptic project").argument("[dir]","target directory",".").action(async o=>{let{runInit:t}=await import('./init-
|
|
33
|
+
$ skeptic inspect https://example.com --interactive --compact`).hook("preAction",(o,t)=>{let e=p.opts(),i="info";e.verbose&&(i="debug"),e.quiet&&(i="error"),a$2(i);});p.command("init").alias("setup").description("Initialize a new skeptic project").argument("[dir]","target directory",".").action(async o=>{let{runInit:t}=await import('./init-6RHO2LGR.mjs');await t(o);});_t(p.command("run").description("Run TypeScript test specs").argument("[specs...]","spec file globs (default: tests/**/*.spec.ts)"),{includeWatch:true}).action(async(o,t)=>{let{runRun:e}=await import('./run-GUWITPL4.mjs');await e(o.length>0?o:void 0,t);});_t(p.command("tui").description("Open the interactive test runner TUI").argument("[specs...]","spec file globs (default: tests/**/*.spec.ts)")).addHelpText("after",`
|
|
34
34
|
Examples:
|
|
35
35
|
$ skeptic tui
|
|
36
36
|
$ skeptic tui tests/login.spec.ts
|
|
37
|
-
$ skeptic tui tests/**/*.spec.ts --reporter json`).action(async(o,t)=>{let{runRun:e}=await import('./run-GW3X5ANC.mjs');await e(o.length>0?o:void 0,{...t,forceTui:true});});p.command("mail").description("Start a local SMTP sink and print the one-time code from a verification email").option("--to <address>","only match emails addressed to this recipient (substring)").option("--port <n>","SMTP listen port (point the app's SMTP here)",_,2525).option("--timeout <ms>","how long to wait for the email",_,6e4).option("--json","machine-readable output (includes full message)").action(async o=>{let{runMail:t}=await import('./mail-GTOZFXJ5.mjs');await t(o);});p.command("scaffold").description("Generate a TypeScript spec skeleton from a live page or app (deterministic, no AI)").argument("<target>","URL (web) or app package / deep link (--platform android|ios-sim)").option("-o, --output <dir>","output directory","tests").option("--name <name>","base name for the spec file").option("--headed","show the browser").option("--platform <platform>","web (default) | android | ios-sim \u2014 scaffold a `device`-fixture spec from an app",K).option("--target <serial>","device/emulator serial or simulator UDID for --platform android|ios-sim").action(async(o,t)=>{let{runScaffold:e}=await import('./scaffold-6ZF6K6Y5.mjs');await e(o,t);});var Ot=p.command("add").description("Add integrations and scaffolding");Ot.command("github-action").description("Generate a GitHub Actions workflow for E2E tests").option("--dev-command <cmd>","dev server start command","npm run dev").option("--dev-url <url>","dev server URL","http://localhost:3000").option("-c, --config <path>","path to config file").action(async o=>{let{runAddGitHubAction:t}=await import('./add-G7JFXU4S.mjs');await t(o);});Ot.command("skill").description("Install skeptic skill for an AI coding agent").option("--agent <name>","agent name: claude, codex, cursor, opencode, all").option("--scope <scope>","skill scope: project or user","project").action(async o=>{let{runAddSkill:t}=await import('./add-G7JFXU4S.mjs');await t(o);});var te=p.command("cookies").description("Manage browser cookie extraction"),ee=p.command("browsers").description("Manage Playwright browser binaries");ee.command("install").description("Download Playwright browser binaries").argument("[browsers...]","browsers to install (chromium, firefox, webkit, all). Defaults to chromium.").option("--with-deps","also install OS-level dependencies (sudo on Linux)").option("--dry-run","print what would be installed without installing").action(async(o,t)=>{let{runBrowsersInstall:e}=await import('./browsers-install-F2ZWEBOX.mjs'),i=o.length>0?o:["chromium"];await e(i,t);});te.command("list").description("List detected browsers for cookie extraction").action(async()=>{let{runCookiesList:o}=await import('./cookies-X7W5U3VE.mjs');await o();});p.command("comment").description("Upsert a PR comment with test results (uses `gh` CLI)").option("--results <path>","path to results.json","./skeptic-output/results.json").option("--pr <number>","PR number (default: auto-detect)").option("--marker <string>","HTML comment marker","<!-- skeptic-qa-results -->").option("--run-url <url>","URL to CI run page").option("--dry-run","print body to stdout instead of posting").option("-c, --config <path>","path to config file").action(async o=>{let{runComment:t}=await import('./comment-F734YE5S.mjs');await t(o);});p.command("doctor").description("Diagnose skeptic setup, browser installs, optional engines, daemon state, and agent DX").option("--json","emit machine-readable JSON").option("--quick","skip live browser launch checks").option("--fix","create missing skeptic-owned directories when safe").action(async o=>{let{runDoctor:t}=await import('./doctor-WRKNAK3W.mjs');await t(o);});p.command("observe").description("Run one ad hoc browser observability pass and write a full artifact bundle").argument("<url>","URL to observe").option("-c, --config <path>","path to config file").option("--headed","run browser in headed mode").option("--device <id>","device profile for viewport emulation").option("--output <dir>","output directory for reports").option("--wait <ms>","extra wait after navigation before capture",O).option("--wait-until <strategy>","navigation wait strategy: load, domcontentloaded, networkidle, or commit",wt).option("--full-page","capture full-page screenshots").option("--video","record video of the observation").option("--no-video","disable video recording").option("--video-size <WxH>","video recording resolution (e.g., 1920x1080)").option("--trace","record Playwright trace").option("--no-trace","disable Playwright trace").option("--cookies","enable browser cookie extraction").option("--cookies-from <browser>","extract cookies from specific browser only").option("--timeout <ms>","default timeout in ms",_).option("--no-tui","suppress live console progress").action(async(o,t)=>{let{runObserve:e}=await import('./observe-MHEV7OVP.mjs');await e(o,t);});p.command("inspect").description("Inspect a page \u2014 emit ARIA + cursor-interactive refs with stable selectorHints").argument("<url>","URL to inspect").option("--interactive","filter to lines with refs").option("--compact","interactive + minimal ancestors").option("--selector <css>","scope to a CSS subtree").option("--json","emit machine-readable JSON").option("--device <id>","device profile (e.g. iphone_15)").option("--headed","show the browser").option("--wait <ms>","extra settle in ms after navigation before snapshot (default 0; the adaptive networkidle settle runs regardless)").option("--connect <url>","CDP auto-discover and attach (host:port or ws URL)").option("--with-playwright-hints","also emit Playwright snippet per ref").option("--annotated","capture an annotated PNG with numbered badges over each ref").option("--annotate-output <path>","output path for the annotated PNG (defaults to ./skeptic-inspect-<ts>.png)").option("--no-daemon","bypass the persistent daemon and launch a fresh browser").action(async(o,t)=>{let{runInspect:e}=await import('./inspect-3XFCCSUL.mjs');await e(o,t);});var E=p.command("daemon").description("Manage the persistent BrowserServer daemon (B10)");E.command("start").description("Start the daemon (foreground; auto-spawned by `run`/`inspect` when needed)").option("--engine <engine>","browser engine: chromium | firefox | webkit","chromium").option("--headed","run BrowserServer in headed mode").option("--daemon-idle-timeout <seconds>","auto-stop after N idle seconds (default 300; 0 disables)",O).action(async o=>{let{runDaemonStart:t}=await import('./daemon-M2J3L6JW.mjs');await t(o);});E.command("stop").description("Stop the running daemon").action(async()=>{let{runDaemonStop:o}=await import('./daemon-M2J3L6JW.mjs');await o();});E.command("status").description("Show daemon status (running/uptime/clients/engine)").action(async()=>{let{runDaemonStatus:o}=await import('./daemon-M2J3L6JW.mjs');await o();});E.command("logs").description("Tail the daemon log file at ~/.skeptic/daemon.log").option("-n, --lines <n>","show last N lines (default 200)",_).action(async o=>{let{runDaemonLogs:t}=await import('./daemon-M2J3L6JW.mjs');await t(o);});p.command("session-daemon",{hidden:true}).description("(internal) interactive browser-session daemon \u2014 auto-spawned by session verbs").option("--engine <engine>","browser engine","chromium").option("--headed","run headed (default)").option("--headless","run headless").option("--idle-timeout <seconds>","daemon idle shutdown",O).option("--session-idle <seconds>","per-session idle reap",O).action(async o=>{let{runSessionDaemon:t}=await import('./session-daemon-cmd-23UUK6TD.mjs');await t(o);});var m=o=>o.option("--session <name>","isolated session name","default").option("--json","machine-readable JSON output").option("--platform <platform>","web (default) | android (adb) | ios-sim (simctl+axe)",K).option("--headed","run the session browser headed (default; web only)").option("--headless","run the session browser headless (web only)");m(p.command("open").description("Open a URL in a persistent browser session").argument("<url>","URL to open")).option("--wait-until <s>","navigation wait: load, domcontentloaded, networkidle, commit",wt).action(async(o,t)=>{let{runOpen:e}=await import('./browser-verbs-U54BZACP.mjs');await e(o,t);});m(p.command("snapshot").description("Snapshot the open session's page \u2014 mints @eN refs + selectorHints")).option("-i, --interactive","filter to interactive refs").option("-c, --compact","interactive + minimal ancestors").action(async o=>{let{runSnapshot:t}=await import('./browser-verbs-U54BZACP.mjs');await t(o);});m(p.command("click").description("Click an element (@eN ref or selector)").argument("<target>","@eN or selector")).action(async(o,t)=>{let{runClick:e}=await import('./browser-verbs-U54BZACP.mjs');await e(o,t);});m(p.command("fill").description("Fill an input (clears first)").argument("<target>","@eN or selector").argument("<text>","text")).action(async(o,t,e)=>{let{runFill:i}=await import('./browser-verbs-U54BZACP.mjs');await i(o,t,e);});m(p.command("type").description("Type into an element (no clear)").argument("<target>","@eN or selector").argument("<text>","text")).action(async(o,t,e)=>{let{runType:i}=await import('./browser-verbs-U54BZACP.mjs');await i(o,t,e);});m(p.command("press").description("Press a key on an element").argument("<target>","@eN or selector").argument("<key>",'e.g. "Enter"')).action(async(o,t,e)=>{let{runPress:i}=await import('./browser-verbs-U54BZACP.mjs');await i(o,t,e);});m(p.command("hover").description("Hover an element").argument("<target>","@eN or selector")).action(async(o,t)=>{let{runHover:e}=await import('./browser-verbs-U54BZACP.mjs');await e(o,t);});m(p.command("check").description("Check a checkbox").argument("<target>","@eN or selector")).action(async(o,t)=>{let{runCheck:e}=await import('./browser-verbs-U54BZACP.mjs');await e(o,t);});m(p.command("uncheck").description("Uncheck a checkbox").argument("<target>","@eN or selector")).action(async(o,t)=>{let{runUncheck:e}=await import('./browser-verbs-U54BZACP.mjs');await e(o,t);});m(p.command("select").description("Select an option").argument("<target>","@eN or selector").argument("<value>","option value")).action(async(o,t,e)=>{let{runSelect:i}=await import('./browser-verbs-U54BZACP.mjs');await i(o,t,e);});m(p.command("get").description("Read text|value|box|url|title from the session").argument("<query>","text | value | box | url | title").argument("[target]","@eN or selector")).action(async(o,t,e)=>{let{runGet:i}=await import('./browser-verbs-U54BZACP.mjs');await i(o,t,e);});m(p.command("is").description("Query a boolean element state").argument("<state>","visible | enabled | checked",Zt).argument("<target>","@eN or selector")).action(async(o,t,e)=>{let{runGet:i}=await import('./browser-verbs-U54BZACP.mjs');await i(o,t,e);});m(p.command("scroll").description("Scroll an element into view (<@ref>) or pan the viewport (--dx/--dy)").argument("[target]","@eN or selector")).option("--dx <n>","horizontal viewport pan (px)",ft).option("--dy <n>","vertical viewport pan (px)",ft).action(async(o,t)=>{let{runScroll:e}=await import('./browser-verbs-U54BZACP.mjs');await e(o,t);});m(p.command("screenshot").description("Capture a screenshot of the session (returns a file path)")).option("--name <name>","artifact name","screenshot").option("--full","full-page capture").option("--annotate","numbered badges over interactive refs").action(async o=>{let{runScreenshot:t}=await import('./browser-verbs-U54BZACP.mjs');await t(o);});m(p.command("console").description("Read the session's console messages (or --errors only)")).option("--errors","only uncaught errors / console.error").action(async o=>{let{runConsole:t}=await import('./browser-verbs-U54BZACP.mjs');await t(o);});m(p.command("record").description("Record a fixed-duration screen video of the session (Android screenrecord)")).option("--duration <seconds>","recording length (1-20s, default 3)",O).action(async o=>{let{runRecord:t}=await import('./browser-verbs-U54BZACP.mjs');await t(o);});for(let[o,t,e]of [["perf","performance","Read performance evidence (Android: gfxinfo/meminfo/launch; web: Web Vitals)"],["a11y","accessibility","Read accessibility evidence (Android: uiautomator heuristics; web: axe)"],["network","network","Read network evidence (Android: degraded per-uid totals; web: requests)"]])m(p.command(o).description(e)).action(async i=>{let{runObserve:n}=await import('./browser-verbs-U54BZACP.mjs');await n(t,i);});m(p.command("wait").description("Wait for a duration (--ms) or a selector")).option("--ms <n>","milliseconds to wait",O).option("--selector <sel>","wait for a selector").option("--state <state>","visible | hidden | attached | detached",Qt).option("--timeout-ms <n>","wait timeout",O).action(async o=>{let{runWait:t}=await import('./browser-verbs-U54BZACP.mjs');await t(o);});m(p.command("close").description("Close the session (--all closes every session)")).option("--all","close all sessions").action(async o=>{let{runClose:t}=await import('./browser-verbs-U54BZACP.mjs');await t(o);});m(p.command("list").description("List open browser sessions")).action(async o=>{let{runList:t}=await import('./browser-verbs-U54BZACP.mjs');await t(o);});p.command("devices").description("List connected devices/emulators (Android via adb; iOS preview via simctl)").option("--json","machine-readable JSON output").action(async o=>{let{runDevices:t}=await import('./devices-NG4P5UPS.mjs');await t(o);});p.command("audit").description("Run project lint, type-check, and quality scripts").option("--fix","attempt to auto-fix issues").action(async o=>{let{runAudit:t}=await import('./audit-ID2BSVYC.mjs');await t(o);});p.action(()=>{p.outputHelp();});
|
|
37
|
+
$ skeptic tui tests/**/*.spec.ts --reporter json`).action(async(o,t)=>{let{runRun:e}=await import('./run-GUWITPL4.mjs');await e(o.length>0?o:void 0,{...t,forceTui:true});});p.command("mail").description("Start a local SMTP sink and print the one-time code from a verification email").option("--to <address>","only match emails addressed to this recipient (substring)").option("--port <n>","SMTP listen port (point the app's SMTP here)",_,2525).option("--timeout <ms>","how long to wait for the email",_,6e4).option("--json","machine-readable output (includes full message)").action(async o=>{let{runMail:t}=await import('./mail-GTOZFXJ5.mjs');await t(o);});p.command("scaffold").description("Generate a TypeScript spec skeleton from a live page or app (deterministic, no AI)").argument("<target>","URL (web) or app package / deep link (--platform android|ios-sim)").option("-o, --output <dir>","output directory","tests").option("--name <name>","base name for the spec file").option("--headed","show the browser").option("--platform <platform>","web (default) | android | ios-sim \u2014 scaffold a `device`-fixture spec from an app",K).option("--target <serial>","device/emulator serial or simulator UDID for --platform android|ios-sim").action(async(o,t)=>{let{runScaffold:e}=await import('./scaffold-6ZF6K6Y5.mjs');await e(o,t);});var Ot=p.command("add").description("Add integrations and scaffolding");Ot.command("github-action").description("Generate a GitHub Actions workflow for E2E tests").option("--dev-command <cmd>","dev server start command","npm run dev").option("--dev-url <url>","dev server URL","http://localhost:3000").option("-c, --config <path>","path to config file").action(async o=>{let{runAddGitHubAction:t}=await import('./add-G7JFXU4S.mjs');await t(o);});Ot.command("skill").description("Install skeptic skill for an AI coding agent").option("--agent <name>","agent name: claude, codex, cursor, opencode, all").option("--scope <scope>","skill scope: project or user","project").action(async o=>{let{runAddSkill:t}=await import('./add-G7JFXU4S.mjs');await t(o);});var te=p.command("cookies").description("Manage browser cookie extraction"),ee=p.command("browsers").description("Manage Playwright browser binaries");ee.command("install").description("Download Playwright browser binaries").argument("[browsers...]","browsers to install (chromium, firefox, webkit, all). Defaults to chromium.").option("--with-deps","also install OS-level dependencies (sudo on Linux)").option("--dry-run","print what would be installed without installing").action(async(o,t)=>{let{runBrowsersInstall:e}=await import('./browsers-install-F2ZWEBOX.mjs'),i=o.length>0?o:["chromium"];await e(i,t);});te.command("list").description("List detected browsers for cookie extraction").action(async()=>{let{runCookiesList:o}=await import('./cookies-X7W5U3VE.mjs');await o();});p.command("comment").description("Upsert a PR comment with test results (uses `gh` CLI)").option("--results <path>","path to results.json","./skeptic-output/results.json").option("--pr <number>","PR number (default: auto-detect)").option("--marker <string>","HTML comment marker","<!-- skeptic-qa-results -->").option("--run-url <url>","URL to CI run page").option("--dry-run","print body to stdout instead of posting").option("-c, --config <path>","path to config file").action(async o=>{let{runComment:t}=await import('./comment-F734YE5S.mjs');await t(o);});p.command("doctor").description("Diagnose skeptic setup, browser installs, optional engines, daemon state, and agent DX").option("--json","emit machine-readable JSON").option("--quick","skip live browser launch checks").option("--fix","create missing skeptic-owned directories when safe").action(async o=>{let{runDoctor:t}=await import('./doctor-Q76JEQQI.mjs');await t(o);});p.command("observe").description("Run one ad hoc browser observability pass and write a full artifact bundle").argument("<url>","URL to observe").option("-c, --config <path>","path to config file").option("--headed","run browser in headed mode").option("--device <id>","device profile for viewport emulation").option("--output <dir>","output directory for reports").option("--wait <ms>","extra wait after navigation before capture",O).option("--wait-until <strategy>","navigation wait strategy: load, domcontentloaded, networkidle, or commit",wt).option("--full-page","capture full-page screenshots").option("--video","record video of the observation").option("--no-video","disable video recording").option("--video-size <WxH>","video recording resolution (e.g., 1920x1080)").option("--trace","record Playwright trace").option("--no-trace","disable Playwright trace").option("--cookies","enable browser cookie extraction").option("--cookies-from <browser>","extract cookies from specific browser only").option("--timeout <ms>","default timeout in ms",_).option("--no-tui","suppress live console progress").action(async(o,t)=>{let{runObserve:e}=await import('./observe-EDXYWK6C.mjs');await e(o,t);});p.command("inspect").description("Inspect a page \u2014 emit ARIA + cursor-interactive refs with stable selectorHints").argument("<url>","URL to inspect").option("--interactive","filter to lines with refs").option("--compact","interactive + minimal ancestors").option("--selector <css>","scope to a CSS subtree").option("--json","emit machine-readable JSON").option("--device <id>","device profile (e.g. iphone_15)").option("--headed","show the browser").option("--wait <ms>","extra settle in ms after navigation before snapshot (default 0; the adaptive networkidle settle runs regardless)").option("--connect <url>","CDP auto-discover and attach (host:port or ws URL)").option("--with-playwright-hints","also emit Playwright snippet per ref").option("--annotated","capture an annotated PNG with numbered badges over each ref").option("--annotate-output <path>","output path for the annotated PNG (defaults to ./skeptic-inspect-<ts>.png)").option("--no-daemon","bypass the persistent daemon and launch a fresh browser").action(async(o,t)=>{let{runInspect:e}=await import('./inspect-44KF3IPH.mjs');await e(o,t);});var E=p.command("daemon").description("Manage the persistent BrowserServer daemon (B10)");E.command("start").description("Start the daemon (foreground; auto-spawned by `run`/`inspect` when needed)").option("--engine <engine>","browser engine: chromium | firefox | webkit","chromium").option("--headed","run BrowserServer in headed mode").option("--daemon-idle-timeout <seconds>","auto-stop after N idle seconds (default 300; 0 disables)",O).action(async o=>{let{runDaemonStart:t}=await import('./daemon-7M5HNFD7.mjs');await t(o);});E.command("stop").description("Stop the running daemon").action(async()=>{let{runDaemonStop:o}=await import('./daemon-7M5HNFD7.mjs');await o();});E.command("status").description("Show daemon status (running/uptime/clients/engine)").action(async()=>{let{runDaemonStatus:o}=await import('./daemon-7M5HNFD7.mjs');await o();});E.command("logs").description("Tail the daemon log file at ~/.skeptic/daemon.log").option("-n, --lines <n>","show last N lines (default 200)",_).action(async o=>{let{runDaemonLogs:t}=await import('./daemon-7M5HNFD7.mjs');await t(o);});p.command("session-daemon",{hidden:true}).description("(internal) interactive browser-session daemon \u2014 auto-spawned by session verbs").option("--engine <engine>","browser engine","chromium").option("--headed","run headed (default)").option("--headless","run headless").option("--idle-timeout <seconds>","daemon idle shutdown",O).option("--session-idle <seconds>","per-session idle reap",O).action(async o=>{let{runSessionDaemon:t}=await import('./session-daemon-cmd-QHVSSKSL.mjs');await t(o);});var m=o=>o.option("--session <name>","isolated session name","default").option("--json","machine-readable JSON output").option("--platform <platform>","web (default) | android (adb) | ios-sim (simctl+axe)",K).option("--headed","run the session browser headed (default; web only)").option("--headless","run the session browser headless (web only)");m(p.command("open").description("Open a URL in a persistent browser session").argument("<url>","URL to open")).option("--wait-until <s>","navigation wait: load, domcontentloaded, networkidle, commit",wt).action(async(o,t)=>{let{runOpen:e}=await import('./browser-verbs-R7R6PK2G.mjs');await e(o,t);});m(p.command("snapshot").description("Snapshot the open session's page \u2014 mints @eN refs + selectorHints")).option("-i, --interactive","filter to interactive refs").option("-c, --compact","interactive + minimal ancestors").action(async o=>{let{runSnapshot:t}=await import('./browser-verbs-R7R6PK2G.mjs');await t(o);});m(p.command("click").description("Click an element (@eN ref or selector)").argument("<target>","@eN or selector")).action(async(o,t)=>{let{runClick:e}=await import('./browser-verbs-R7R6PK2G.mjs');await e(o,t);});m(p.command("fill").description("Fill an input (clears first)").argument("<target>","@eN or selector").argument("<text>","text")).action(async(o,t,e)=>{let{runFill:i}=await import('./browser-verbs-R7R6PK2G.mjs');await i(o,t,e);});m(p.command("type").description("Type into an element (no clear)").argument("<target>","@eN or selector").argument("<text>","text")).action(async(o,t,e)=>{let{runType:i}=await import('./browser-verbs-R7R6PK2G.mjs');await i(o,t,e);});m(p.command("press").description("Press a key on an element").argument("<target>","@eN or selector").argument("<key>",'e.g. "Enter"')).action(async(o,t,e)=>{let{runPress:i}=await import('./browser-verbs-R7R6PK2G.mjs');await i(o,t,e);});m(p.command("hover").description("Hover an element").argument("<target>","@eN or selector")).action(async(o,t)=>{let{runHover:e}=await import('./browser-verbs-R7R6PK2G.mjs');await e(o,t);});m(p.command("check").description("Check a checkbox").argument("<target>","@eN or selector")).action(async(o,t)=>{let{runCheck:e}=await import('./browser-verbs-R7R6PK2G.mjs');await e(o,t);});m(p.command("uncheck").description("Uncheck a checkbox").argument("<target>","@eN or selector")).action(async(o,t)=>{let{runUncheck:e}=await import('./browser-verbs-R7R6PK2G.mjs');await e(o,t);});m(p.command("select").description("Select an option").argument("<target>","@eN or selector").argument("<value>","option value")).action(async(o,t,e)=>{let{runSelect:i}=await import('./browser-verbs-R7R6PK2G.mjs');await i(o,t,e);});m(p.command("get").description("Read text|value|box|url|title from the session").argument("<query>","text | value | box | url | title").argument("[target]","@eN or selector")).action(async(o,t,e)=>{let{runGet:i}=await import('./browser-verbs-R7R6PK2G.mjs');await i(o,t,e);});m(p.command("is").description("Query a boolean element state").argument("<state>","visible | enabled | checked",Zt).argument("<target>","@eN or selector")).action(async(o,t,e)=>{let{runGet:i}=await import('./browser-verbs-R7R6PK2G.mjs');await i(o,t,e);});m(p.command("scroll").description("Scroll an element into view (<@ref>) or pan the viewport (--dx/--dy)").argument("[target]","@eN or selector")).option("--dx <n>","horizontal viewport pan (px)",ft).option("--dy <n>","vertical viewport pan (px)",ft).action(async(o,t)=>{let{runScroll:e}=await import('./browser-verbs-R7R6PK2G.mjs');await e(o,t);});m(p.command("screenshot").description("Capture a screenshot of the session (returns a file path)")).option("--name <name>","artifact name","screenshot").option("--full","full-page capture").option("--annotate","numbered badges over interactive refs").action(async o=>{let{runScreenshot:t}=await import('./browser-verbs-R7R6PK2G.mjs');await t(o);});m(p.command("console").description("Read the session's console messages (or --errors only)")).option("--errors","only uncaught errors / console.error").action(async o=>{let{runConsole:t}=await import('./browser-verbs-R7R6PK2G.mjs');await t(o);});m(p.command("record").description("Record a fixed-duration screen video of the session (Android screenrecord)")).option("--duration <seconds>","recording length (1-20s, default 3)",O).action(async o=>{let{runRecord:t}=await import('./browser-verbs-R7R6PK2G.mjs');await t(o);});for(let[o,t,e]of [["perf","performance","Read performance evidence (Android: gfxinfo/meminfo/launch; web: Web Vitals)"],["a11y","accessibility","Read accessibility evidence (Android: uiautomator heuristics; web: axe)"],["network","network","Read network evidence (Android: degraded per-uid totals; web: requests)"]])m(p.command(o).description(e)).action(async i=>{let{runObserve:n}=await import('./browser-verbs-R7R6PK2G.mjs');await n(t,i);});m(p.command("wait").description("Wait for a duration (--ms) or a selector")).option("--ms <n>","milliseconds to wait",O).option("--selector <sel>","wait for a selector").option("--state <state>","visible | hidden | attached | detached",Qt).option("--timeout-ms <n>","wait timeout",O).action(async o=>{let{runWait:t}=await import('./browser-verbs-R7R6PK2G.mjs');await t(o);});m(p.command("close").description("Close the session (--all closes every session)")).option("--all","close all sessions").action(async o=>{let{runClose:t}=await import('./browser-verbs-R7R6PK2G.mjs');await t(o);});m(p.command("list").description("List open browser sessions")).action(async o=>{let{runList:t}=await import('./browser-verbs-R7R6PK2G.mjs');await t(o);});p.command("devices").description("List connected devices/emulators (Android via adb; iOS preview via simctl)").option("--json","machine-readable JSON output").action(async o=>{let{runDevices:t}=await import('./devices-NG4P5UPS.mjs');await t(o);});p.command("audit").description("Run project lint, type-check, and quality scripts").option("--fix","attempt to auto-fix issues").action(async o=>{let{runAudit:t}=await import('./audit-ID2BSVYC.mjs');await t(o);});p.action(()=>{p.outputHelp();});
|
|
38
38
|
export{J as Timer,mt as expect,O as parseNonNegativeInt,_ as parsePositiveInt,p as program};
|
|
@@ -6,7 +6,7 @@ var m=".skeptic",$=`*
|
|
|
6
6
|
"type": "module"
|
|
7
7
|
}
|
|
8
8
|
`;async function T(s=process.cwd()){let e=r.resolve(s);d.info(`Initializing ${a} project in ${a$1.cyan(e)}`);let c$1=r.join(e,"tests");S(c$1),d.success(`Created ${a$1.dim("tests/")}`),P(e),R(e),C(e),E(c$1);let o=r.join(e,c);t.existsSync(o)?d.warn(`${c} already exists, skipping`):(t.writeFileSync(o,a$2("skeptic.config.yaml")),d.success(`Created ${a$1.dim(c)}`));let p=r.join(c$1,"example.spec.ts");t.existsSync(p)?d.warn("Example test already exists, skipping"):(t.writeFileSync(p,a$2("example.spec.ts")),d.success(`Created ${a$1.dim("tests/example.spec.ts")}`));let l=r.join(e,"tsconfig.json");t.existsSync(l)?d.warn("tsconfig.json already exists, skipping"):(t.writeFileSync(l,a$2("tsconfig.json")),d.success(`Created ${a$1.dim("tsconfig.json")}`)),d.info("Installing Playwright browsers...");try{let{runBrowsersInstall:g}=await import('./browsers-install-F2ZWEBOX.mjs');await g(["chromium"],{withDeps:!0}),d.success("Playwright Chromium installed");}catch{d.warn(`Failed to install Playwright browsers automatically.
|
|
9
|
-
Run manually: ${a$1.cyan("skeptic browsers install --with-deps chromium")}`);}console.log(),console.log(a$1.bold(" Next steps:"));let a$3=1;console.log(a$1.dim(` ${a$3}.`)+` Run ${a$1.cyan(j(e).join(" "))}`),a$3+=1,console.log(a$1.dim(` ${a$3}.`)+` Edit ${a$1.cyan(c)} with your base URL`),a$3+=1,console.log(a$1.dim(` ${a$3}.`)+` Write tests in ${a$1.cyan("tests/*.spec.ts")}`),a$3+=1,console.log(a$1.dim(` ${a$3}.`)+` Run ${a$1.cyan("skeptic run")} to execute`),console.log();}function j(s){return t.existsSync(r.join(s,"pnpm-lock.yaml"))?["pnpm","install"]:t.existsSync(r.join(s,"yarn.lock"))?["yarn","install"]:t.existsSync(r.join(s,"bun.lock"))||t.existsSync(r.join(s,"bun.lockb"))?["bun","install"]:["npm","install"]}function S(s){t.existsSync(s)||t.mkdirSync(s,{recursive:true});}function C(s){let e=r.join(s,"package.json"),c="^1.0.
|
|
9
|
+
Run manually: ${a$1.cyan("skeptic browsers install --with-deps chromium")}`);}console.log(),console.log(a$1.bold(" Next steps:"));let a$3=1;console.log(a$1.dim(` ${a$3}.`)+` Run ${a$1.cyan(j(e).join(" "))}`),a$3+=1,console.log(a$1.dim(` ${a$3}.`)+` Edit ${a$1.cyan(c)} with your base URL`),a$3+=1,console.log(a$1.dim(` ${a$3}.`)+` Write tests in ${a$1.cyan("tests/*.spec.ts")}`),a$3+=1,console.log(a$1.dim(` ${a$3}.`)+` Run ${a$1.cyan("skeptic run")} to execute`),console.log();}function j(s){return t.existsSync(r.join(s,"pnpm-lock.yaml"))?["pnpm","install"]:t.existsSync(r.join(s,"yarn.lock"))?["yarn","install"]:t.existsSync(r.join(s,"bun.lock"))||t.existsSync(r.join(s,"bun.lockb"))?["bun","install"]:["npm","install"]}function S(s){t.existsSync(s)||t.mkdirSync(s,{recursive:true});}function C(s){let e=r.join(s,"package.json"),c="^1.0.1";if(!t.existsSync(e)){let g={name:r.basename(s).replace(/[^a-zA-Z0-9._-]/g,"-")||"skeptic-project",private:true,type:"module",scripts:{"test:e2e":"skeptic run"},devDependencies:{"skeptic-cli":c}};t.writeFileSync(e,`${JSON.stringify(g,null,2)}
|
|
10
10
|
`,"utf-8"),d.success(`Created ${a$1.dim("package.json")}`);return}let o;try{o=JSON.parse(t.readFileSync(e,"utf-8"));}catch{d.warn("package.json exists but could not be parsed, skipping dependency/script update");return}let p=false;o.scripts??={},o.scripts["test:e2e"]||(o.scripts["test:e2e"]="skeptic run",p=true),o.dependencies?.["skeptic-cli"]!==void 0||o.devDependencies?.["skeptic-cli"]!==void 0||(o.devDependencies??={},o.devDependencies["skeptic-cli"]=c,p=true),p?(t.writeFileSync(e,`${JSON.stringify(o,null,2)}
|
|
11
11
|
`,"utf-8"),d.success(`Updated ${a$1.dim("package.json")} for skeptic`)):d.warn("package.json already has skeptic script/dependency, skipping");}function E(s){let e=r.join(s,"package.json");if(t.existsSync(e)){d.warn("tests/package.json already exists, skipping");return}t.writeFileSync(e,x,"utf-8"),d.success(`Created ${a$1.dim("tests/package.json")}`);}function P(s){let e=r.join(s,m);S(e);let c=r.join(e,".gitignore");if(t.existsSync(c)){d.warn(`${m}/.gitignore already exists, skipping`);return}t.writeFileSync(c,$,"utf-8"),d.success(`Created ${a$1.dim(`${m}/.gitignore`)}`);}function R(s){let e=r.join(s,".gitignore"),c=_(d$1),o=[m+"/",c],p=t.existsSync(e),l=p?t.readFileSync(e,"utf-8"):"",a=I(l),g=o.filter(w=>!a.has(y(w)));if(g.length===0){d.warn(".gitignore already ignores skeptic artifacts, skipping");return}let f=[];l.length>0&&!l.endsWith(`
|
|
12
12
|
`)&&f.push(""),l.trim().length>0&&f.push(""),f.push("# Skeptic artifacts",...g),t.appendFileSync(e,`${f.join(`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {createRequire}from'node:module';import {a as a$1,c as c$1}from'./chunk-2ZORFJJP.mjs';export{a as buildSelectorHint}from'./chunk-2ZORFJJP.mjs';import {b}from'./chunk-NXTEMSUR.mjs';import {b as b$1}from'./chunk-OHVNABCL.mjs';import {c}from'./chunk-6U6H22OR.mjs';import'./chunk-7BFRKEFV.mjs';import'./chunk-N3533BCE.mjs';import {a}from'./chunk-IYLF56WL.mjs';import {d}from'./chunk-ZN6MI2TU.mjs';import'./chunk-MHNEFL35.mjs';import'./chunk-S3M2RTHJ.mjs';import'./chunk-2YKSIUIN.mjs';import {setTimeout}from'timers/promises';import {resolve}from'path';/*! @license skeptic-cli — see LICENSES.md for third-party attributions */
|
|
2
2
|
createRequire(import.meta.url);
|
|
3
|
-
var P=0,D=1e3,Y=async(n,t)=>{let s=H(t.wait),i=await a(),{prewarmDaemonIfNeeded:o}=await import('./auto-spawn-4TO4DBO6.mjs'),e=await o(process.argv,{engine:"chromium",headed:t.headed===true,cliVersion:"1.0.
|
|
3
|
+
var P=0,D=1e3,Y=async(n,t)=>{let s=H(t.wait),i=await a(),{prewarmDaemonIfNeeded:o}=await import('./auto-spawn-4TO4DBO6.mjs'),e=await o(process.argv,{engine:"chromium",headed:t.headed===true,cliVersion:"1.0.1",noDaemon:t.daemon===false||t.connect!==void 0}),r=null,a$1=null,c=null,w=t.daemon===false||!t.connect&&!e,R=!t.connect&&w,d=null;try{if(t.connect){let f=await W(t.connect);r=await i.chromium.connectOverCDP(f),a$1=r.contexts()[0]??await r.newContext(),c=a$1.pages()[0]??await a$1.newPage();}else if(w){r=await i.chromium.launch({headless:!t.headed});let f=I(t);a$1=await r.newContext(f),c=await a$1.newPage();}else {let{connectDaemon:f}=await import('./client-UR65IKYX.mjs'),u=await f({engine:"chromium",headed:t.headed===!0,cliVersion:"1.0.1"});r=u.browser,d=u.disconnect;let m=I(t);a$1=await r.newContext(m),c=await a$1.newPage();}await c.goto(n,{waitUntil:"domcontentloaded"}),await Promise.race([c.waitForLoadState("networkidle").catch(()=>{}),setTimeout(D)]),s>0&&await setTimeout(s);let k=new b(c,n),E={interactive:t.interactive??!1,compact:t.compact??!1,selector:t.selector,includeCursorInteractive:!0,viewportAware:!1},b$2=await b$1(c,k,E),p,g;if(t.annotated){let f=resolve(t.annotateOutput??`./skeptic-inspect-${Date.now()}.png`),{captureAnnotatedScreenshot:u}=await import('./screenshot-GUJSIRQB.mjs'),m=await u(c,f,{fullPage:!1,scope:t.selector??"body"});p=m.annotations,g=m.path;}t.json?T(n,b$2,t,p,g):N(b$2,t,p,g);}finally{try{d?(await a$1?.close().catch(()=>{}),await d()):R?await r?.close():await c?.close();}catch{}}},H=n=>{if(!n)return P;let t=Number.parseInt(n,10);return !Number.isFinite(t)||t<0?P:t},I=n=>{let t={};if(n.device){let s=c(n.device);s?(t.viewport={width:s.width,height:s.height},t.deviceScaleFactor=s.dpr,s.userAgent&&(t.userAgent=s.userAgent)):d.warn(`[inspect] unknown device profile "${n.device}" \u2014 using browser defaults`);}return t};var C=n=>{if(n.kind!=="aria")return;let t=n.name?`, { name: ${JSON.stringify(n.name)}, exact: true }`:"",s=n.nth>0?`.nth(${n.nth})`:"";return `page.getByRole(${JSON.stringify(n.role)}${t})${s}`},N=(n,t,s,i)=>{if(process.stdout.write(n.yaml),n.yaml.endsWith(`
|
|
4
4
|
`)||process.stdout.write(`
|
|
5
5
|
`),n.refs.size>0){let o=new Set([...n.yaml.matchAll(/\[ref=(e\d+)\]/g)].map(e=>e[1]));process.stdout.write(`
|
|
6
6
|
`);for(let e of n.refs.values()){if(!o.has(e.ref))continue;let r=a$1(e);if(process.stdout.write(` ${e.ref} selectorHint: ${r}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {createRequire}from'node:module';import {b,a}from'./chunk-
|
|
1
|
+
import {createRequire}from'node:module';import {b,a}from'./chunk-2VGKPSCR.mjs';import {a as a$1}from'./chunk-42J77CYA.mjs';import {a as a$2}from'./chunk-YB25SMQ2.mjs';import'./chunk-EYVJTUBL.mjs';import'./chunk-EU3OXJX4.mjs';import {d}from'./chunk-CWNYWHJ2.mjs';import {d as d$3,b as b$2,a as a$8,c as c$2}from'./chunk-2N64R5DC.mjs';import'./chunk-6TLKI7UN.mjs';import {a as a$3,b as b$3}from'./chunk-NXTEMSUR.mjs';import'./chunk-7ZUWKIDM.mjs';import {b as b$4,a as a$9}from'./chunk-U3KRIAEU.mjs';import {b as b$1}from'./chunk-OHVNABCL.mjs';import {c}from'./chunk-6U6H22OR.mjs';import'./chunk-AH75LR2T.mjs';import'./chunk-RU7M6UGM.mjs';import'./chunk-2VSGDT7T.mjs';import {a as a$4}from'./chunk-B26AZRXU.mjs';import'./chunk-7BFRKEFV.mjs';import {c as c$1}from'./chunk-N3533BCE.mjs';import {a as a$7}from'./chunk-IYLF56WL.mjs';import {d as d$2}from'./chunk-ZN6MI2TU.mjs';import {d as d$1,a as a$6}from'./chunk-MHNEFL35.mjs';import {a as a$5}from'./chunk-S3M2RTHJ.mjs';import'./chunk-2YKSIUIN.mjs';import*as ce from'fs';import*as x from'path';import x__default,{join}from'path';import {writeFile,mkdir,mkdtemp,rm}from'fs/promises';import {performance as performance$1}from'perf_hooks';import {tmpdir}from'os';/*! @license skeptic-cli — see LICENSES.md for third-party attributions */
|
|
2
2
|
createRequire(import.meta.url);
|
|
3
3
|
var re=(s,e)=>(s.warnings||(s.warnings=[]),s.warnings.push(e),s);var ge=new Set(["click","doubleClick","hover","type","select","clearInput","copyTextFrom","randomType","randomEmail","randomNumber","randomPhone","press","scroll","scrollUntilVisible"]),he=s=>ge.has(s),be=async(s,e)=>{let r=e.args,a=r&&typeof r.selector=="string"?r.selector:null;if(!a)return null;try{let n=await s.locator(a).boundingBox({timeout:250}).catch(()=>null);return n?{x:Math.round(n.x+n.width/2),y:Math.round(n.y+n.height/2)}:null}catch{return null}},we=(s,e,r={})=>{let a=a$9(e),c=r.persistent===true;return s.evaluate(({label:n,persistent:d})=>{let C=globalThis.__skepticCursor;C&&typeof C.setCommandLabel=="function"&&C.setCommandLabel(n,{persistent:d});},{label:a,persistent:c}).catch(()=>{})},ye=s=>s.evaluate(()=>{let e=globalThis.__skepticCursor;e&&typeof e.clearCommandLabel=="function"&&e.clearCommandLabel();}).catch(()=>{}),ve=(s,e,r)=>{s.evaluate(({cmd:a,x:c,y:n})=>{let d=globalThis.__skepticCursor;!d||typeof d.recordAction!="function"||(typeof c=="number"&&typeof n=="number"?d.recordAction(a,c,n):d.recordAction(a));},{cmd:e,x:r?.x??null,y:r?.y??null}).catch(()=>{});},Ce={collectors:[],networkCaptureLimit:500,duplicateWindowMs:500,accessibilityDualEngine:false,accessibilityHtmlSnippetLimit:500,consoleCaptureLimit:200,consoleRedaction:true,autoAccessibilityAudit:false,accessibilityStandard:"WCAG21AA"},F=class{browser=null;options;constructor(e={}){this.options=e;}async launch(){let e=this.options.browserEngine??"chromium",r=await a$7(),a={chromium:r.chromium,firefox:r.firefox,webkit:r.webkit}[e];try{this.browser=await a.launch({headless:!this.options.headed});}catch(c){let n=c instanceof Error?c.message:String(c);throw n.includes("Executable doesn't exist")||n.includes("browserType.launch")?new Error(`Playwright browsers not found. Run: npx playwright install ${e}`):c}}async close(){this.browser&&(await this.browser.close(),this.browser=null);}async runTest(e,r){if(!this.browser)throw new Error("Browser not launched. Call launch() first.");let a=performance.now(),c=this.options.video??false,n=this.options.trace??false,d=false,C=this.options.outputDir??"./skeptic-output";await mkdir(C,{recursive:true});let S=e.name.replace(/[^a-zA-Z0-9_-]/g,"_"),E=e.testIndex??0,g=join(C,`${S}-${E}`);await mkdir(g,{recursive:true});let h=c?await mkdtemp(join(tmpdir(),`skeptic-video-${S}-`)):null,k=e.viewport??this.options.viewport??(this.options.deviceProfile?{width:this.options.deviceProfile.width,height:this.options.deviceProfile.height}:{width:1280,height:720}),w=this.options.videoSize??k,y=this.options.artifactConfig??a$3,m={name:e.name,file:e.file,status:"passed",duration_ms:0,steps:[],artifacts:{},...this.options.shardId!==void 0?{shardId:this.options.shardId}:{}},T="passed",b={viewport:k,...this.options.deviceProfile?.dpr?{deviceScaleFactor:this.options.deviceProfile.dpr}:{},...this.options.deviceProfile?.user_agent?{userAgent:this.options.deviceProfile.user_agent}:{},...c&&h?{recordVideo:{dir:h,size:w}}:{}},p=null,t=null;try{p=await this.browser.newContext(b),n&&(await p.tracing.start({screenshots:!0,snapshots:!0,sources:!1}),d=!0);let u=e.timeout??this.options.timeout??3e4;if(p.setDefaultTimeout(u),(e.auth==="cookies"||e.auth!=="none"&&this.options.cookies?.enabled)&&e.url)try{let{extractAndInjectCookies:o}=await import('./extractor-Y477MBN6.mjs'),i=new URL(e.url).hostname,P=await o(p,i,{browsers:this.options.cookies?.browser?[this.options.cookies.browser]:void 0});d$2.debug(`Injected ${P} cookies for ${i}`);}catch(o){d$2.warn(`Cookie extraction failed: ${o instanceof Error?o.message:String(o)}`);}if(t=await p.newPage(),c)try{await p.addInitScript({content:d$3});}catch(o){d$2.debug(`Cursor overlay attach failed: ${o instanceof Error?o.message:String(o)}`);}let v=this.options.observability??Ce,j=b$2({required:e.requiredCollectors??new Set,configured:v.collectors,config:v}),f=new b$3(t,e.url,g,x__default.dirname(e.file),u,j,y);for(let o of j)try{await o.attach(t,f);}catch(i){d$2.warn(`Collector "${o.name}" attach failed: ${i instanceof Error?i.message:String(i)}`),f.collectors.delete(o.name);}if(f.outputDir=g,e.runFn){let o="test";r?.({type:"step:start",index:0,total:1,command:o,args:{name:e.name}}),c&&we(t,o,{persistent:b$4.has(o)}).catch(()=>{});try{await e.runFn(t,f);}catch(i){let P=i instanceof Error?i.message:String(i),I={command:"test",args:{name:e.name},status:"failed",duration_ms:Math.round(performance.now()-a),error:P};if(re(I,P),m.steps.push(I),r?.({type:"step:complete",index:0,total:1,result:I}),this.options.screenshotOnFailure&&t&&!t.isClosed())try{let $=join(g,"failure.png"),ue=await t.screenshot({fullPage:!0});await writeFile($,ue),I.screenshot=$,f.addScreenshot($);}catch{}T="failed";}if(T==="passed"){let i={command:"test",args:{name:e.name},status:"passed",duration_ms:Math.round(performance.now()-a)};if(m.steps.push(i),r?.({type:"step:complete",index:0,total:1,result:i}),c&&i.status==="passed"&&he(i.command)&&t&&!t.isClosed()){let P=await be(t,i);ve(t,i.command,P);}}c&&t&&!t.isClosed()&&ye(t).catch(()=>{});}let L=f.collectors.get("accessibility"),le=v.autoAccessibilityAudit??!1;if(L instanceof a$8&&le&&f.abortReason===null&&t&&!t.isClosed()&&!(await L.snapshot()!==void 0))try{await L.audit({standard:v.accessibilityStandard??"WCAG21AA",...v.accessibilityImpacts?{impacts:v.accessibilityImpacts}:{}});}catch(i){d$2.warn(`Auto a11y audit failed: ${i instanceof Error?i.message:String(i)}`);}let _={};f.inTeardown=!0;try{for(let o of f.collectors.values())try{let i=await o.snapshot();i!=null&&(_[o.name]=i);}catch(i){d$2.warn(`Collector "${o.name}" snapshot failed: ${i instanceof Error?i.message:String(i)}`);}for(let o of f.collectors.values())try{await o.detach();}catch(i){d$2.warn(`Collector "${o.name}" detach failed: ${i instanceof Error?i.message:String(i)}`);}}finally{f.inTeardown=!1;}if(y.visualSettle.enabled&&t&&!t.isClosed())try{await c$1(t,f,y.visualSettle);}catch(o){d$2.debug(`Pre-video settle failed: ${o instanceof Error?o.message:String(o)}`);}if(f.screenshots.length>0&&(m.artifacts.screenshots=[...f.screenshots]),c&&t)try{let o=t.video();if(o){let i=join(g,`${S}.webm`);await t.close(),t=null,await o.saveAs(i),h&&await rm(h,{recursive:!0,force:!0}).catch(()=>{}),m.artifacts.video={path:i,width:w.width,height:w.height},d$2.info(`Video saved to ${i}`);}}catch(o){d$2.warn(`Video save failed: ${o instanceof Error?o.message:String(o)}`);}if(d&&p)try{let o=join(g,`${S}.trace.zip`);await p.tracing.stop({path:o}),m.artifacts.trace=o,d=!1,d$2.info(`Trace saved. View with: npx playwright show-trace ${o}`);}catch(o){d$2.warn(`Trace save failed: ${o instanceof Error?o.message:String(o)}`);}return m.status=T,m.duration_ms=Math.round(performance.now()-a),Object.keys(_).length>0&&(m.metrics=_),y.writeSidecars&&await c$2({testDir:g,metrics:_,artifacts:m.artifacts,observabilityConfig:v}),m}finally{if(d&&p)try{let u=join(g,`${S}.trace.zip`);await p.tracing.stop({path:u});}catch{}t&&!t.isClosed()&&await t.close().catch(()=>{}),p&&await p.close().catch(()=>{}),h&&await rm(h,{recursive:true,force:true}).catch(()=>{});}}};var Se=s=>s.tui!==false,ke=()=>new Date().toISOString().replace(/[:.]/g,"-"),Pe=s=>{try{return new URL(s).hostname.replace(/[^a-zA-Z0-9_-]/g,"_")||"page"}catch{return "page"}},tt=async(s,e)=>{let r=d({configPath:e.config,overrides:{}}),a$7=e.output??x.join(r.output.dir??d$1,`observe-${ke()}`);ce.mkdirSync(a$7,{recursive:true});let c$1=e.device??r.browser.device,n=c$1?c(c$1):void 0,d$3=n?{width:n.width,height:n.height}:r.browser.viewport,C=n?{width:n.width,height:n.height,dpr:n.dpr,user_agent:n.userAgent}:void 0,S=e.videoSize?b(e.videoSize):d$3,E=e.timeout??r.browser.timeout,g=new Set(["performance","network","console","accessibility"]),h=`observe ${Pe(s)}`,k=`skeptic observe ${s}`,w=[...Se(e)?[new a]:[],new a$1(a$7),new a$2(a$7)],y={name:h,file:k,testIndex:0};for(let b of w)b.onRunStart?.({tests:[{name:h,file:k,stepCount:1}],totalTests:1}),b.onTestStart(y);let m=new F({headed:e.headed??!r.browser.headless,timeout:E,outputDir:a$7,browserEngine:r.browser.engine,viewport:d$3,deviceProfile:C,video:e.video??true,videoSize:S,trace:e.trace??true,screenshotOnFailure:true,cookies:e.cookies??r.auth.cookies?{enabled:e.cookies??r.auth.cookies,...e.cookiesFrom?{browser:e.cookiesFrom}:{}}:void 0,observability:{collectors:[...g],networkCaptureLimit:r.observability.networkCaptureLimit,duplicateWindowMs:r.observability.duplicateWindowMs,accessibilityDualEngine:true,accessibilityHtmlSnippetLimit:r.observability.accessibilityHtmlSnippetLimit,consoleCaptureLimit:r.observability.consoleCaptureLimit,consoleRedaction:r.observability.consoleRedaction,autoAccessibilityAudit:true,accessibilityStandard:r.observability.accessibilityStandard,...r.observability.accessibilityImpacts?{accessibilityImpacts:r.observability.accessibilityImpacts}:{},accessibilityMaxRulesPerImpact:r.observability.accessibilityMaxRulesPerImpact},artifactConfig:{...a$3,fullPageScreenshots:e.fullPage??r.observability.fullPageScreenshots,blankFrameDetection:r.observability.blankFrameDetection,writeSidecars:true}}),T=performance$1.now();try{await m.launch();let b=await m.runTest({url:s,name:h,file:k,timeout:E,viewport:d$3,requiredCollectors:g,runFn:async(t,u)=>{await t.goto(s,{waitUntil:e.waitUntil??"domcontentloaded"}),e.wait&&e.wait>0&&await t.waitForTimeout(e.wait),await a$4(t,u,"01-page",{fullPage:e.fullPage??r.observability.fullPageScreenshots}),await a$4(t,u,"02-page-annotated",{annotate:!0,fullPage:e.fullPage??r.observability.fullPageScreenshots});let A=await b$1(t,u,{compact:!0}),v={url:t.url(),title:await t.title(),yaml:A.yaml,stats:A.stats,refs:[...A.refs.values()]};await writeFile(x.join(u.testDir,"snapshot.txt"),A.yaml,"utf-8"),await writeFile(x.join(u.testDir,"snapshot.json"),JSON.stringify(v,null,2),"utf-8");}},t=>{if(t.type==="step:start")for(let u of w)u.onStepStart?.({command:t.command,args:t.args},t.index,t.total,y);else for(let u of w)u.onStepComplete(t.result,t.index,t.total,y);});for(let t of w)t.onTestComplete(b,y);let p={total:1,passed:b.status==="passed"?1:0,failed:b.status==="passed"?0:1,skipped:0,duration_ms:Math.round(performance$1.now()-T),tests:[b]};for(let t of w)await t.onRunComplete(p);d$2.raw(""),d$2.raw(a$5.bold(` ${a$6} observe artifacts`));for(let[t,u]of [["Report",x.join(a$7,"report.html")],["JSON",x.join(a$7,"results.json")],["Output",a$7]])d$2.raw(` ${a$5.dim(t.padEnd(8))} ${a$5.cyan(u)}`);d$2.raw(""),process.exitCode=b.status==="passed"?0:1;}finally{await m.close().catch(()=>{});}};export{Se as observeShowsLiveConsole,tt as runObserve};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {createRequire}from'node:module';export{c as buildWorkerConfig,d as ensureJsonReporter,b as parseVideoSize,e as resolveRunExitCode,f as runRun}from'./chunk-
|
|
1
|
+
import {createRequire}from'node:module';export{c as buildWorkerConfig,d as ensureJsonReporter,b as parseVideoSize,e as resolveRunExitCode,f as runRun}from'./chunk-2VGKPSCR.mjs';import'./chunk-EU3OXJX4.mjs';import'./chunk-CWNYWHJ2.mjs';import'./chunk-6U6H22OR.mjs';import'./chunk-AH75LR2T.mjs';import'./chunk-RU7M6UGM.mjs';import'./chunk-2VSGDT7T.mjs';import'./chunk-IYLF56WL.mjs';import'./chunk-ZN6MI2TU.mjs';import'./chunk-MHNEFL35.mjs';import'./chunk-S3M2RTHJ.mjs';import'./chunk-2YKSIUIN.mjs';/*! @license skeptic-cli — see LICENSES.md for third-party attributions */
|
|
2
2
|
createRequire(import.meta.url);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import {createRequire}from'node:module';import {a as a$2}from'./chunk-COVGJJ47.mjs';import {b,a}from'./chunk-IXBYLSGB.mjs';import {b as b$2}from'./chunk-2ZORFJJP.mjs';import {c as c$1,b as b$1}from'./chunk-6TLKI7UN.mjs';import'./chunk-NXTEMSUR.mjs';import'./chunk-OHVNABCL.mjs';import {m as m$1,j as j$1,k,h as h$1,n,p as p$1,i,l,o}from'./chunk-2VSGDT7T.mjs';import'./chunk-B26AZRXU.mjs';import'./chunk-7BFRKEFV.mjs';import'./chunk-N3533BCE.mjs';import {a as a$1}from'./chunk-IYLF56WL.mjs';import {c}from'./chunk-ZN6MI2TU.mjs';import'./chunk-MHNEFL35.mjs';import'./chunk-S3M2RTHJ.mjs';import'./chunk-2YKSIUIN.mjs';import*as m from'fs';/*! @license skeptic-cli — see LICENSES.md for third-party attributions */
|
|
2
2
|
createRequire(import.meta.url);
|
|
3
3
|
function H(){c(process.stderr);}var y=class{tail=Promise.resolve();run(e){let s=this.tail.then(e,e);return this.tail=s.then(()=>{},()=>{}),s}},p=class{constructor(e){this.opts=e;this.idleSeconds=e.sessionIdleSeconds??180,this.now=e.now??Date.now;}opts;driver=null;sessions=new Map;pending=new Map;driverPromise=null;idleSeconds;now;get size(){return this.sessions.size}has(e){return this.sessions.has(e)}ensureDriver(){return this.driver?Promise.resolve(this.driver):this.driverPromise?this.driverPromise:(this.driverPromise=(async()=>{if(this.opts.createDriver)this.driver=await this.opts.createDriver();else {let s=await(await a$1())[this.opts.engine].launch({headless:!this.opts.headed});this.driver=a$2.fromBrowser(s,true);}return this.driver})(),this.driverPromise)}getOrCreate(e){let s=this.sessions.get(e);if(s)return this.touch(s),Promise.resolve(s);let t=this.pending.get(e);if(t)return t;let r=(async()=>{try{let o=await(await this.ensureDriver()).newSession({artifactDir:l(e)});this.opts.onSessionCreate&&await this.opts.onSessionCreate(o);let a={name:e,session:o,mutex:new y,idle:null,createdAt:this.now(),lastUsedAt:this.now(),url:""};return this.sessions.set(e,a),this.touch(a),this.opts.onChange?.(),a}finally{this.pending.delete(e);}})();return this.pending.set(e,r),r}async run(e,s){let t=await this.getOrCreate(e);return t.mutex.run(async()=>{this.touch(t);let r=await s(t.session);return t.url=t.session.url(),r})}async close(e){let s=this.sessions.get(e);return s?(s.idle&&clearTimeout(s.idle),this.sessions.delete(e),await s.session.close().catch(()=>{}),this.opts.onChange?.(),true):false}async closeAll(){let e=[...this.sessions.keys()];for(let s of e)await this.close(s);this.driver&&(await this.driver.close().catch(()=>{}),this.driver=null);}list(){let e=this.now();return [...this.sessions.values()].map(s=>({name:s.name,url:s.url,ageMs:e-s.createdAt,idleMs:e-s.lastUsedAt}))}touch(e){e.lastUsedAt=this.now(),e.idle&&clearTimeout(e.idle),this.idleSeconds>0&&(e.idle=setTimeout(()=>{this.close(e.name);},this.idleSeconds*1e3),e.idle.unref?.());}};var u=n=>({result:n}),d=n=>({error:n}),F="Stable artifact: copy a selectorHint into your test. In this session @eN refs persist until navigation or the next `skeptic snapshot`.",j=n=>typeof n.session=="string"&&n.session?n.session:"default",h=(n,e)=>n.has(e)?null:`no open session "${e}" \u2014 run \`skeptic open <url>\` first`,_=async(n,e)=>{if(typeof e.ref=="string"&&e.ref)return n.resolveRef(e.ref);if(typeof e.selector=="string"&&e.selector)return n.resolveSelector(e.selector);throw new Error("a ref (@eN) or --selector is required")},q=async(n,e,s)=>{switch(e){case "click":return n.click();case "fill":return n.fill(String(s.text??""));case "type":return n.type(String(s.text??""));case "press":return n.press(String(s.key??""));case "hover":return n.hover();case "check":return n.check();case "uncheck":return n.uncheck();case "select":return n.selectOption(s.value??"");case "scrollIntoView":return n.scrollIntoView();default:throw new Error(`unknown act verb "${e}"`)}};async function L(n,e){let s=n.params??{},t=j(s);try{switch(n.method){case "session.open":{let r=String(s.url??"");if(!r)return d("session.open: a url is required");let i=await e.run(t,async o=>(await o.open(r,{...typeof s.waitUntil=="string"?{waitUntil:s.waitUntil}:{},...s.timeoutMs!==void 0?{timeoutMs:Number(s.timeoutMs)}:{}}),{session:t,url:o.url(),title:await o.title()}));return u(i)}case "session.snapshot":{let r=h(e,t);if(r)return d(r);let i=await e.run(t,async o=>{let a=await o.snapshot({viewport:s.viewport!==!1,includeCursorInteractive:!0,extractLinkHrefs:!0}),c=b$2(a,{interactive:!!s.interactive,compact:!!s.compact});return {session:t,url:o.url(),title:await o.title(),yaml:c.yaml,refs:c.refs,stats:c.stats,truncated:a.truncated,note:F}});return u(i)}case "session.act":{let r=h(e,t);if(r)return d(r);let i=String(s.verb??""),o=await e.run(t,async a=>{if(i==="scroll")return await a.scroll({dx:Number(s.dx??0),dy:Number(s.dy??0)}),{ok:!0,verb:i};let c=await _(a,s);return await q(c,i,s),{ok:!0,verb:i,target:s.ref??s.selector}});return u(o)}case "session.query":{let r=h(e,t);if(r)return d(r);let i=String(s.query??"text"),o=await e.run(t,async a=>{if(i==="url")return {value:a.url()};if(i==="title")return {value:await a.title()};let c=await _(a,s);if(i==="text")return {value:await c.textContent()};if(i==="box")return {value:await c.boundingBox()};if(i==="visible")return {value:await c.isVisible()};if(i==="enabled")return {value:await c.isEnabled()};if(i==="checked")return {value:await c.isChecked()};if(i==="value")return {value:await c.inputValue()};throw new Error(`unsupported query "${i}" (supported: text, value, box, visible, enabled, checked, url, title)`)});return u(o)}case "session.screenshot":{let r=h(e,t);if(r)return d(r);let i=String(s.name??"screenshot"),o=await e.run(t,async a=>{let c=await a.screenshot(i,{fullPage:!!s.fullPage,annotate:!!s.annotate});return {path:c.path,...c.annotations?{annotations:c.annotations}:{}}});return u(o)}case "session.record":{let r=h(e,t);if(r)return d(r);let i=Number(s.durationSec??3),o=await e.run(t,async a=>{if(!a.recordVideo)throw new Error("video recording is only supported on the Android driver; for web use `skeptic run --video`");return a.recordVideo(i)});return u(o)}case "session.observe":{let r=h(e,t);if(r)return d(r);let i=String(s.collector??"console"),o=await e.run(t,async a=>{let c=await a.collectEvidence();if(i==="errors"){let f=(c.console?.messages??[]).filter(l=>l.type==="error");return {collector:"errors",errors:f,count:f.length}}return {collector:i,snapshot:c[i]??null}});return u(o)}case "session.wait":{let r=h(e,t);if(r)return d(r);let i=await e.run(t,async o=>{if(s.ms!==void 0)return await o.wait(Number(s.ms)),{ok:!0};if(typeof s.selector=="string"&&s.selector)return await(await o.resolveSelector(s.selector)).waitFor({...typeof s.state=="string"?{state:s.state}:{},...s.timeoutMs!==void 0?{timeoutMs:Number(s.timeoutMs)}:{}}),{ok:!0};throw new Error("session.wait needs --ms or a selector")});return u(i)}case "session.close":{let r=await e.close(t);return u({closed:r,session:t})}case "session.list":return u({sessions:e.list()});default:return d(`unknown session method: ${n.method}`)}}catch(r){return d(r instanceof Error?r.message:String(r))}}var $=n=>n==="chromium"||n==="firefox"||n==="webkit",z=1024*1024,G=()=>{let n=i(),e=null;try{e=m.readFileSync(n,"utf8").trim();}catch{}if(e){let s=Number(e);if(Number.isFinite(s)&&s>0&&a(s)&&s!==process.pid)throw new Error(`session daemon already running at PID ${s}`);B();}m.writeFileSync(n,String(process.pid),{mode:384});},B=()=>{for(let n of [i(),j$1(),k()])try{m.unlinkSync(n);}catch{}},J=async n=>{await n.attachCollectors([new c$1({captureLimit:500,redact:true}),new b$1({captureLimit:500,duplicateWindowMs:50})]);},U=async n$1=>{m$1(),G(),m.writeFileSync(j$1(),n$1.cliVersion,{mode:384}),m.writeFileSync(k(),`${n$1.engine}
|
|
4
|
-
${n$1.headed?"headed":"headless"}`,{mode:384});let e=null,t=$(n$1.engine)?void 0:n$1.engine==="ios-sim"?async()=>{let{IosSimDriver:l}=await import('./simctl-driver-PNUN7W7G.mjs');return l.create()}:async()=>{let{AdbDriver:l}=await import('./adb-driver-TBOCCKEO.mjs');return l.create()},r=new p({engine:$(n$1.engine)?n$1.engine:"chromium",headed:n$1.headed,sessionIdleSeconds:n$1.sessionIdleSeconds??180,...t?{createDriver:t}:{onSessionCreate:J},onChange:()=>o.reset()}),i=h$1();n(i);let o=new b(n$1.idleTimeoutSeconds??600,()=>{if(r.size>0){o.arm();return}a();}),a=l=>e||(e=(async()=>{o.disarm();try{await r.closeAll();}catch{}try{await g.close();}catch{}B();try{m.unlinkSync(i);}catch{}})(),e),g=await p$1(i,(l,P)=>(P.onActivity(),o.reset(),l.method==="daemon.ping"?Promise.resolve(W(l.params,n$1)):l.method==="daemon.shutdown"?(P.close(),a(),Promise.resolve({result:{ok:true}})):l.method==="daemon.status"?Promise.resolve({result:{ok:true,engine:n$1.engine,headed:n$1.headed,sessions:r.size}}):L(l,r)),{onAccept:()=>o.reset(),maxLineBytes:z});o.arm();let f=l=>{a().then(()=>process.exit(0));};return process.on("SIGTERM",f),process.on("SIGINT",f),process.on("SIGHUP",f),{registry:r,socket:g,shutdown:a}},W=(n,e)=>{let s=n??{};return o(s.authToken)?typeof s.engine=="string"&&s.engine!==e.engine?{result:{ok:false,reason:"engine-mismatch"}}:typeof s.headed=="boolean"&&s.headed!==e.headed?{result:{ok:false,reason:"headed-mismatch"}}:typeof s.cliVersion=="string"&&s.cliVersion!==e.cliVersion?{result:{ok:false,reason:"version-mismatch"}}:{result:{ok:true,sessions:e.engine}}:{result:{ok:false,reason:"auth-failed"}}};var K=["chromium","firefox","webkit","android","ios-sim"],he=async n=>{H();let e=K.includes(n.engine)?n.engine:"chromium",s=n.headless!==true;try{await U({engine:e,headed:s,cliVersion:"1.0.
|
|
4
|
+
${n$1.headed?"headed":"headless"}`,{mode:384});let e=null,t=$(n$1.engine)?void 0:n$1.engine==="ios-sim"?async()=>{let{IosSimDriver:l}=await import('./simctl-driver-PNUN7W7G.mjs');return l.create()}:async()=>{let{AdbDriver:l}=await import('./adb-driver-TBOCCKEO.mjs');return l.create()},r=new p({engine:$(n$1.engine)?n$1.engine:"chromium",headed:n$1.headed,sessionIdleSeconds:n$1.sessionIdleSeconds??180,...t?{createDriver:t}:{onSessionCreate:J},onChange:()=>o.reset()}),i=h$1();n(i);let o=new b(n$1.idleTimeoutSeconds??600,()=>{if(r.size>0){o.arm();return}a();}),a=l=>e||(e=(async()=>{o.disarm();try{await r.closeAll();}catch{}try{await g.close();}catch{}B();try{m.unlinkSync(i);}catch{}})(),e),g=await p$1(i,(l,P)=>(P.onActivity(),o.reset(),l.method==="daemon.ping"?Promise.resolve(W(l.params,n$1)):l.method==="daemon.shutdown"?(P.close(),a(),Promise.resolve({result:{ok:true}})):l.method==="daemon.status"?Promise.resolve({result:{ok:true,engine:n$1.engine,headed:n$1.headed,sessions:r.size}}):L(l,r)),{onAccept:()=>o.reset(),maxLineBytes:z});o.arm();let f=l=>{a().then(()=>process.exit(0));};return process.on("SIGTERM",f),process.on("SIGINT",f),process.on("SIGHUP",f),{registry:r,socket:g,shutdown:a}},W=(n,e)=>{let s=n??{};return o(s.authToken)?typeof s.engine=="string"&&s.engine!==e.engine?{result:{ok:false,reason:"engine-mismatch"}}:typeof s.headed=="boolean"&&s.headed!==e.headed?{result:{ok:false,reason:"headed-mismatch"}}:typeof s.cliVersion=="string"&&s.cliVersion!==e.cliVersion?{result:{ok:false,reason:"version-mismatch"}}:{result:{ok:true,sessions:e.engine}}:{result:{ok:false,reason:"auth-failed"}}};var K=["chromium","firefox","webkit","android","ios-sim"],he=async n=>{H();let e=K.includes(n.engine)?n.engine:"chromium",s=n.headless!==true;try{await U({engine:e,headed:s,cliVersion:"1.0.1",...typeof n.idleTimeout=="number"?{idleTimeoutSeconds:n.idleTimeout}:{},...typeof n.sessionIdle=="number"?{sessionIdleSeconds:n.sessionIdle}:{}});}catch(t){console.error(`session-daemon: ${t instanceof Error?t.message:String(t)}`),process.exit(1);}await new Promise(()=>{});};export{he as runSessionDaemon};
|
package/dist/skeptic.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {createRequire}from'node:module';/*! @license skeptic-cli — see LICENSES.md for third-party attributions */
|
|
3
3
|
createRequire(import.meta.url);
|
|
4
|
-
if(process.argv.length===3){let s=process.argv[2];(s==="--version"||s==="-V")&&(console.log("1.0.
|
|
4
|
+
if(process.argv.length===3){let s=process.argv[2];(s==="--version"||s==="-V")&&(console.log("1.0.1"),process.exit(0)),s==="--features"&&(console.log(JSON.stringify({COOKIE_EXTRACTION:true,RECORDING:true},null,2)),process.exit(0));}(async()=>{let{program:s}=await import('./index.mjs');await s.parseAsync(process.argv);})().catch(s=>{console.error(s instanceof Error?s.stack||s.message:String(s)),process.exit(1);});
|
package/dist/worker.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import {createRequire}from'node:module';import {b as b$4}from'./chunk-2ZORFJJP.mjs';import {d,b as b$2,a as a$3,c as c$1}from'./chunk-2N64R5DC.mjs';import'./chunk-6TLKI7UN.mjs';import {b as b$1}from'./chunk-NXTEMSUR.mjs';import'./chunk-7ZUWKIDM.mjs';import {a,b,d as d$1}from'./chunk-I4JX25Y5.mjs';import'./chunk-U3KRIAEU.mjs';import'./chunk-OHVNABCL.mjs';import {c}from'./chunk-6U6H22OR.mjs';import'./chunk-B26AZRXU.mjs';import {a as a$4}from'./chunk-7BFRKEFV.mjs';import {a as a$2,b as b$3}from'./chunk-N3533BCE.mjs';import'./chunk-K65JNLTT.mjs';import {a as a$1}from'./chunk-IYLF56WL.mjs';import'./chunk-ZN6MI2TU.mjs';import'./chunk-MHNEFL35.mjs';import'./chunk-S3M2RTHJ.mjs';import'./chunk-2YKSIUIN.mjs';import {isMainThread,parentPort,workerData}from'worker_threads';import {mkdir}from'fs/promises';import {existsSync}from'fs';import {createHash}from'crypto';import R from'path';import {pathToFileURL}from'url';import {tsImport}from'tsx/esm/api';/*! @license skeptic-cli — see LICENSES.md for third-party attributions */
|
|
2
2
|
createRequire(import.meta.url);
|
|
3
|
-
var n=e=>{parentPort?.postMessage(e);},ie=async e=>{let r=a(e);try{await tsImport(pathToFileURL(e).href,import.meta.url);}finally{b();}return r},fe=e=>{let r=e.tests.map(t=>({id:t.id,file:t.file,ordinal:t.ordinal,name:t.name,skip:t.skip,only:t.only,use:{...e.fileUse,...t.use}}));return {file:e.file,fileUse:{...e.fileUse},hookCount:{beforeEach:e.beforeEach.length,afterEach:e.afterEach.length},tests:r}},pe=async e=>{try{let r=await ie(e),t=fe(r);parentPort?.postMessage({type:"manifest",manifest:t});}catch(r){parentPort?.postMessage({type:"error",error:{message:r instanceof Error?r.message:String(r),stack:r instanceof Error?r.stack??"":""}});}finally{process.exit(0);}},H=e=>e.replace(/[^a-zA-Z0-9_-]/g,"_"),oe=e=>{let r=H(R.basename(e).replace(/\.[^./\\]+$/,""))||"spec",t=createHash("sha1").update(e).digest("hex").slice(0,8);return `${r}-${t}`},re=async(e,r,t)=>{if(t.screenshotOnFailure!==false&&!(!e||e.isClosed()))try{let c=R.join(r,"failure.png");return await e.screenshot({path:c,fullPage:!0}),c}catch{return}},he=async e=>{if(!(!e||e.isClosed()))try{let r=await a$4(e,"body",{viewport:!0,includeCursorInteractive:!0,extractLinkHrefs:!0}),t=b$4(r,{interactive:!0});return t.refs.length===0?void 0:{url:e.url(),yaml:t.yaml,candidates:t.refs.slice(0,25).map(c=>({ref:c.ref,role:c.role,name:c.name,selectorHint:c.selectorHint}))}}catch{return}},ge=async(e,r,t,c$2)=>{let E=performance.now();for(let[s,o]of Object.entries(t.envOverrides))process.env[s]=o;let y=H(e.name||`test-${e.ordinal}`),d$2=R.join(t.outputDir,`${oe(r.file)}-${y}-${e.ordinal}`);await mkdir(d$2,{recursive:true});let f={...r.fileUse,...e.use},a=f.device??t.device,l=a?c(a):void 0,b=f.viewport??(l?{width:l.width,height:l.height}:void 0)??t.viewport??{width:1280,height:720},I=f.timeout??t.timeout,C=f.hardTimeout??t.hardTimeout,h=t.videoSize??f.videoSize??b,T=t.baseUrl??f.url,$=R.join(d$2,`${y}.har`),g=await c$2.newContext({viewport:b,...T?{baseURL:T}:{},...l?.dpr?{deviceScaleFactor:l.dpr}:{},...l?.userAgent?{userAgent:l.userAgent}:{},...t.video?{recordVideo:{dir:d$2,size:h}}:{},...t.har?{recordHar:{path:$,content:"embed"}}:{}}),m=f.cookies;if((t.cookies?.enabled===true||m===true||typeof m=="object")&&T)try{let{extractAndInjectCookies:s}=await import('./extractor-Y477MBN6.mjs'),o=new URL(T).hostname,z=typeof m=="object"?m.browser:t.cookies?.browser;await s(g,o,{...z?{browsers:[z]}:{}});}catch(s){n({type:"log",level:"warn",message:`[skeptic] cookie extraction failed: ${s instanceof Error?s.message:String(s)}`});}if(t.trace&&await g.tracing.start({screenshots:true,snapshots:true,sources:false}),t.video)try{await g.addInitScript({content:d});}catch(s){n({type:"log",level:"warn",message:`[skeptic] cursor overlay init script failed: ${s instanceof Error?s.message:String(s)}`});}g.setDefaultTimeout(I);let S=await g.newPage(),A=f.collectors??[],w=new Set;t.observability.forceAll&&(w.add("performance"),w.add("network"),w.add("console"),w.add("accessibility"));for(let s of A)w.add(s);let v={collectors:[...w],networkCaptureLimit:t.observability.networkCaptureLimit,duplicateWindowMs:t.observability.duplicateWindowMs,accessibilityDualEngine:t.observability.accessibilityDualEngine,accessibilityHtmlSnippetLimit:t.observability.accessibilityHtmlSnippetLimit,consoleCaptureLimit:t.observability.consoleCaptureLimit,consoleRedaction:t.observability.consoleRedaction,autoAccessibilityAudit:t.observability.autoAccessibilityAudit,accessibilityStandard:t.observability.accessibilityStandard,accessibilityMaxRulesPerImpact:t.observability.accessibilityMaxRulesPerImpact},i=b$2({required:w,configured:[],config:v}),k=t.visualSettle??t.observability.forceAll,B={fullPageScreenshots:t.artifact.fullPageScreenshots,visualSettle:k?b$3:a$2,blankFrameDetection:t.artifact.blankFrameDetection,writeSidecars:t.artifact.writeSidecars},p=new b$1(S,t.baseUrl??f.url??"",d$2,R.dirname(r.file),I,i,B);for(let s of i)try{await s.attach(S,p);}catch(o){n({type:"log",level:"warn",message:`[skeptic] collector ${s.name} attach failed: ${o instanceof Error?o.message:String(o)}`}),p.collectors.delete(s.name);}let O=[],_=d$1(S,p,{onAction:s=>{s.status==="completed"?O.push({command:s.label,args:{},status:"passed",duration_ms:s.durationMs??0}):s.status==="failed"&&O.push({command:s.label,args:{},status:"failed",duration_ms:s.durationMs??0,error:s.error}),n({type:"test:action",testId:e.id,label:s.label,status:s.status,...s.durationMs!==void 0?{durationMs:s.durationMs}:{},...s.error!==void 0?{error:s.error}:{}});},enableCursorProxy:t.video}),u={name:e.name,file:r.file,testIndex:e.ordinal,status:"passed",duration_ms:0,steps:O,artifacts:{},...t.shardId!==void 0?{shardId:t.shardId}:{}},j,ne=new Promise(s=>{j=setTimeout(()=>{p.abortReason=`test timeout exceeded (${C}ms)`,S.context().close().catch(()=>{}),s("hard-timeout");},C);}),F,P;try{for(let o of r.beforeEach)await _.runAction("beforeEach",()=>Promise.resolve(o.fn(_)));await Promise.race([Promise.resolve(e.skip?void 0:r.tests[e.ordinal]?.fn(_)).then(()=>"ok"),ne])==="hard-timeout"&&(u.status="failed",F=p.abortReason??`test timeout exceeded (${C}ms)`,P=await re(S,d$2,t));}catch(s){u.status="failed",F=s instanceof Error?s.message:String(s),P=await re(S,d$2,t);let o=await he(S);o&&(u.healing=o);}finally{j&&clearTimeout(j);}P&&p.addScreenshot(P),p.inTeardown=true;try{for(let s of r.afterEach)try{await _.runAction("afterEach",()=>Promise.resolve(s.fn(_)));}catch(o){n({type:"log",level:"warn",message:`[skeptic] afterEach failed: ${o instanceof Error?o.message:String(o)}`});}}finally{p.inTeardown=false;}let L=p.collectors.get("accessibility");if(L instanceof a$3&&v.autoAccessibilityAudit&&p.abortReason===null&&!S.isClosed()&&!(await L.snapshot()!==void 0))try{await L.audit({standard:v.accessibilityStandard});}catch(o){n({type:"log",level:"warn",message:`[skeptic] auto a11y audit failed: ${o instanceof Error?o.message:String(o)}`});}let x={};for(let s of p.collectors.values())try{let o=await s.snapshot();o!=null&&(x[s.name]=o);}catch(o){n({type:"log",level:"warn",message:`[skeptic] collector ${s.name} snapshot failed: ${o instanceof Error?o.message:String(o)}`});}for(let s of p.collectors.values())try{await s.detach();}catch{}if(t.trace)try{let s=R.join(d$2,`${y}.trace.zip`);await g.tracing.stop({path:s}),u.artifacts.trace=s;}catch{}if(Object.keys(x).length>0&&(u.metrics=x),p.screenshots.length>0&&(u.artifacts.screenshots=[...p.screenshots]),B.writeSidecars&&Object.keys(x).length>0&&await c$1({testDir:d$2,metrics:x,artifacts:u.artifacts,observabilityConfig:v}),t.video)try{let s=S.video();if(s){let o=R.join(d$2,`${y}.webm`);await S.close().catch(()=>{}),await s.saveAs(o),u.artifacts.video={path:o,width:h.width,height:h.height};}}catch(s){n({type:"log",level:"warn",message:`[skeptic] video save failed: ${s instanceof Error?s.message:String(s)}`});}if(await g.close().catch(()=>{}),t.har)try{existsSync($)&&(u.artifacts.har=$);}catch{}return u.duration_ms=Math.round(performance.now()-E),F?(u.status="failed",u.steps.push({command:"test",args:{name:e.name},status:"failed",duration_ms:u.duration_ms,error:F,...P?{screenshot:P}:{}})):e.skip?(u.status="passed",u.skipped=true,u.steps.push({command:"test",args:{name:e.name},status:"skipped",duration_ms:0})):u.steps.push({command:"test",args:{name:e.name},status:"passed",duration_ms:u.duration_ms}),u},we=async e=>{if(e.target)return e.target;let{listDevices:r}=await import('./adb-DUGGW3FV.mjs'),t=(await r().catch(()=>[])).filter(c=>c.state==="device");if(t.length===0)throw new Error("[android] no device/emulator found. Start one (or pass --target <serial>); `skeptic devices` lists them.");return t[0].serial},ye=async(e,r)=>{if(e.platform==="ios-sim"){let{IosSimDriver:y}=await import('./simctl-driver-PNUN7W7G.mjs');return (await y.create({...e.target?{udid:e.target}:{}})).newSession({artifactDir:r})}let{createAdb:t}=await import('./adb-DUGGW3FV.mjs'),{AndroidAdbDriverSession:c}=await import('./adb-session-AVVXL3QQ.mjs'),E=await we(e);return new c(t({serial:E}),E,r)},be=async(e,r,t)=>{let c=performance.now();for(let[i,k]of Object.entries(t.envOverrides))process.env[i]=k;let E=H(e.name||`test-${e.ordinal}`),y=R.join(t.outputDir,`${oe(r.file)}-${E}-${e.ordinal}`);await mkdir(y,{recursive:true});let d={...r.fileUse,...e.use},f=d.timeout??t.timeout,a=d.hardTimeout??t.hardTimeout,{buildDeviceFixture:l,unavailable:b}=await import('./device-fixture-MJSDIP75.mjs'),I=await ye(t,y),C={fullPageScreenshots:false,visualSettle:a$2,blankFrameDetection:"off",writeSidecars:false},h=new b$1(b("page","web"),t.baseUrl??d.url??"",y,R.dirname(r.file),f,[],C),T=[],g=l(I,h,{onAction:i=>{i.status==="completed"?T.push({command:i.label,args:{},status:"passed",duration_ms:i.durationMs??0}):i.status==="failed"&&T.push({command:i.label,args:{},status:"failed",duration_ms:i.durationMs??0,error:i.error}),n({type:"test:action",testId:e.id,label:i.label,status:i.status,...i.durationMs!==void 0?{durationMs:i.durationMs}:{},...i.error!==void 0?{error:i.error}:{}});}}),m={name:e.name,file:r.file,testIndex:e.ordinal,status:"passed",duration_ms:0,steps:T,artifacts:{},...t.shardId!==void 0?{shardId:t.shardId}:{}},D,S=new Promise(i=>{D=setTimeout(()=>{h.abortReason=`test timeout exceeded (${a}ms)`,i("hard-timeout");},a);}),A,w;try{for(let k of r.beforeEach)await g.runAction("beforeEach",()=>Promise.resolve(k.fn(g)));await Promise.race([Promise.resolve(e.skip?void 0:r.tests[e.ordinal]?.fn(g)).then(()=>"ok"),S])==="hard-timeout"&&(m.status="failed",A=h.abortReason??`test timeout exceeded (${a}ms)`);}catch(i){m.status="failed",A=i instanceof Error?i.message:String(i),w=await I.screenshot(`failure-${E}`).then(k=>k.path).catch(()=>{});}finally{D&&clearTimeout(D);}w&&h.addScreenshot(w),h.inTeardown=true;try{for(let i of r.afterEach)try{await g.runAction("afterEach",()=>Promise.resolve(i.fn(g)));}catch(k){n({type:"log",level:"warn",message:`[skeptic] afterEach failed: ${k instanceof Error?k.message:String(k)}`});}}finally{h.inTeardown=false;}let v={};if(h.abortReason===null&&!e.skip)try{let i=await I.collectEvidence();i.console&&(v.console=i.console),i.performance&&(v.mobilePerformance=i.performance),i.accessibility&&(v.mobileAccessibility=i.accessibility),i.network&&(v.mobileNetwork=i.network);}catch(i){n({type:"log",level:"warn",message:`[skeptic] device evidence failed: ${i instanceof Error?i.message:String(i)}`});}return Object.keys(v).length>0&&(m.metrics=v),h.screenshots.length>0&&(m.artifacts.screenshots=[...h.screenshots]),await I.close().catch(()=>{}),m.duration_ms=Math.round(performance.now()-c),A?(m.status="failed",m.steps.push({command:"test",args:{name:e.name},status:"failed",duration_ms:m.duration_ms,error:A,...w?{screenshot:w}:{}})):e.skip?(m.status="passed",m.skipped=true,m.steps.push({command:"test",args:{name:e.name},status:"skipped",duration_ms:0})):m.steps.push({command:"test",args:{name:e.name},status:"passed",duration_ms:m.duration_ms}),m},Se=async e=>{let r=null;try{r=await ie(e.file);}catch(a){n({type:"fatal",message:a instanceof Error?a.message:String(a),...a instanceof Error&&a.stack?{stack:a.stack}:{}}),process.exit(0);return}let t=new Set(e.allowlist),c=[];if(e.config.platform==="android"||e.config.platform==="ios-sim"){try{for(let a of r.tests){if(!t.has(a.id))continue;n({type:"test:start",testId:a.id,ordinal:a.ordinal,name:a.name,file:r.file,...e.config.shardId!==void 0?{shardId:e.config.shardId}:{}});let l;try{l=await be(a,r,e.config);}catch(b){l={name:a.name,file:r.file,status:"failed",duration_ms:0,steps:[{command:"test",args:{name:a.name},status:"error",duration_ms:0,error:b instanceof Error?b.message:String(b)}],artifacts:{},...e.config.shardId!==void 0?{shardId:e.config.shardId}:{}};}c.push(a.id),n({type:"test:complete",testId:a.id,ordinal:a.ordinal,result:l});}}finally{n({type:"file:complete",file:r.file,finished:c}),process.exit(0);}return}let E;try{E=await a$1();}catch(a){n({type:"fatal",message:`playwright load failed: ${a instanceof Error?a.message:String(a)}`}),process.exit(0);return}let y=E[e.config.browserEngine],d,f=null;try{if(e.config.noDaemon)d=await y.launch({headless:!e.config.headed});else {let{connectDaemon:a}=await import('./client-UR65IKYX.mjs'),l=await a({engine:e.config.browserEngine,headed:e.config.headed,cliVersion:"1.0.0",...typeof e.config.daemonIdleTimeoutSeconds=="number"?{idleTimeoutSeconds:e.config.daemonIdleTimeoutSeconds}:{}});d=l.browser,f=l.disconnect;}}catch(a){n({type:"fatal",message:`browser launch failed: ${a instanceof Error?a.message:String(a)}`}),process.exit(0);return}try{for(let a of r.tests){if(!t.has(a.id))continue;n({type:"test:start",testId:a.id,ordinal:a.ordinal,name:a.name,file:r.file,...e.config.shardId!==void 0?{shardId:e.config.shardId}:{}});let l;try{l=await ge(a,r,e.config,d);}catch(b){l={name:a.name,file:r.file,status:"failed",duration_ms:0,steps:[{command:"test",args:{name:a.name},status:"error",duration_ms:0,error:b instanceof Error?b.message:String(b)}],artifacts:{},...e.config.shardId!==void 0?{shardId:e.config.shardId}:{}};}c.push(a.id),n({type:"test:complete",testId:a.id,ordinal:a.ordinal,result:l});}}finally{f?await f().catch(()=>{}):await d.close().catch(()=>{}),n({type:"file:complete",file:r.file,finished:c}),process.exit(0);}},ve=async e=>{await Se(e);};!isMainThread&&parentPort&&(workerData?.mode==="discover"&&typeof workerData?.file=="string"?pe(workerData.file):(parentPort.on("message",e=>{e.type==="start"&&ve(e);}),n({type:"ready"})));export{pe as handleDiscover,ve as handleStart,ge as runOneTest};
|
|
3
|
+
var n=e=>{parentPort?.postMessage(e);},ie=async e=>{let r=a(e);try{await tsImport(pathToFileURL(e).href,import.meta.url);}finally{b();}return r},fe=e=>{let r=e.tests.map(t=>({id:t.id,file:t.file,ordinal:t.ordinal,name:t.name,skip:t.skip,only:t.only,use:{...e.fileUse,...t.use}}));return {file:e.file,fileUse:{...e.fileUse},hookCount:{beforeEach:e.beforeEach.length,afterEach:e.afterEach.length},tests:r}},pe=async e=>{try{let r=await ie(e),t=fe(r);parentPort?.postMessage({type:"manifest",manifest:t});}catch(r){parentPort?.postMessage({type:"error",error:{message:r instanceof Error?r.message:String(r),stack:r instanceof Error?r.stack??"":""}});}finally{process.exit(0);}},H=e=>e.replace(/[^a-zA-Z0-9_-]/g,"_"),oe=e=>{let r=H(R.basename(e).replace(/\.[^./\\]+$/,""))||"spec",t=createHash("sha1").update(e).digest("hex").slice(0,8);return `${r}-${t}`},re=async(e,r,t)=>{if(t.screenshotOnFailure!==false&&!(!e||e.isClosed()))try{let c=R.join(r,"failure.png");return await e.screenshot({path:c,fullPage:!0}),c}catch{return}},he=async e=>{if(!(!e||e.isClosed()))try{let r=await a$4(e,"body",{viewport:!0,includeCursorInteractive:!0,extractLinkHrefs:!0}),t=b$4(r,{interactive:!0});return t.refs.length===0?void 0:{url:e.url(),yaml:t.yaml,candidates:t.refs.slice(0,25).map(c=>({ref:c.ref,role:c.role,name:c.name,selectorHint:c.selectorHint}))}}catch{return}},ge=async(e,r,t,c$2)=>{let E=performance.now();for(let[s,o]of Object.entries(t.envOverrides))process.env[s]=o;let y=H(e.name||`test-${e.ordinal}`),d$2=R.join(t.outputDir,`${oe(r.file)}-${y}-${e.ordinal}`);await mkdir(d$2,{recursive:true});let f={...r.fileUse,...e.use},a=f.device??t.device,l=a?c(a):void 0,b=f.viewport??(l?{width:l.width,height:l.height}:void 0)??t.viewport??{width:1280,height:720},I=f.timeout??t.timeout,C=f.hardTimeout??t.hardTimeout,h=t.videoSize??f.videoSize??b,T=t.baseUrl??f.url,$=R.join(d$2,`${y}.har`),g=await c$2.newContext({viewport:b,...T?{baseURL:T}:{},...l?.dpr?{deviceScaleFactor:l.dpr}:{},...l?.userAgent?{userAgent:l.userAgent}:{},...t.video?{recordVideo:{dir:d$2,size:h}}:{},...t.har?{recordHar:{path:$,content:"embed"}}:{}}),m=f.cookies;if((t.cookies?.enabled===true||m===true||typeof m=="object")&&T)try{let{extractAndInjectCookies:s}=await import('./extractor-Y477MBN6.mjs'),o=new URL(T).hostname,z=typeof m=="object"?m.browser:t.cookies?.browser;await s(g,o,{...z?{browsers:[z]}:{}});}catch(s){n({type:"log",level:"warn",message:`[skeptic] cookie extraction failed: ${s instanceof Error?s.message:String(s)}`});}if(t.trace&&await g.tracing.start({screenshots:true,snapshots:true,sources:false}),t.video)try{await g.addInitScript({content:d});}catch(s){n({type:"log",level:"warn",message:`[skeptic] cursor overlay init script failed: ${s instanceof Error?s.message:String(s)}`});}g.setDefaultTimeout(I);let S=await g.newPage(),A=f.collectors??[],w=new Set;t.observability.forceAll&&(w.add("performance"),w.add("network"),w.add("console"),w.add("accessibility"));for(let s of A)w.add(s);let v={collectors:[...w],networkCaptureLimit:t.observability.networkCaptureLimit,duplicateWindowMs:t.observability.duplicateWindowMs,accessibilityDualEngine:t.observability.accessibilityDualEngine,accessibilityHtmlSnippetLimit:t.observability.accessibilityHtmlSnippetLimit,consoleCaptureLimit:t.observability.consoleCaptureLimit,consoleRedaction:t.observability.consoleRedaction,autoAccessibilityAudit:t.observability.autoAccessibilityAudit,accessibilityStandard:t.observability.accessibilityStandard,accessibilityMaxRulesPerImpact:t.observability.accessibilityMaxRulesPerImpact},i=b$2({required:w,configured:[],config:v}),k=t.visualSettle??t.observability.forceAll,B={fullPageScreenshots:t.artifact.fullPageScreenshots,visualSettle:k?b$3:a$2,blankFrameDetection:t.artifact.blankFrameDetection,writeSidecars:t.artifact.writeSidecars},p=new b$1(S,t.baseUrl??f.url??"",d$2,R.dirname(r.file),I,i,B);for(let s of i)try{await s.attach(S,p);}catch(o){n({type:"log",level:"warn",message:`[skeptic] collector ${s.name} attach failed: ${o instanceof Error?o.message:String(o)}`}),p.collectors.delete(s.name);}let O=[],_=d$1(S,p,{onAction:s=>{s.status==="completed"?O.push({command:s.label,args:{},status:"passed",duration_ms:s.durationMs??0}):s.status==="failed"&&O.push({command:s.label,args:{},status:"failed",duration_ms:s.durationMs??0,error:s.error}),n({type:"test:action",testId:e.id,label:s.label,status:s.status,...s.durationMs!==void 0?{durationMs:s.durationMs}:{},...s.error!==void 0?{error:s.error}:{}});},enableCursorProxy:t.video}),u={name:e.name,file:r.file,testIndex:e.ordinal,status:"passed",duration_ms:0,steps:O,artifacts:{},...t.shardId!==void 0?{shardId:t.shardId}:{}},j,ne=new Promise(s=>{j=setTimeout(()=>{p.abortReason=`test timeout exceeded (${C}ms)`,S.context().close().catch(()=>{}),s("hard-timeout");},C);}),F,P;try{for(let o of r.beforeEach)await _.runAction("beforeEach",()=>Promise.resolve(o.fn(_)));await Promise.race([Promise.resolve(e.skip?void 0:r.tests[e.ordinal]?.fn(_)).then(()=>"ok"),ne])==="hard-timeout"&&(u.status="failed",F=p.abortReason??`test timeout exceeded (${C}ms)`,P=await re(S,d$2,t));}catch(s){u.status="failed",F=s instanceof Error?s.message:String(s),P=await re(S,d$2,t);let o=await he(S);o&&(u.healing=o);}finally{j&&clearTimeout(j);}P&&p.addScreenshot(P),p.inTeardown=true;try{for(let s of r.afterEach)try{await _.runAction("afterEach",()=>Promise.resolve(s.fn(_)));}catch(o){n({type:"log",level:"warn",message:`[skeptic] afterEach failed: ${o instanceof Error?o.message:String(o)}`});}}finally{p.inTeardown=false;}let L=p.collectors.get("accessibility");if(L instanceof a$3&&v.autoAccessibilityAudit&&p.abortReason===null&&!S.isClosed()&&!(await L.snapshot()!==void 0))try{await L.audit({standard:v.accessibilityStandard});}catch(o){n({type:"log",level:"warn",message:`[skeptic] auto a11y audit failed: ${o instanceof Error?o.message:String(o)}`});}let x={};for(let s of p.collectors.values())try{let o=await s.snapshot();o!=null&&(x[s.name]=o);}catch(o){n({type:"log",level:"warn",message:`[skeptic] collector ${s.name} snapshot failed: ${o instanceof Error?o.message:String(o)}`});}for(let s of p.collectors.values())try{await s.detach();}catch{}if(t.trace)try{let s=R.join(d$2,`${y}.trace.zip`);await g.tracing.stop({path:s}),u.artifacts.trace=s;}catch{}if(Object.keys(x).length>0&&(u.metrics=x),p.screenshots.length>0&&(u.artifacts.screenshots=[...p.screenshots]),B.writeSidecars&&Object.keys(x).length>0&&await c$1({testDir:d$2,metrics:x,artifacts:u.artifacts,observabilityConfig:v}),t.video)try{let s=S.video();if(s){let o=R.join(d$2,`${y}.webm`);await S.close().catch(()=>{}),await s.saveAs(o),u.artifacts.video={path:o,width:h.width,height:h.height};}}catch(s){n({type:"log",level:"warn",message:`[skeptic] video save failed: ${s instanceof Error?s.message:String(s)}`});}if(await g.close().catch(()=>{}),t.har)try{existsSync($)&&(u.artifacts.har=$);}catch{}return u.duration_ms=Math.round(performance.now()-E),F?(u.status="failed",u.steps.push({command:"test",args:{name:e.name},status:"failed",duration_ms:u.duration_ms,error:F,...P?{screenshot:P}:{}})):e.skip?(u.status="passed",u.skipped=true,u.steps.push({command:"test",args:{name:e.name},status:"skipped",duration_ms:0})):u.steps.push({command:"test",args:{name:e.name},status:"passed",duration_ms:u.duration_ms}),u},we=async e=>{if(e.target)return e.target;let{listDevices:r}=await import('./adb-DUGGW3FV.mjs'),t=(await r().catch(()=>[])).filter(c=>c.state==="device");if(t.length===0)throw new Error("[android] no device/emulator found. Start one (or pass --target <serial>); `skeptic devices` lists them.");return t[0].serial},ye=async(e,r)=>{if(e.platform==="ios-sim"){let{IosSimDriver:y}=await import('./simctl-driver-PNUN7W7G.mjs');return (await y.create({...e.target?{udid:e.target}:{}})).newSession({artifactDir:r})}let{createAdb:t}=await import('./adb-DUGGW3FV.mjs'),{AndroidAdbDriverSession:c}=await import('./adb-session-AVVXL3QQ.mjs'),E=await we(e);return new c(t({serial:E}),E,r)},be=async(e,r,t)=>{let c=performance.now();for(let[i,k]of Object.entries(t.envOverrides))process.env[i]=k;let E=H(e.name||`test-${e.ordinal}`),y=R.join(t.outputDir,`${oe(r.file)}-${E}-${e.ordinal}`);await mkdir(y,{recursive:true});let d={...r.fileUse,...e.use},f=d.timeout??t.timeout,a=d.hardTimeout??t.hardTimeout,{buildDeviceFixture:l,unavailable:b}=await import('./device-fixture-MJSDIP75.mjs'),I=await ye(t,y),C={fullPageScreenshots:false,visualSettle:a$2,blankFrameDetection:"off",writeSidecars:false},h=new b$1(b("page","web"),t.baseUrl??d.url??"",y,R.dirname(r.file),f,[],C),T=[],g=l(I,h,{onAction:i=>{i.status==="completed"?T.push({command:i.label,args:{},status:"passed",duration_ms:i.durationMs??0}):i.status==="failed"&&T.push({command:i.label,args:{},status:"failed",duration_ms:i.durationMs??0,error:i.error}),n({type:"test:action",testId:e.id,label:i.label,status:i.status,...i.durationMs!==void 0?{durationMs:i.durationMs}:{},...i.error!==void 0?{error:i.error}:{}});}}),m={name:e.name,file:r.file,testIndex:e.ordinal,status:"passed",duration_ms:0,steps:T,artifacts:{},...t.shardId!==void 0?{shardId:t.shardId}:{}},D,S=new Promise(i=>{D=setTimeout(()=>{h.abortReason=`test timeout exceeded (${a}ms)`,i("hard-timeout");},a);}),A,w;try{for(let k of r.beforeEach)await g.runAction("beforeEach",()=>Promise.resolve(k.fn(g)));await Promise.race([Promise.resolve(e.skip?void 0:r.tests[e.ordinal]?.fn(g)).then(()=>"ok"),S])==="hard-timeout"&&(m.status="failed",A=h.abortReason??`test timeout exceeded (${a}ms)`);}catch(i){m.status="failed",A=i instanceof Error?i.message:String(i),w=await I.screenshot(`failure-${E}`).then(k=>k.path).catch(()=>{});}finally{D&&clearTimeout(D);}w&&h.addScreenshot(w),h.inTeardown=true;try{for(let i of r.afterEach)try{await g.runAction("afterEach",()=>Promise.resolve(i.fn(g)));}catch(k){n({type:"log",level:"warn",message:`[skeptic] afterEach failed: ${k instanceof Error?k.message:String(k)}`});}}finally{h.inTeardown=false;}let v={};if(h.abortReason===null&&!e.skip)try{let i=await I.collectEvidence();i.console&&(v.console=i.console),i.performance&&(v.mobilePerformance=i.performance),i.accessibility&&(v.mobileAccessibility=i.accessibility),i.network&&(v.mobileNetwork=i.network);}catch(i){n({type:"log",level:"warn",message:`[skeptic] device evidence failed: ${i instanceof Error?i.message:String(i)}`});}return Object.keys(v).length>0&&(m.metrics=v),h.screenshots.length>0&&(m.artifacts.screenshots=[...h.screenshots]),await I.close().catch(()=>{}),m.duration_ms=Math.round(performance.now()-c),A?(m.status="failed",m.steps.push({command:"test",args:{name:e.name},status:"failed",duration_ms:m.duration_ms,error:A,...w?{screenshot:w}:{}})):e.skip?(m.status="passed",m.skipped=true,m.steps.push({command:"test",args:{name:e.name},status:"skipped",duration_ms:0})):m.steps.push({command:"test",args:{name:e.name},status:"passed",duration_ms:m.duration_ms}),m},Se=async e=>{let r=null;try{r=await ie(e.file);}catch(a){n({type:"fatal",message:a instanceof Error?a.message:String(a),...a instanceof Error&&a.stack?{stack:a.stack}:{}}),process.exit(0);return}let t=new Set(e.allowlist),c=[];if(e.config.platform==="android"||e.config.platform==="ios-sim"){try{for(let a of r.tests){if(!t.has(a.id))continue;n({type:"test:start",testId:a.id,ordinal:a.ordinal,name:a.name,file:r.file,...e.config.shardId!==void 0?{shardId:e.config.shardId}:{}});let l;try{l=await be(a,r,e.config);}catch(b){l={name:a.name,file:r.file,status:"failed",duration_ms:0,steps:[{command:"test",args:{name:a.name},status:"error",duration_ms:0,error:b instanceof Error?b.message:String(b)}],artifacts:{},...e.config.shardId!==void 0?{shardId:e.config.shardId}:{}};}c.push(a.id),n({type:"test:complete",testId:a.id,ordinal:a.ordinal,result:l});}}finally{n({type:"file:complete",file:r.file,finished:c}),process.exit(0);}return}let E;try{E=await a$1();}catch(a){n({type:"fatal",message:`playwright load failed: ${a instanceof Error?a.message:String(a)}`}),process.exit(0);return}let y=E[e.config.browserEngine],d,f=null;try{if(e.config.noDaemon)d=await y.launch({headless:!e.config.headed});else {let{connectDaemon:a}=await import('./client-UR65IKYX.mjs'),l=await a({engine:e.config.browserEngine,headed:e.config.headed,cliVersion:"1.0.1",...typeof e.config.daemonIdleTimeoutSeconds=="number"?{idleTimeoutSeconds:e.config.daemonIdleTimeoutSeconds}:{}});d=l.browser,f=l.disconnect;}}catch(a){n({type:"fatal",message:`browser launch failed: ${a instanceof Error?a.message:String(a)}`}),process.exit(0);return}try{for(let a of r.tests){if(!t.has(a.id))continue;n({type:"test:start",testId:a.id,ordinal:a.ordinal,name:a.name,file:r.file,...e.config.shardId!==void 0?{shardId:e.config.shardId}:{}});let l;try{l=await ge(a,r,e.config,d);}catch(b){l={name:a.name,file:r.file,status:"failed",duration_ms:0,steps:[{command:"test",args:{name:a.name},status:"error",duration_ms:0,error:b instanceof Error?b.message:String(b)}],artifacts:{},...e.config.shardId!==void 0?{shardId:e.config.shardId}:{}};}c.push(a.id),n({type:"test:complete",testId:a.id,ordinal:a.ordinal,result:l});}}finally{f?await f().catch(()=>{}):await d.close().catch(()=>{}),n({type:"file:complete",file:r.file,finished:c}),process.exit(0);}},ve=async e=>{await Se(e);};!isMainThread&&parentPort&&(workerData?.mode==="discover"&&typeof workerData?.file=="string"?pe(workerData.file):(parentPort.on("message",e=>{e.type==="start"&&ve(e);}),n({type:"ready"})));export{pe as handleDiscover,ve as handleStart,ge as runOneTest};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skeptic-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Agent-native CLI for browser QA — deterministic Playwright TypeScript test runner with observability, evidence capture, and snapshot-based page discovery. No API keys, no LLM of its own.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|