shiplightai 0.1.74 → 0.1.75
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/cjs/debugger-manager.cjs +5 -5
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/reporter.cjs +2 -2
- package/dist/cli.js +48 -48
- package/dist/debugger-manager.d.ts +5 -0
- package/dist/debugger-manager.js +8 -8
- package/dist/index.js +1 -1
- package/dist/reporter.js +2 -2
- package/dist/static-embedded/assets/{index-CoKedfWS.js → index-Dk5ihq1Y.js} +2 -2
- package/dist/static-embedded/assets/{index-BEW7CdFm.js → index-Mg0a6DkO.js} +50 -4
- package/dist/static-embedded/index.html +1 -1
- package/package.json +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var F=Object.create;var $=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var J=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty;var W=(r,s)=>{for(var e in s)$(r,e,{get:s[e],enumerable:!0})},_=(r,s,e,t)=>{if(s&&typeof s=="object"||typeof s=="function")for(let o of G(s))!Y.call(r,o)&&o!==e&&$(r,o,{get:()=>s[o],enumerable:!(t=k(s,o))||t.enumerable});return r};var S=(r,s,e)=>(e=r!=null?F(J(r)):{},_(s||!r||!r.__esModule?$(e,"default",{value:r,enumerable:!0}):e,r)),V=r=>_($({},"__esModule",{value:!0}),r);var X={};W(X,{DebuggerManager:()=>I});module.exports=V(X);var O=S(require("http"),1),L=S(require("net"),1),m=S(require("path"),1),U=S(require("fs"),1),M=require("crypto");var y=S(require("fs"),1),h=S(require("path"),1),N=require("child_process"),C=require("yaml");function K(r){let s=!1;return()=>{if(!s){s=!0;try{y.unlinkSync(r)}catch{}}}}function E(r){let s=["playwright.config.ts","playwright.config.js","playwright.config.mjs"],e=h.resolve(r);for(;;){for(let o of s){let n=h.join(e,o);if(y.existsSync(n))return n}let t=h.dirname(e);if(t===e)break;e=t}return null}function z(r,s,e,t){let o={...e},n=o.launchOptions?.args??[];return o.launchOptions={...o.launchOptions??{},args:[...n,"--remote-debugging-port=0"]},`// @generated by shiplightai \u2014 temporary debug test
|
|
2
2
|
import { test } from 'shiplightai/fixture';
|
|
3
3
|
${`
|
|
4
4
|
test.use(${JSON.stringify(o)});
|
|
@@ -22,13 +22,13 @@ test('__shiplight_debug__', async ({ page, agent }) => {
|
|
|
22
22
|
// Keep alive until the server is closed externally (Ctrl+C kills the process)
|
|
23
23
|
await new Promise(() => {});
|
|
24
24
|
});
|
|
25
|
-
`}async function Q(r){let{createServer:s}=await import("net");for(let e=r;e<r+20;e++)if(await new Promise(o=>{let n=s();n.once("error",()=>o(!1)),n.once("listening",()=>{n.close(()=>o(!0))}),n.listen(e,"127.0.0.1")}))return e;throw new Error(`No available port found in range ${r}-${r+19}`)}async function j(r){let{yamlFilePath:s,configPath:e,tempSuffix:t="",headed:o}=r,n=
|
|
25
|
+
`}async function Q(r){let{createServer:s}=await import("net");for(let e=r;e<r+20;e++)if(await new Promise(o=>{let n=s();n.once("error",()=>o(!1)),n.once("listening",()=>{n.close(()=>o(!0))}),n.listen(e,"127.0.0.1")}))return e;throw new Error(`No available port found in range ${r}-${r+19}`)}async function j(r){let{yamlFilePath:s,configPath:e,tempSuffix:t="",headed:o}=r,n=h.dirname(e),a=await Q(16174),i;if(!y.existsSync(s))throw new Error(`Please select a test file before starting the debug session. File not found: ${s}`);try{let u=(0,C.parse)(y.readFileSync(s,"utf-8"));u?.use&&typeof u.use=="object"&&!Array.isArray(u.use)&&(i=u.use),u?.base_url&&!i?.baseURL&&(i={...i,baseURL:u.base_url})}catch(u){console.error("[debugger] Could not parse YAML for `use` block:",u)}let d=h.dirname(h.resolve(s)),l=t?`-${t}`:"",c=h.join(d,`.__shiplight_debug__${l}.yaml.spec.ts`),p=z(s,a,i,n);y.writeFileSync(c,p);let w=K(c),T=["playwright","test",c,...o?["--headed"]:[]],g=(0,N.spawn)("npx",T,{stdio:["ignore","pipe","pipe"],shell:!0,cwd:n,env:{...process.env,PWDEBUG:"console",SHIPLIGHT_REGISTRY_URL:""}});g.stdout?.on("data",u=>{process.stderr.write(u)}),g.stderr?.on("data",u=>{process.stderr.write(u)});let f=()=>{g.killed||g.kill("SIGTERM")};process.on("SIGTERM",f),process.on("SIGINT",f),process.on("exit",f),g.on("close",u=>{process.removeListener("SIGTERM",f),process.removeListener("SIGINT",f),process.removeListener("exit",f),w(),u!==0&&u!==null&&console.error(`[debugger] Playwright process exited with code ${u}`)}),console.error("[debugger] Waiting for Playwright sandbox to start...");let x=["127.0.0.1","::1"];async function v(u){try{let b=u.includes(":")?`[${u}]`:u,H=await fetch(`http://${b}:${a}/api/test-flow`);if(H.ok){try{await H.text()}catch{}return!0}}catch{}return!1}let P=null;for(let u=0;u<180;u++){if(g.exitCode!==null)throw w(),new Error(`Playwright process exited with code ${g.exitCode} before sandbox was ready`);for(let b of x)if(await v(b)){P=b;break}if(P){console.error(`[debugger] Playwright sandbox ready on ${P}:${a}`);break}if(u===179)throw f(),w(),new Error("Timed out waiting for Playwright sandbox to start (180s)");await new Promise(b=>setTimeout(b,1e3))}if(!P)throw f(),w(),new Error("Sandbox poll finished without a reachable host");return{port:a,host:P,pid:g.pid??0,cleanup:async()=>{f(),w()}}}var D=1e4,I=class{sessions=new Map;byYamlPath=new Map;options;spawner;headed;constructor(s={}){this.options=s,this.spawner=s.spawner??j,this.headed=s.headed??!1}log(s){this.options.onLog?this.options.onLog(s):console.error(s)}resetToIdle(s,e){s.session.innerPort=0,s.session.innerHost="127.0.0.1",s.session.pid=0,s.session.status="idle",s.session.exitInfo=e,s.cleanup=async()=>{},s.readyPromise=Promise.resolve(),this.notifyStateChange(s.session)}notifyStateChange(s){try{this.options.onSessionStateChange?.({...s})}catch(e){this.log(`[manager] onSessionStateChange listener threw: ${e.message}`)}}openSession(s){let e=m.resolve(s),t=this.byYamlPath.get(e);if(t){let l=this.sessions.get(t);if(l&&l.session.status!=="ended")return{...l.session};this.byYamlPath.delete(e)}if(!U.existsSync(e))throw new Error(`YAML file not found: ${e}`);if(!E(m.dirname(e)))throw new Error(`No Playwright config found for ${e} (searched parents for playwright.config.{ts,js,mjs}).`);let n=`dbg-${(0,M.randomUUID)().slice(0,8)}`,a=new Date().toISOString(),i={sessionId:n,yamlPath:e,innerPort:0,innerHost:"127.0.0.1",pid:0,startedAt:a,status:"idle",exitInfo:null},d={session:i,cleanup:async()=>{},readyPromise:Promise.resolve()};return this.sessions.set(n,d),this.byYamlPath.set(e,n),this.notifyStateChange(i),this.log(`[manager] session ${n} created (idle) for ${m.basename(e)}`),{...i}}async startSandbox(s){let e=this.sessions.get(s);if(!e)throw new Error(`No session ${s} to start sandbox for`);if(e.session.status==="running"||e.session.status==="starting"){e.readyPromise&&await e.readyPromise;return}if(e.session.status==="ended")throw new Error(`Session ${s} has ended`);let t=e.session.yamlPath,o=E(m.dirname(t));if(!o)throw new Error(`No Playwright config found for ${t} (searched parents for playwright.config.{ts,js,mjs}).`);e.session.status="starting",this.notifyStateChange(e.session);let n=(async()=>{let a=D+18e4,i,d=new Promise((c,p)=>{i=setTimeout(()=>p(new Error(`Timed out after ${a/1e3}s waiting for inner playwright to register on a port.`)),a)}),l;try{l=await Promise.race([this.spawner({yamlFilePath:t,configPath:o,tempSuffix:s,headed:this.headed}),d])}finally{i&&clearTimeout(i)}e.session.innerPort=l.port,e.session.innerHost=l.host,e.session.pid=l.pid,e.session.status="running",e.cleanup=l.cleanup,e.livenessTimer=this.startLivenessProbe(s,c=>{(e.session.status==="running"||e.session.status==="starting")&&this.resetToIdle(e,c)}),this.notifyStateChange(e.session),this.log(`[manager] session ${s} running on ${e.session.innerHost}:${e.session.innerPort} (yaml=${m.basename(t)})`)})();e.readyPromise=n;try{await n}catch(a){throw this.resetToIdle(e,a.message),a}}async stopSandbox(s){let e=this.sessions.get(s);if(e&&e.session.status!=="idle"&&e.session.status!=="ended"){this.log(`[manager] stopSandbox ${s}`),e.livenessTimer&&(clearInterval(e.livenessTimer),e.livenessTimer=void 0);try{await e.cleanup()}catch(t){this.log(`[manager] stopSandbox ${s} cleanup error: ${t.message}`)}this.resetToIdle(e,null)}}startLivenessProbe(s,e){let n=0,a=setInterval(()=>{let i=this.sessions.get(s);if(!i||i.session.status==="ended"||i.session.status==="idle"){clearInterval(a);return}let d=!1;try{process.kill(i.session.pid,0),d=!0}catch(l){l?.code!=="ESRCH"&&(d=!0)}d?n=0:(n+=1,n>=3&&(clearInterval(a),e("process-exited")))},3e3);return a.unref(),a}async closeSession(s){let e=this.sessions.get(s);if(e){this.log(`[manager] closeSession ${s} (status=${e.session.status})`),this.sessions.delete(s),this.byYamlPath.get(e.session.yamlPath)===s&&this.byYamlPath.delete(e.session.yamlPath),e.livenessTimer&&(clearInterval(e.livenessTimer),e.livenessTimer=void 0),e.session.status!=="ended"&&(e.session.status="ended",e.session.exitInfo="SIGTERM",this.notifyStateChange(e.session));try{await e.cleanup()}catch(t){this.log(`[manager] closeSession ${s} cleanup error: ${t.message}`)}}}async restartInner(s){let e=this.sessions.get(s);if(!e)throw new Error(`No session ${s} to restart`);if(e.restartInProgress)throw new Error(`Restart already in progress for session ${s}`);let t=e.session.yamlPath,o=E(m.dirname(t));if(!o)throw new Error(`No Playwright config found for ${t} (searched parents for playwright.config.{ts,js,mjs}).`);e.restartInProgress=!0;try{e.livenessTimer&&(clearInterval(e.livenessTimer),e.livenessTimer=void 0);try{await e.cleanup()}catch(l){this.log(`[manager] restartInner ${s} old cleanup error: ${l.message}`)}e.session.status="starting",e.session.innerPort=0,e.session.pid=0,this.notifyStateChange(e.session);let n=D+18e4,a,i=new Promise((l,c)=>{a=setTimeout(()=>c(new Error(`Timed out after ${n/1e3}s waiting for inner playwright to respawn.`)),n)}),d;try{d=await Promise.race([this.spawner({yamlFilePath:t,configPath:o,tempSuffix:s,headed:this.headed}),i])}catch(l){throw this.resetToIdle(e,l.message),l}finally{a&&clearTimeout(a)}e.session.innerPort=d.port,e.session.innerHost=d.host,e.session.pid=d.pid,e.session.status="running",e.cleanup=d.cleanup,e.livenessTimer=this.startLivenessProbe(s,l=>{(e.session.status==="running"||e.session.status==="starting")&&this.resetToIdle(e,l)}),this.notifyStateChange(e.session),this.log(`[manager] session ${s} restarted on ${e.session.innerHost}:${e.session.innerPort} (yaml=${m.basename(t)})`)}finally{e.restartInProgress=!1}}listSessions(){return Array.from(this.sessions.values()).map(s=>({...s.session}))}getSession(s){let e=this.sessions.get(s);return e?{...e.session}:void 0}httpProxyFor(s,e={}){let{liveviewUrlBuilder:t}=e;return async(o,n,a)=>{let i=this.sessions.get(s);if(!i){n.status(404).json({status:"error",message:"Session not found"});return}if(i.session.status==="ended"){n.status(410).json({status:"error",message:"Session has ended",exitInfo:i.session.exitInfo});return}if(i.session.status==="idle"){n.status(503).json({status:"error",message:"Sandbox not started"});return}let d=`${o.method} ${o.path}`;if(d==="POST /api/int-runner/create-session"){let c=await A(o),p={};if(c.length)try{p=JSON.parse(c.toString("utf-8"))}catch{n.status(400).json({status:"error",message:"Invalid JSON body"});return}p.testFilePath=i.session.yamlPath,await B(o,n,i.session.innerHost,i.session.innerPort,Buffer.from(JSON.stringify(p),"utf-8"),"application/json");return}if(d==="POST /api/int-runner/terminate-session"){try{await this.stopSandbox(s),n.json({status:"success",details:"Sandbox stopped"})}catch(c){n.status(500).json({status:"error",message:c.message})}return}if(d==="POST /api/int-runner/liveview-url"){let c=t?.(o)??"";n.json({liveviewUrl:c,browserWsUrl:""});return}let l=await A(o);await B(o,n,i.session.innerHost,i.session.innerPort,l,o.headers["content-type"])}}wsUpgradeFor(s){return async(e,t,o,n)=>{let a=this.sessions.get(s);if(!a){R(t,`HTTP/1.1 404 Not Found\r
|
|
26
26
|
\r
|
|
27
27
|
`);return}if(a.session.status==="ended"){R(t,`HTTP/1.1 410 Gone\r
|
|
28
28
|
\r
|
|
29
|
-
`);return}try{let i=a.session.innerHost.includes(":")?`[${a.session.innerHost}]`:a.session.innerHost,d=await fetch(`http://${i}:${a.session.innerPort}/api/browser-cdp`);if(!d.ok)throw new Error(`Inner /api/browser-cdp returned ${d.status}`);let{cdpUrl:l}=await d.json(),c=new URL(l.replace(/^ws/,"http")),p=parseInt(c.port||"80",10),
|
|
30
|
-
Host: ${
|
|
31
|
-
`;for(let[
|
|
29
|
+
`);return}try{let i=a.session.innerHost.includes(":")?`[${a.session.innerHost}]`:a.session.innerHost,d=await fetch(`http://${i}:${a.session.innerPort}/api/browser-cdp`);if(!d.ok)throw new Error(`Inner /api/browser-cdp returned ${d.status}`);let{cdpUrl:l}=await d.json(),c=new URL(l.replace(/^ws/,"http")),p=parseInt(c.port||"80",10),w=c.hostname,T=c.pathname;n&&n.startsWith("/page/")&&(T=`/devtools${n}`);let g=L.createConnection(p,w);g.on("connect",()=>{let f=`GET ${T} HTTP/1.1\r
|
|
30
|
+
Host: ${w}:${p}\r
|
|
31
|
+
`;for(let[x,v]of Object.entries(e.headers)){let P=x.toLowerCase();P!=="host"&&P!=="origin"&&(f+=`${x}: ${Array.isArray(v)?v.join(", "):v}\r
|
|
32
32
|
`)}f+=`\r
|
|
33
33
|
`,g.write(f),o.length&&g.write(o),g.pipe(t),t.pipe(g)}),g.on("error",()=>{(!("destroyed"in t)||!t.destroyed)&&t.destroy()}),t.on("error",()=>{g.destroyed||g.destroy()}),t.on("close",()=>{g.destroyed||g.destroy()})}catch(i){this.log(`[manager] WS upgrade for ${s} failed: ${i.message}`),R(t,`HTTP/1.1 502 Bad Gateway\r
|
|
34
34
|
\r
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -4365,7 +4365,7 @@ ${m.join(`
|
|
|
4365
4365
|
`)}function Bc(e,t){let i=[],a=t?.version||"unknown";i.push(`// @generated by shiplightai v${a}`),i.push(...jo()),i.push(""),t?.use&&Object.keys(t.use).length>0&&(i.push(`test.use(${JSON.stringify(t.use,null,2)});`),i.push(""));let n=new Set,o={imports:n,actionEntityStore:t?.actionEntityStore},r=t?.testName||"Test Suite",s=ea(t?.tags);i.push(`test.describe.serial('${s}${pe(r)}', () => {`),e.beforeAll&&e.beforeAll.length>0&&(i.push(...Mi("beforeAll",e.beforeAll,o,1)),i.push("")),e.beforeEach&&e.beforeEach.length>0&&(i.push(...Mi("beforeEach",e.beforeEach,o,1)),i.push(""));for(let c=0;c<e.tests.length;c++){let d=e.tests[c],h=d.timeout||d.skip!==void 0||d.fail!==void 0||d.only||d.slow?{timeout:d.timeout,skip:d.skip,fail:d.fail,only:d.only,slow:d.slow}:void 0;if(d.parameters&&d.parameters.length>0)for(let m of d.parameters)i.push(...Ci(d.testFlow,`${pe(d.name)} [${pe(m.name)}]`,o,1,h,m.name,m.values)),i.push("");else i.push(...Ci(d.testFlow,pe(d.name),o,1,h)),(c<e.tests.length-1||e.afterEach||e.afterAll)&&i.push("")}return e.afterEach&&e.afterEach.length>0&&(i.push(...Mi("afterEach",e.afterEach,o,1)),i.push("")),e.afterAll&&e.afterAll.length>0&&i.push(...Mi("afterAll",e.afterAll,o,1)),i.push("});"),Ko(i,n),i.join(`
|
|
4366
4366
|
`)}function ea(e){return e&&e.length>0?e.map(t=>`@${t}`).join(" ")+" ":""}var Gc=["testContext","request"];function Pi(e){let t=new Set;function i(a){for(let n of a)switch(n.type){case he.ACTION:{let r=n.action_entity?.action_data?.kwargs;if(r?.args&&Array.isArray(r.args))for(let s of r.args)typeof s=="string"&&Gc.includes(s)&&t.add(s);break}case he.STEP:i(n.statements);break;case he.IF_ELSE:{let o=n;i(o.then),o.else&&i(o.else);break}case he.WHILE_LOOP:i(n.body);break}}return i(e),t}function jc(e){let t=Pi(e.statements??[]);if(e.teardown)for(let i of Pi(e.teardown))t.add(i);return t}function na(e){return`{ ${["page","agent",...Array.from(e).sort()].join(", ")} }`}function Ci(e,t,i,a=0,n,o,r){let s=" ".repeat(a),l=[],c=jc(e),d=na(c),h=n?.only?"test.only":"test",m=o?`, { tag: '@${pe(o)}' }`:"";if(l.push(`${s}${h}('${t}'${m}, async (${d}) => {`),n?.skip===!0?l.push(`${s} test.skip();`):typeof n?.skip=="string"&&l.push(`${s} test.skip(true, '${pe(n.skip)}');`),n?.fail===!0?l.push(`${s} test.fail();`):typeof n?.fail=="string"&&l.push(`${s} test.fail(true, '${pe(n.fail)}');`),n?.slow&&l.push(`${s} test.slow();`),n?.timeout&&l.push(`${s} test.setTimeout(${n.timeout});`),r){for(let[y,b]of Object.entries(r))l.push(`${s} agent.agentServices.saveVariable(${JSON.stringify(y)}, ${JSON.stringify(b)});`);l.push("")}let g=e.teardown&&e.teardown.length>0,f=a+1;if(g){if(l.push(`${s} try {`),e.statements&&e.statements.length>0){l.push(`${s} // Test steps`);let b=me(e.statements,f+1,i);l.push(...b)}l.push(`${s} } finally {`),l.push(`${s} // Teardown`);let y=me(e.teardown,f+1,i,"teardown");l.push(...y),l.push(`${s} }`)}else if(e.statements&&e.statements.length>0){l.push(`${s} // Test steps`);let y=me(e.statements,f,i);l.push(...y)}return l.push(`${s}});`),l}function Wo(e,t,i){let a=[],n=Go(t),o=Pi(n),r=na(o);return a.push(`test.${e}(async (${r}) => {`),a.push(...me(n,1,i,e)),a.push("});"),a}function Mi(e,t,i,a){let n=" ".repeat(a),o=[],r=Go(t);if(e==="beforeAll"||e==="afterAll"){let l={...i,noAgent:!0};o.push(`${n}test.${e}(async ({ browser }, workerInfo) => {`),o.push(`${n} const page = await browser.newPage({ baseURL: workerInfo.project.use.baseURL });`),o.push(...me(r,a+1,l,e)),o.push(`${n} await page.close();`),o.push(`${n}});`)}else{let l=Pi(r),c=na(l);o.push(`${n}test.${e}(async (${c}) => {`),o.push(...me(r,a+1,i,e)),o.push(`${n}});`)}return o}function Go(e){let i=(0,Bo.stringify)({goal:"_hook",statements:e});return ke(i).statements??[]}function jo(){return["import { test, expect } from 'shiplightai/fixture';"]}function Ko(e,t){if(t.size>0){let i=0;for(let n=0;n<e.length;n++)e[n].startsWith("import ")&&(i=n+1);let a=Array.from(t);e.splice(i,0,...a)}}var Uo=5;function Vo(e,t,i){let a={expandingPaths:new Set([(0,Je.resolve)(t)]),depth:0,referencedPaths:new Set,basePath:i},n={...e};Array.isArray(n.statements)&&(n.statements=De(n.statements,t,a)),Array.isArray(n.teardown)&&(n.teardown=De(n.teardown,t,a));for(let o of["beforeAll","afterAll","beforeEach","afterEach"])Array.isArray(n[o])&&(n[o]=De(n[o],t,a));return{doc:n,referencedTemplatePaths:Array.from(a.referencedPaths)}}function De(e,t,i){let a=[];for(let n of e)if(Kc(n)){let o=zc(n,t,i);a.push(o)}else a.push(Vc(n,t,i));return a}function Kc(e){return typeof e=="object"&&e!==null&&typeof e.template=="string"}function zc(e,t,i){if(i.depth>=Uo)throw new Error(`Template expansion exceeded maximum depth of ${Uo}. Check for deeply nested or circular template references.`);let a=(0,Je.resolve)((0,Je.dirname)(t),e.template),n=!(0,Oi.existsSync)(a)&&i.basePath?(0,Je.resolve)(i.basePath,e.template):a;if(i.expandingPaths.has(n))throw new Error(`Circular template reference detected: ${n} is already being expanded. Stack: ${Array.from(i.expandingPaths).join(" \u2192 ")} \u2192 ${n}`);i.referencedPaths.add(n);let o;try{o=(0,Oi.readFileSync)(n,"utf-8")}catch(f){throw new Error(`Failed to read template file: ${n} (referenced from ${t}): ${f.message}`)}let r=(0,yt.parse)(o);if(!r||typeof r!="object")throw new Error(`Invalid template file: ${n} \u2014 expected a YAML object`);let s=r.params||[],l=e.params||{};for(let f of s)if(!(f in l))throw new Error(`Template ${e.template} requires param "${f}" but it was not provided. Required params: [${s.join(", ")}]`);let c=r.statements;if(!Array.isArray(c))throw new Error(`Template ${e.template} must have a "statements" array`);if(Object.keys(l).length>0){let y=(0,yt.stringify)(c);for(let[b,p]of Object.entries(l))y=y.split(`<<${b}>>`).join(String(p));c=(0,yt.parse)(y)}let d={expandingPaths:new Set([...i.expandingPaths,n]),depth:i.depth+1,referencedPaths:i.referencedPaths},h=De(c,n,d),g={STEP:r.name||e.template.replace(/\.yaml$/,"").split("/").pop()||e.template,template_path:e.template,statements:h};return Object.keys(l).length>0&&(g.template_params=l),g}function Vc(e,t,i){if(typeof e!="object"||e===null)return e;let a={...e};return Array.isArray(a.statements)&&(a.statements=De(a.statements,t,i)),Array.isArray(a.THEN)&&(a.THEN=De(a.THEN,t,i)),Array.isArray(a.ELSE)&&(a.ELSE=De(a.ELSE,t,i)),Array.isArray(a.DO)&&(a.DO=De(a.DO,t,i)),a}var aa=class extends Error{constructor(e){super(e),this.name="YamlValidationError"}};function oa(e,t,i){let a=(0,xt.parse)(e),n=a?.name,o=a?.tags,r=a?.use;if(a&&(a.name!==void 0||a.tags!==void 0||a.use!==void 0)&&(delete a.name,delete a.tags,delete a.use),a?.suite){if(a.goal||a.statements)throw new aa('YAML file cannot have both "suite" and top-level "goal"/"statements". Use either suite format or single-test format.');return Yc(a,n,o,r,t,i)}return Xc(a,n,o,r,t,i)}function Xc(e,t,i,a,n,o){let r=e?.beforeEach,s=e?.afterEach,l=Xo(e?.parameters),c=e?.timeout,d=e?.skip,h=e?.fail,m=e?.only,g=e?.slow;if(e&&(delete e.beforeEach,delete e.afterEach,delete e.parameters,delete e.timeout,delete e.skip,delete e.fail,delete e.only,delete e.slow),e?.url)throw new aa(`The "url" field is not supported in local YAML tests. Use "base_url: ${e.url}" and add "- URL: /" as the first statement instead.`);e&&!e.goal&&t&&(e.goal=t);let f=[];if(n&&e&&typeof e=="object"){let p=Vo(e,n,o);e=p.doc,f=p.referencedTemplatePaths}let y=(0,xt.stringify)(e),b=ke(y);return n&&(Ye(b.statements??[],n,"main"),b.teardown&&Ye(b.teardown,n,"teardown")),{testFlow:b,name:t,tags:i,use:a,beforeEach:r,afterEach:s,parameters:l,timeout:c,skip:d,fail:h,only:m,slow:g,referencedTemplatePaths:f}}function Yc(e,t,i,a,n,o){let r=e.suite;if(!Array.isArray(r.tests)||r.tests.length===0)throw new Error('Suite must have a non-empty "tests" array.');let s=r.beforeAll,l=r.afterAll,c=r.beforeEach,d=r.afterEach,h=[],m=r.tests.map(y=>{if(!y.name)throw new Error('Each test in a suite must have a "name" field.');if(!Array.isArray(y.statements)||y.statements.length===0)throw new Error(`Suite test "${y.name}" must have a non-empty "statements" array.`);let b={goal:y.name,statements:y.statements};y.teardown&&(b.teardown=y.teardown);let p=[],x=b;if(n&&typeof b=="object"){let M=Vo(b,n,o);x=M.doc,p=M.referencedTemplatePaths,h.push(...p)}let S=(0,xt.stringify)(x),E=ke(S),A=Xo(y.parameters);return{testFlow:E,name:y.name,tags:Array.isArray(y.tags)?y.tags:void 0,parameters:A,timeout:y.timeout,skip:y.skip,fail:y.fail,only:y.only,slow:y.slow}}),g=r.base_url,f=g?{...a,baseURL:g}:a;return{suite:{beforeAll:s,afterAll:l,beforeEach:c,afterEach:d,tests:m},name:t,tags:i,use:f,referencedTemplatePaths:h}}function Xo(e){if(!(!Array.isArray(e)||e.length===0))return e.map((t,i)=>{if(!t.name)throw new Error(`Parameter set at index ${i} must have a "name" field.`);if(!t.values||typeof t.values!="object")throw new Error(`Parameter set "${t.name}" must have a "values" object.`);return{name:t.name,values:t.values}})}function Ye(e,t,i){for(let a=0;a<e.length;a++){let n=e[a],o=`${i}.${a}`,r=n.description||"";if(n.uid=Jc(t,o,r),n.type===he.STEP)Ye(n.statements,t,o);else if(n.type===he.IF_ELSE){let s=n;Ye(s.then,t,`${o}.then`),s.else&&Ye(s.else,t,`${o}.else`)}else n.type===he.WHILE_LOOP&&Ye(n.body,t,`${o}.body`)}}function Jc(e,t,i){let a=(0,zo.createHash)("sha256").update(`${e}:${t}:${i}`).digest("hex");return`${a.slice(0,8)}-${a.slice(8,12)}-${a.slice(12,16)}-${a.slice(16,20)}-${a.slice(20,32)}`}function Jo(e,t,i){let a=/\btemplate:\s/.test(e),n=/^suite:/m.test(e),o=a||n?null:qn(e);if(o&&!o.valid)return{valid:!1,errors:o.errors,warnings:[],stats:o.stats};let r,s,l=[];try{let c=i?.parsed??oa(e,t,i?.basePath);l=c.referencedTemplatePaths;let d={version:i?.version,actionEntityStore:i?.actionEntityStore},h=c.testFlow?.baseURL?{...c.use,baseURL:c.testFlow.baseURL}:c.use;c.suite?r=Bc(c.suite,{...d,testName:c.name,tags:c.tags,use:c.use}):r=Uc(c.testFlow,{...d,testName:c.name,tags:c.tags,use:h,beforeEach:c.beforeEach,afterEach:c.afterEach,parameters:c.parameters,timeout:c.timeout,skip:c.skip,fail:c.fail,only:c.only,slow:c.slow});let m=r.split(`
|
|
4367
4367
|
`).filter(g=>!g.startsWith("import ")).join(`
|
|
4368
|
-
`);new Function(m),s=t.replace(/\.test\.yaml$/,".yaml.spec.ts"),(0,vt.mkdirSync)((0,Yo.dirname)(s),{recursive:!0}),(0,vt.writeFileSync)(s,r)}catch(c){let d=c instanceof aa?"":c.message.includes("Unexpected token")?" This usually means a YAML escaping issue \u2014 in double-quoted strings, use \\\\/ instead of \\/ for regex patterns, or use single quotes / block scalars.":" This may indicate a transpiler bug \u2014 please report it.";return{valid:!1,errors:[`Transpilation failed: ${c.message}.${d}`],warnings:[],stats:o?.stats??{total:0,action:0,draft:0,coverage:0},referencedTemplatePaths:l}}return{valid:!0,errors:[],warnings:o?.warnings??[],stats:o?.stats??{total:0,action:0,draft:0,coverage:0},specFile:s,referencedTemplatePaths:l}}var ra="0.1.
|
|
4368
|
+
`);new Function(m),s=t.replace(/\.test\.yaml$/,".yaml.spec.ts"),(0,vt.mkdirSync)((0,Yo.dirname)(s),{recursive:!0}),(0,vt.writeFileSync)(s,r)}catch(c){let d=c instanceof aa?"":c.message.includes("Unexpected token")?" This usually means a YAML escaping issue \u2014 in double-quoted strings, use \\\\/ instead of \\/ for regex patterns, or use single quotes / block scalars.":" This may indicate a transpiler bug \u2014 please report it.";return{valid:!1,errors:[`Transpilation failed: ${c.message}.${d}`],warnings:[],stats:o?.stats??{total:0,action:0,draft:0,coverage:0},referencedTemplatePaths:l}}return{valid:!0,errors:[],warnings:o?.warnings??[],stats:o?.stats??{total:0,action:0,draft:0,coverage:0},specFile:s,referencedTemplatePaths:l}}var ra="0.1.75";function qo(e){try{return(0,Re.statSync)(e).mtimeMs}catch{return 0}}var qc=`// @generated by shiplightai v${ra}`;function Zc(e,t){if(!(0,Re.existsSync)(e)||(0,Re.readFileSync)(e,"utf-8").split(`
|
|
4369
4369
|
`,1)[0]!==qc)return!1;let a=qo(e);for(let n of t)if(qo(n)>a)return!1;return!0}function Qc(e){let t=process.argv.slice(2),i=[],a=(0,qe.resolve)(e);for(let n of t){if(n.startsWith("-"))continue;let o=n.endsWith(".yaml.spec.ts")?n.replace(/\.yaml\.spec\.ts$/,".test.yaml"):n;if(!o.endsWith(".test.yaml"))continue;let r=(0,qe.resolve)(e,o);(0,Re.existsSync)(r)&&i.push(r.startsWith(a)?r.slice(a.length+1):o)}return i.length>0?i:null}function Qo(e){let t=Qc(e.cwd),i=t??(0,Zo.globSync)("**/*.test.yaml",{cwd:e.cwd,ignore:["**/node_modules/**"]}),a=[];for(let n of i){let o=(0,qe.resolve)(e.cwd,n),r=o.replace(/\.test\.yaml$/,".yaml.spec.ts"),s=(0,Re.readFileSync)(o,"utf-8");try{let l=oa(s,o,e.projectRoot??e.cwd),c=(0,qe.relative)(e.cwd,o),d=e.actionEntityStores?.get(c)??e.actionEntityStores?.get("*");if(!(d&&Object.keys(d.entries).length>0)&&Zc(r,[o,...l.referencedTemplatePaths]))continue;let m=Jo(s,o,{version:ra,actionEntityStore:d,parsed:l});if(!m.valid)throw new Error(m.errors.join("; "))}catch(l){console.error(`[shiplight] Failed to transpile ${n}:`,l),a.push({file:n,error:l})}}if(a.length>0){let n=`[shiplight] Transpilation failed for ${a.length} file(s):
|
|
4370
4370
|
`+a.map(o=>` - ${o.file}`).join(`
|
|
4371
4371
|
`);if(t)throw new Error(n);console.warn(n+" (skipped)")}}var re=X(require("fs"),1),_t=X(require("path"),1),sr=require("glob");Di();function lr(e){let t=Ni().SHIPLIGHT_API_TOKEN;return process.env.CI&&t?new ua:new da(e)}var cd=".shiplight/action-cache";function rr(e){return e.replace(/\//g,"__")+".json"}function dd(e){return e.replace(/\.json$/,"").replace(/__/g,"/")}var da=class{constructor(t){this.cwd=t;this.cacheDir=_t.join(t,cd)}isCloud=!1;cacheDir;async lookup(t){let i=new Map;if(t.length===0||!re.existsSync(this.cacheDir))return i;for(let a of t){let n=_t.join(this.cacheDir,rr(a));try{if(re.existsSync(n)){let o=re.readFileSync(n,"utf-8");i.set(a,JSON.parse(o))}}catch{}}return i}async update(t){if(t.size===0)return 0;re.mkdirSync(this.cacheDir,{recursive:!0});let i=0;for(let[a,n]of t)try{let o=_t.join(this.cacheDir,rr(a)),r=Zn();if(re.existsSync(o))try{r=JSON.parse(re.readFileSync(o,"utf-8"))}catch{}let s={...r,entries:{...r.entries,...n.entries}};re.writeFileSync(o,JSON.stringify(s,null,2)),i++}catch{}return i}loadAll(){if(!re.existsSync(this.cacheDir))return;let t=(0,sr.globSync)("*.json",{cwd:this.cacheDir});if(t.length===0)return;let i=new Map,a=0;for(let n of t)try{let o=re.readFileSync(_t.join(this.cacheDir,n),"utf-8"),r=JSON.parse(o),s=dd(n);i.set(s,r),a+=Object.keys(r.entries??{}).length}catch{}if(i.size!==0)return console.log(`[shiplight] Cache: loaded ${a} cached action entit${a===1?"y":"ies"} for ${i.size} test file${i.size!==1?"s":""}`),i}},ua=class{isCloud=!0;async lookup(t){let{lookupActionStores:i}=await Promise.resolve().then(()=>(ca(),la));return i(t)}async update(t){let{updateActionStores:i}=await Promise.resolve().then(()=>(ca(),la));return i(t)}loadAll(){}};Di();function ur(e={}){e.dotenv!==!1&&hd(e.scanDir||process.cwd());let t=e.scanDir||process.cwd(),a=lr(t).loadAll();Qo({cwd:t,projectRoot:process.cwd(),actionEntityStores:a});let n=process.env.SHIPLIGHT_REPORT_DIR,o=process.env.SHIPLIGHT_RUN_ID??ud();return process.env.SHIPLIGHT_RUN_ID=o,n?{outputDir:`test-results/${o}`,reporter:[["list"],["shiplightai/reporter",{outputFolder:n,open:"never"}]]}:{outputDir:`test-results/${o}`,reporter:[["list"],["shiplightai/reporter",{outputFolder:`shiplight-report/${o}`,latestSymlinkDir:"shiplight-report",open:"never"}]]}}function ud(){let e=new Date,t=(i,a=2)=>String(i).padStart(a,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}-${t(e.getMinutes())}-${t(e.getSeconds())}-${t(e.getMilliseconds(),3)}`}function hr(e,...t){return(0,dr.defineConfig)(e,...t)}function hd(e){ir(e);for(let t of sa(e))cr.default.config({path:t})}R();R();Bt();it();var ao=require("zod"),ph=ao.z.object({instruction:ao.z.string().describe('The instruction of the operation to perform. Can only include one operation. Do not inlcude element indexes just describe the element, e.g. "select the text "Hello, world!" in "Hello, world!""')});function Ml(e){e.register({name:"perform_accurate_operation",description:"Perform an operation that requires accurate interaction like dragging or interacting with a specific area of an element. Only use this action when neccecary.",schema:ph,usesElementIndex:!1,async execute(t,i){let{instruction:a}=t,n={page:i.page,agentServices:i.agentServices,domService:i.domService},o=await tt(a,n,{});if(o.status==="error"||!o.actionEntity)return{success:!1,actionEntity:{action_description:a,action_data:{action_name:"perform_accurate_operation",kwargs:{instruction:a}}},error:o.error||"Failed to generate action"};let{actionEntity:r}=o,s=await Wt(r,n);return{success:s.success,actionEntity:r,message:s.success?`Successfully executed action: ${r.action_data?.action_name}`:void 0,error:s.error}}})}Ae();R();var Il=require("ai"),Pl=require("html-to-text");async function mh(e,t,i){let{apiKey:a,domain:n}=e;if(!a||!n)throw new Error("Mailgun configuration missing. Please provide apiKey and domain");let o=[];try{let r=`https://api.mailgun.net/v3/${n}/events`,s={event:"accepted",limit:"10",ascending:"yes",recipient:t};if(i.from_email&&(s.from=i.from_email),i.since)s.begin=Math.floor(i.since/1e3).toString();else{let d=new Date(Date.now()-6e5);s.begin=Math.floor(d.getTime()/1e3).toString()}u.info(`Mailgun params: ${JSON.stringify(s)}`);let l=await fetch(r+"?"+new URLSearchParams(s),{method:"GET",headers:{Authorization:`Basic ${Buffer.from(`api:${a}`).toString("base64")}`}});if(!l.ok){let d=await l.text();throw new Error(`Mailgun events API error: ${d}`)}let c=(await l.json()).items||[];for(let d of c.slice(0,10)){if(d.event!=="accepted")continue;let h=(d.storage||{}).url;if(u.info(`message_url: ${h}`),!h){let f=(d.message||{}).headers||{},y=f.subject||"",b=f.from||"",p=f.to||"";if(i.from_email&&!b.toLowerCase().includes(i.from_email.toLowerCase())||i.to_email&&!p.toLowerCase().includes(i.to_email.toLowerCase())||i.subject&&!y.toLowerCase().includes(i.subject.toLowerCase()))continue;o.push({subject:y,from:b,to:p,date:new Date(d.timestamp*1e3).toUTCString(),body:"Message body not available (Mailgun storage disabled)",message_id:f["message-id"]||""});continue}let m=h.split("/"),g=m[m.length-1];if(u.info(`Storage key: ${g}`),g){let f=`https://api.mailgun.net/v3/domains/${n}/messages/${g}`;try{let y=await fetch(f,{method:"GET",headers:{Authorization:`Basic ${Buffer.from(`api:${a}`).toString("base64")}`,Accept:"application/json"}});if(y.ok){let b=await y.json(),p=b.Subject||"",x=b.From||"",S=b.To||"",E=b.Date||"",A=b["Message-Id"]||"";u.info(`subject: ${p}`),u.info(`from_addr: ${x}`),u.info(`to_addr: ${S}`),u.info(`date: ${E}`),u.info(`message_id: ${A}`);let M=b["body-html"]||b["body-plain"]||"";if(M&&M.includes("<")&&(M=(0,Pl.convert)(M)),u.info(`Body: ${M.substring(0,200)}...`),i.subject&&!p.toLowerCase().includes(i.subject.toLowerCase())||i.body_contains&&!M.toLowerCase().includes(i.body_contains.toLowerCase()))continue;o.push({subject:p,from:x,to:S,date:E,body:M,message_id:A});continue}else u.warn(`Messages API returned ${y.status}`)}catch(y){u.warn(`Failed to parse JSON response: ${y}`)}}try{let f=await fetch(h,{method:"GET",headers:{Authorization:`Basic ${Buffer.from(`api:${a}`).toString("base64")}`}});if(!f.ok){u.warn(`Could not fetch stored message: ${f.status}`);continue}let y=await f.text();u.info(`Fallback: Raw email length: ${y.length}`);let b=y.split(`
|
package/dist/cjs/reporter.cjs
CHANGED
|
@@ -883,9 +883,9 @@
|
|
|
883
883
|
});
|
|
884
884
|
</script>
|
|
885
885
|
</body>
|
|
886
|
-
</html>`}var Ie="0.1.
|
|
886
|
+
</html>`}var Ie="0.1.75",Le=Ie!=="dev"?Ie:void 0;var hn=3600*1e3,fn=10080*60*1e3;var xt={before:0,main:1,teardown:2,after:3};function Ne(e){let t=e.split(".")[0];return xt[t]??1}function Ce(e){return e.split(".").map(t=>{let r=Number(t);return Number.isNaN(r)?0:r})}function kt(e){return[...e].sort(([t],[r])=>{let i=Ne(t),n=Ne(r);if(i!==n)return i-n;let a=Ce(t),o=Ce(r);for(let p=0;p<Math.max(a.length,o.length);p++){let h=a[p]??-1,l=o[p]??-1;if(h!==l)return h-l}return 0})}function Tt(e){let t=new Set;for(let r of e)if(t.add(r.category),r.category==="hook")for(let i of r.steps)t.add(i.category);return t}function At(e,t){let r=e.toLowerCase();return r.includes("before")?"before":r.includes("after")?"after":t}function ie(e,t="main",r,i,n){r===void 0&&(r=!Tt(e).has("test.step")),n||(n=new Map);let a=[];for(let o of e){if(o.category==="fixture"||o.category==="test.attach")continue;if(o.category==="hook"){let h=At(o.title,t);a.push(...ie(o.steps,h,r,i,n));continue}if(o.category==="test.step"||r&&(o.category==="expect"||o.category==="pw:api")){let h=n.get(t)??0;n.set(t,h+1);let l=`${t}.${h}`,g={stepId:l,description:o.title,status:o.error?"failure":o.duration===-1?"skipped":"success",duration:o.duration>=0?o.duration:void 0};o.error&&(g.error=o.error.message??o.error.stack),i&&o.location&&i.set(l,o.location),a.push(g),o.steps.length>0&&a.push(...ie(o.steps,l,r,i,n))}}return a}function $t(e,t){let r=w.isAbsolute(e)?e:w.join(process.cwd(),e),i=w.join(r,"latest");try{if(x.lstatSync(i).isSymbolicLink())x.unlinkSync(i);else{console.warn("[report] 'latest' exists and is not a symlink; skipping update");return}}catch{}try{process.platform==="win32"?x.symlinkSync(w.join(r,t),i,"junction"):x.symlinkSync(t,i,"dir")}catch(n){console.warn(`[report] Could not create 'latest' symlink: ${n instanceof Error?n.message:String(n)}`)}}var ne=class{outputFolder;openMode;latestSymlinkDir;collected=[];config;runStartTime;constructor(t={}){this.outputFolder=t.outputFolder||"shiplight-report",this.openMode=t.open||"on-failure",this.latestSymlinkDir=t.latestSymlinkDir}onBegin(t,r){this.config=t,this.runStartTime=new Date().toISOString()}onTestEnd(t,r){this.collected.push({test:t,result:r})}async onEnd(t){if(this.collected.length===0)return;let r=new Map;for(let l of this.collected){let g=l.test.titlePath().join(" > "),b=r.get(g);b||(b=[],r.set(g,b)),b.push(l)}let i=[];for(let[,l]of r.entries()){let g=l[0].test.location.file,b=[],c,u,m;for(let y=0;y<l.length;y++){let{test:v,result:A}=l[y],$=await this.buildReportTest(v,A,g);c=$,u||(u=$.startTime),m=$.endTime,b.push({attemptNumber:y+1,status:A.status,duration:A.duration,steps:$.steps,error:$.error,videoPath:$.videoPath,tracePath:$.tracePath})}let d=b[b.length-1],{test:S}=l[l.length-1],_={title:S.title,baseTitle:c?.baseTitle,file:w.relative(process.cwd(),g),status:d.status,duration:d.duration,steps:d.steps,error:d.error,videoPath:d.videoPath,tracePath:d.tracePath,actionStepsMap:c?.actionStepsMap,tags:c?.tags,baseUrl:c?.baseUrl,skip:c?.skip,slow:c?.slow,timeout:c?.timeout,parameterSetName:c?.parameterSetName,startTime:u,endTime:m,suiteName:c?.suiteName};b.length>1&&(_.retries=b.length-1,_.attempts=b,b.some(v=>v.status==="failed"||v.status==="timedOut")&&d.status==="passed"&&(_.flaky=!0)),i.push(_)}let n={tests:i,totalDuration:t.duration,timestamp:new Date().toISOString(),shiplightVersion:Le},a=w.isAbsolute(this.outputFolder)?this.outputFolder:w.join(process.cwd(),this.outputFolder);x.mkdirSync(a,{recursive:!0});let o=w.join(a,"screenshots");for(let l=0;l<n.tests.length;l++){let g=n.tests[l],b=g.attempts&&g.attempts.length>0,c=[{obj:g,prefix:b?`test-${l}-attempt-0`:`test-${l}`,screenshotSubDir:`test-${l}`}];if(g.attempts)for(let u=0;u<g.attempts.length;u++)c.push({obj:g.attempts[u],prefix:`test-${l}-attempt-${u+1}`,screenshotSubDir:`test-${l}/attempt-${u}`});for(let{obj:u,prefix:m,screenshotSubDir:d}of c){let S=w.join(o,d),_=!1;for(let y of u.steps)if(y.screenshot&&w.isAbsolute(y.screenshot))try{_||(x.mkdirSync(S,{recursive:!0}),_=!0);let v=`${y.stepId.replace(/\./g,"-")}.png`;x.copyFileSync(y.screenshot,w.join(S,v)),y.screenshot=`screenshots/${d}/${v}`}catch(v){console.warn(`[reporter] Failed to copy screenshot for ${y.stepId}:`,v)}if(u.videoPath&&w.isAbsolute(u.videoPath)){let y=w.extname(u.videoPath)||".webm",v=`${m}-video${y}`;try{x.copyFileSync(u.videoPath,w.join(a,v)),u.videoPath=v}catch{u.videoPath=void 0}}if(u.tracePath&&w.isAbsolute(u.tracePath)){let y=w.extname(u.tracePath)||".zip",v=`${m}-trace${y}`;try{x.copyFileSync(u.tracePath,w.join(a,v)),u.tracePath=v}catch{u.tracePath=void 0}}}}let p=w.join(a,"report-data.json");x.writeFileSync(p,JSON.stringify(n,null,2),"utf-8");let h=w.join(a,"index.html");if(x.writeFileSync(h,Oe({...n,outputDir:a}),"utf-8"),console.log(`
|
|
887
887
|
Shiplight report written to: ${h}`),this.latestSymlinkDir&&$t(this.latestSymlinkDir,w.basename(a)),this.openMode==="always"||this.openMode==="on-failure"&&t.status!=="passed")try{let l=(await import("open")).default;await l(h)}catch{}}printsToStdio(){return!1}async buildReportTest(t,r,i){let n={title:t.title,file:w.relative(process.cwd(),i),status:r.status,duration:r.duration,steps:[],startTime:new Date(r.startTime).toISOString(),endTime:new Date(r.startTime.getTime()+r.duration).toISOString()};r.errors.length>0&&(n.error=r.errors.map(c=>c.message||c.stack||String(c)).join(`
|
|
888
888
|
|
|
889
|
-
`)),r.stdout.length>0&&(n.stdout=r.stdout.map(c=>typeof c=="string"?c:c.toString()).join("")),r.stderr.length>0&&(n.stderr=r.stderr.map(c=>typeof c=="string"?c:c.toString()).join(""));for(let c of r.attachments)c.name==="video"&&c.path&&(n.videoPath=c.path),c.name==="trace"&&c.path&&(n.tracePath=c.path);let a=r.attachments.find(c=>c.name==="shiplight-results"),o=null;if(a)try{if(a.body)o=JSON.parse(a.body.toString("utf-8"));else if(a.path){let c=x.readFileSync(a.path,"utf-8");o=JSON.parse(c)}}catch{}let p=i.replace(/\.yaml\.spec\.ts$/,".test.yaml"),h={},l=t.title.match(/^(.*)\s+\[([^\]]+)\]$/),g=l?l[1]:t.title,b=l?l[2]:void 0;if(b&&(n.parameterSetName=b),x.existsSync(p))try{let c=x.readFileSync(p,"utf-8"),u=$e(c,p);if(u.suite){let m=u.suite.tests.find(d=>d.name===g);m&&(h=J(m.testFlow),m.tags?.length&&(n.tags=m.tags),m.skip!==void 0&&(n.skip=m.skip),m.slow&&(n.slow=m.slow),m.timeout!==void 0&&(n.timeout=m.timeout),n.baseTitle=m.name||m.testFlow?.goal),n.suiteName=u.name,u.tags?.length&&(n.suiteTags=u.tags),u.use?.baseURL&&(n.baseUrl=u.use.baseURL)}else u.testFlow&&(h=J(u.testFlow),n.baseTitle=u.name||u.testFlow?.goal,u.tags?.length&&(n.tags=u.tags),u.use?.baseURL&&(n.baseUrl=u.use.baseURL))}catch{}if(o||Object.keys(h).length>0){let c=new Set([...Object.keys(h),...Object.keys(o||{})]),u=Array.from(c).map(d=>[d,null]),m=kt(u);for(let[d]of m){let S=h[d],_=o?.[d],y=S?.description;if(!y||y==="Action"||y==="Draft"){let A=S?.action_entity;y=A?.action_description||A?.action_data?.kwargs?.description||_?.description||d}let v={stepId:d,description:y,status:_?.status||"pending",duration:_?.duration};if(_?.message){let A=typeof _.message=="string"?_.message:JSON.stringify(_.message,null,2);_.status==="failure"?v.error=A:v.message=A}if(_?.screenshot){let A=_.screenshot,$=a?.path?w.dirname(a.path):"",I=w.isAbsolute(A)?A:w.join($,A);x.existsSync(I)&&(v.screenshot=I)}_?.code&&(v.code=_.code),n.steps.push(v)}}if(o===null&&Object.keys(h).length===0&&!i.endsWith(".yaml.spec.ts")){let c=new Map;if(n.steps=ie(r.steps,"main",void 0,c),n.steps.length>0){let u=new Map;n.actionStepsMap=Object.fromEntries(n.steps.map(m=>{let d=c.get(m.stepId),S;if(d?.file){if(!u.has(d.file))try{u.set(d.file,x.readFileSync(d.file,"utf-8").split(`
|
|
889
|
+
`)),r.stdout.length>0&&(n.stdout=r.stdout.map(c=>typeof c=="string"?c:c.toString()).join("")),r.stderr.length>0&&(n.stderr=r.stderr.map(c=>typeof c=="string"?c:c.toString()).join(""));for(let c of r.attachments)c.name==="video"&&c.path&&(n.videoPath=c.path),c.name==="trace"&&c.path&&(n.tracePath=c.path);let a=r.attachments.find(c=>c.name==="shiplight-results"),o=null;if(a)try{if(a.body)o=JSON.parse(a.body.toString("utf-8"));else if(a.path){let c=x.readFileSync(a.path,"utf-8");o=JSON.parse(c)}}catch{}let p=i.replace(/\.yaml\.spec\.ts$/,".test.yaml"),h={},l=t.title.match(/^(.*)\s+\[([^\]]+)\]$/),g=l?l[1]:t.title,b=l?l[2]:void 0;if(b&&(n.parameterSetName=b),x.existsSync(p))try{let c=x.readFileSync(p,"utf-8"),u=$e(c,p,this.config.rootDir);if(u.suite){let m=u.suite.tests.find(d=>d.name===g);m&&(h=J(m.testFlow),m.tags?.length&&(n.tags=m.tags),m.skip!==void 0&&(n.skip=m.skip),m.slow&&(n.slow=m.slow),m.timeout!==void 0&&(n.timeout=m.timeout),n.baseTitle=m.name||m.testFlow?.goal),n.suiteName=u.name,u.tags?.length&&(n.suiteTags=u.tags),u.use?.baseURL&&(n.baseUrl=u.use.baseURL)}else u.testFlow&&(h=J(u.testFlow),n.baseTitle=u.name||u.testFlow?.goal,u.tags?.length&&(n.tags=u.tags),u.use?.baseURL&&(n.baseUrl=u.use.baseURL))}catch{}if(o||Object.keys(h).length>0){let c=new Set([...Object.keys(h),...Object.keys(o||{})]),u=Array.from(c).map(d=>[d,null]),m=kt(u);for(let[d]of m){let S=h[d],_=o?.[d],y=S?.description;if(!y||y==="Action"||y==="Draft"){let A=S?.action_entity;y=A?.action_description||A?.action_data?.kwargs?.description||_?.description||d}let v={stepId:d,description:y,status:_?.status||"pending",duration:_?.duration};if(_?.message){let A=typeof _.message=="string"?_.message:JSON.stringify(_.message,null,2);_.status==="failure"?v.error=A:v.message=A}if(_?.screenshot){let A=_.screenshot,$=a?.path?w.dirname(a.path):"",I=w.isAbsolute(A)?A:w.join($,A);x.existsSync(I)&&(v.screenshot=I)}_?.code&&(v.code=_.code),n.steps.push(v)}}if(o===null&&Object.keys(h).length===0&&!i.endsWith(".yaml.spec.ts")){let c=new Map;if(n.steps=ie(r.steps,"main",void 0,c),n.steps.length>0){let u=new Map;n.actionStepsMap=Object.fromEntries(n.steps.map(m=>{let d=c.get(m.stepId),S;if(d?.file){if(!u.has(d.file))try{u.set(d.file,x.readFileSync(d.file,"utf-8").split(`
|
|
890
890
|
`))}catch{u.set(d.file,[])}let y=u.get(d.file);S=y[d.line-1]?.trim();let v=d.line-2,A=d.line,$=[],I=d.line;v>=0&&($.push(y[v]??""),I=d.line-1),$.push(y[d.line-1]??""),A<y.length&&$.push(y[A]??""),m.code=$.join(`
|
|
891
891
|
`),m.codeStartLine=I,m.codeLine=d.line}let _={description:m.description,...S&&{action_entity:{action_description:m.description,action_data:{action_name:"js_code",args:[],kwargs:{code:S}}}}};return[m.stepId,_]}))}}return Object.keys(h).length>0?n.actionStepsMap=h:o&&n.steps.length>0&&(n.actionStepsMap=Object.fromEntries(n.steps.map(c=>{let u=o[c.stepId],m=u?.type,d={description:c.description,...m&&{action_entity:{action_description:c.description,action_data:{action_name:m==="step"?"js_code":m,args:[],kwargs:m==="step"?{code:u?.code??c.description}:{statement:c.description}}}}};return[c.stepId,d]}))),n}},De=ne;
|