@checksum-ai/runtime 4.16.0 → 4.16.2-beta.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/.env +1 -1
- package/cli.js +106 -106
- package/index.js +1 -1
- package/package.json +2 -2
- package/scripts/playwright_patches/1.62.1.js +562 -0
- package/test-run-monitor.js +33 -33
package/index.js
CHANGED
|
@@ -416,7 +416,7 @@ ${c}
|
|
|
416
416
|
})`,{filename:i})(s,(0,joe.createRequire)(i),r,i,(0,Hoe.dirname)(i));let p=r.exports,d=p.default;return d===void 0?p:d}u(Joe,"requireChecksumConfig");var kw=require("fs"),Zoe=require("module"),Xoe=require("node:util");var hc={defaultMerge:Symbol("deepmerge-ts: default merge"),skip:Symbol("deepmerge-ts: skip")},Y_t={defaultMerge:hc.defaultMerge};function QFe(i,n){return n}u(QFe,"defaultMetaDataUpdater");function MFe(i,n){return i.filter(c=>c!==void 0)}u(MFe,"defaultFilterValues");var qoe;(function(i){i[i.NOT=0]="NOT",i[i.RECORD=1]="RECORD",i[i.ARRAY=2]="ARRAY",i[i.SET=3]="SET",i[i.MAP=4]="MAP",i[i.OTHER=5]="OTHER"})(qoe||(qoe={}));function $oe(i){return typeof i!="object"||i===null?0:Array.isArray(i)?2:jFe(i)?1:i instanceof Set?3:i instanceof Map?4:5}u($oe,"getObjectType");function FFe(i){let n=new Set;for(let c of i)for(let s of[...Object.keys(c),...Object.getOwnPropertySymbols(c)])n.add(s);return n}u(FFe,"getKeys");function UFe(i,n){return typeof i=="object"&&Object.prototype.propertyIsEnumerable.call(i,n)}u(UFe,"objectHasProperty");function zoe(i){let n=0,c=i[0]?.[Symbol.iterator]();return{[Symbol.iterator](){return{next(){do{if(c===void 0)return{done:!0,value:void 0};let s=c.next();if(s.done===!0){n+=1,c=i[n]?.[Symbol.iterator]();continue}return{done:!1,value:s.value}}while(!0)}}}}}u(zoe,"getIterableOfIterables");var Voe=["[object Object]","[object Module]"];function jFe(i){if(!Voe.includes(Object.prototype.toString.call(i)))return!1;let{constructor:n}=i;if(n===void 0)return!0;let c=n.prototype;return!(c===null||typeof c!="object"||!Voe.includes(Object.prototype.toString.call(c))||!c.hasOwnProperty("isPrototypeOf"))}u(jFe,"isRecord");function HFe(i,n,c){let s={};for(let r of FFe(i)){let f=[];for(let h of i)UFe(h,r)&&f.push(h[r]);if(f.length===0)continue;let p=n.metaDataUpdater(c,{key:r,parents:i}),d=Koe(f,n,p);d!==hc.skip&&(r==="__proto__"?Object.defineProperty(s,r,{value:d,configurable:!0,enumerable:!0,writable:!0}):s[r]=d)}return s}u(HFe,"mergeRecords$1");function WFe(i){return i.flat()}u(WFe,"mergeArrays$1");function GFe(i){return new Set(zoe(i))}u(GFe,"mergeSets$1");function JFe(i){return new Map(zoe(i))}u(JFe,"mergeMaps$1");function qFe(i){return i.at(-1)}u(qFe,"mergeOthers$1");var Cw={mergeRecords:HFe,mergeArrays:WFe,mergeSets:GFe,mergeMaps:JFe,mergeOthers:qFe};function Yoe(...i){return $Fe({})(...i)}u(Yoe,"deepmerge");function $Fe(i,n){let c=VFe(i,s);function s(...r){return Koe(r,c,n)}return u(s,"customizedDeepmerge"),s}u($Fe,"deepmergeCustom");function VFe(i,n){return{defaultMergeFunctions:Cw,mergeFunctions:{...Cw,...Object.fromEntries(Object.entries(i).filter(([c,s])=>Object.hasOwn(Cw,c)).map(([c,s])=>s===!1?[c,Cw.mergeOthers]:[c,s]))},metaDataUpdater:i.metaDataUpdater??QFe,deepmerge:n,useImplicitDefaultMerging:i.enableImplicitDefaultMerging??!1,filterValues:i.filterValues===!1?void 0:i.filterValues??MFe,actions:hc}}u(VFe,"getUtils");function Koe(i,n,c){let s=n.filterValues?.(i,c)??i;if(s.length===0)return;if(s.length===1)return NM(s,n,c);let r=$oe(s[0]);if(r!==0&&r!==5){for(let f=1;f<s.length;f++)if($oe(s[f])!==r)return NM(s,n,c)}switch(r){case 1:return zFe(s,n,c);case 2:return YFe(s,n,c);case 3:return KFe(s,n,c);case 4:return ZFe(s,n,c);default:return NM(s,n,c)}}u(Koe,"mergeUnknowns");function zFe(i,n,c){let s=n.mergeFunctions.mergeRecords(i,n,c);return s===hc.defaultMerge||n.useImplicitDefaultMerging&&s===void 0&&n.mergeFunctions.mergeRecords!==n.defaultMergeFunctions.mergeRecords?n.defaultMergeFunctions.mergeRecords(i,n,c):s}u(zFe,"mergeRecords");function YFe(i,n,c){let s=n.mergeFunctions.mergeArrays(i,n,c);return s===hc.defaultMerge||n.useImplicitDefaultMerging&&s===void 0&&n.mergeFunctions.mergeArrays!==n.defaultMergeFunctions.mergeArrays?n.defaultMergeFunctions.mergeArrays(i):s}u(YFe,"mergeArrays");function KFe(i,n,c){let s=n.mergeFunctions.mergeSets(i,n,c);return s===hc.defaultMerge||n.useImplicitDefaultMerging&&s===void 0&&n.mergeFunctions.mergeSets!==n.defaultMergeFunctions.mergeSets?n.defaultMergeFunctions.mergeSets(i):s}u(KFe,"mergeSets");function ZFe(i,n,c){let s=n.mergeFunctions.mergeMaps(i,n,c);return s===hc.defaultMerge||n.useImplicitDefaultMerging&&s===void 0&&n.mergeFunctions.mergeMaps!==n.defaultMergeFunctions.mergeMaps?n.defaultMergeFunctions.mergeMaps(i):s}u(ZFe,"mergeMaps");function NM(i,n,c){let s=n.mergeFunctions.mergeOthers(i,n,c);return s===hc.defaultMerge||n.useImplicitDefaultMerging&&s===void 0&&n.mergeFunctions.mergeOthers!==n.defaultMergeFunctions.mergeOthers?n.defaultMergeFunctions.mergeOthers(i):s}u(NM,"mergeOthers");var ere=!1;function Foe(i){ere=i}u(Foe,"setLogToConsole");function ye(...i){ere&&process.stdout.write(`${(0,Xoe.format)(...i)}
|
|
417
417
|
`)}u(ye,"log");function XFe(i,n){return i in n}u(XFe,"isLocatorMethod");async function ZX(i,n,c,s=6e4){if(!XFe(n,i))return i;let r=u(()=>{let f=i[n];return typeof f=="function"?Reflect.apply(f,i,c):f},"executor");return s===null?r():dt(r(),s,"Execution timeout")}u(ZX,"executePlaywrightMethodWithTimeout");function LM({envName:i,role:n}={}){let c=process.env.CHECKSUM_RUNTIME_ENV_OVERRIDE_NAME??i,s=process.env.CHECKSUM_RUNTIME_ENV_OVERRIDE_ROLE??n;return{...c!==void 0?{envName:c}:{},...s!==void 0?{role:s}:{}}}u(LM,"applyRuntimeEnvOverrides");function QM(i,{role:n,environment:c}={},s=!1){let r;if(c&&(r=i.environments?.find(({name:d})=>c===d)),r??=i.environments?.find(({default:d})=>d),!r)throw new Error("Environment not found. Please make sure your environments are properly defined in the checksum.config.ts file.");let f=r.users,p;if(f&&(n!==void 0&&(p=f.find(d=>d.role===n)),p??=f.find(d=>d.default)),!p)throw new Error(`User not found. Please make sure the users array for the "${r.name}" environment is properly defined in the checksum.config.ts file.`);if(c&&r.name!==c){if(s)throw new Error(`Could not find environment with name "${c}" in config file`);console.warn(`Could not find environment with name "${c}" in config file, trying to use default environment`)}if(n&&p.role!==n){if(s)throw new Error(`Could not find user with role "${n}" for environment "${c}" in config file`);console.warn(`Could not find user with role "${n}" for environment "${c}" in config file, trying to login with environment's default user`)}return{environment:r,user:p}}u(QM,"resolveEnvironment");function e3e(i){let n=`${i??Po()}/login.ts`;if(!(0,kw.existsSync)(n))throw console.warn(`Could not locate the login.ts file. Please make sure your login file exists at ${n}`),new Error("Could not find login.ts file");try{return(0,Zoe.createRequire)(__filename)(n).default}catch(c){throw console.warn("Error loading login.ts file",c),c}}u(e3e,"requireLogin");async function t3e(i,n,{environment:c,user:s,config:r}){try{let f=u(()=>n(i,{environment:c,user:s,config:r}),"performLogin");"checksumAI"in i?await i.checksumAI(`Log in${s.role?` using ${s.role} role`:""}${c.name?` in ${c.name} environment`:""}`,f,{skipAutoRecovery:!0}):await f()}catch(f){throw console.warn(`The login method threw an exception, please check the login.ts file for the following error:
|
|
418
418
|
`,f),f}}u(t3e,"proceedWithLogin");function ds(i){let{config:n,folder:c,throwIfAuthFailed:s}=i,r=e3e(c);return async(f,{role:p,environment:d}={})=>{let{envName:h,role:o}=LM({...d!==void 0?{envName:d}:{},...p!==void 0?{role:p}:{}}),{environment:a,user:e}=QM(n,{...o!==void 0?{role:o}:{},...h!==void 0?{environment:h}:{}},i.throwIfEnvInfoInvalid);if(s&&!e)throw new Error("Could not find user credentials matching the provided role and/or environment");await t3e(f,r,{environment:a,user:e,config:n})}}u(ds,"makeUnboundLogin");function tre(i,{environmentName:n,userRole:c}){let s=ds(i);return r=>s(r,{environment:n,role:c})}u(tre,"makeBoundLogin");var or;function AI(){if(or)return or;try{let i=(0,kw.existsSync)(`${Po()}/checksum.config.ts`)?"checksum.config.ts":(0,kw.existsSync)(`${Po()}/checksum.config.tmp.ts`)?"checksum.config.tmp.ts":void 0;if(i)return Tw(Joe(`${Po()}/${i}`))}catch{console.warn("Could not find checksum config file, will run with defaults")}return Tw()}u(AI,"loadChecksumConfig");function Tw(i={}){let n={apiKey:"",runMode:"normal",apiURL:"https://api.checksum.ai",options:{useChecksumSelectors:!0,useChecksumAI:{actions:!0,assertions:!1,skipTestsWithKnownBugs:!0},newAssertionsEnabled:!0,useMockData:!1,printLogs:!1,consecutiveActionDelay:100,hideReports:process.env.AUTHORIZE_REPORTS==="true"}};return i.options?.useChecksumAI?.visualComparison===void 0&&i.options?.useChecksumAI?.assertions&&(i.options.useChecksumAI.visualComparison=!0),or=Yoe(n,i),process.env.CHECKSUM_API_URL&&(or.apiURL=process.env.CHECKSUM_API_URL),Fe.testRun.disableAutoRecovery&&or.options&&(or.options.useChecksumAI={actions:!1,assertions:!1,visualComparison:!1}),Fe.testRun.disableHostReports&&or.options&&(or.options.hostReports=!1),or.options&&(Fe.testRun.disableTimeMachine&&(or.options.disableTimeMachine=!0),Fe.testRun.disableRrwebRecording&&(or.options.disableRrwebRecording=!0)),or}u(Tw,"getChecksumConfig");var sc="Checksum failed connecting to the server";var IBt=require("@playwright/test");async function nre(i){await i.body?.cancel().catch(()=>{})}u(nre,"drainBody");var n3e="http://127.0.0.1";async function MM(i,n){let c=n.fetchImpl??globalThis.fetch;try{let s=await c(`${n3e}:${n.port}/`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i),signal:AbortSignal.timeout(n.timeoutMs)});return await nre(s),s.ok?!0:(n.onError?.(new Error(`monitor rejected message with status ${s.status}`)),!1)}catch(s){return n.onError?.(s),!1}}u(MM,"postToMonitor");async function FM(i,n){return await MM(i,n)?!0:n.attempts<=1?!1:(await o3e(n.retryDelayMs),FM(i,{...n,attempts:n.attempts-1}))}u(FM,"postToMonitorWithRetry");function o3e(i){return new Promise(n=>{setTimeout(n,i)})}u(o3e,"sleep");var xw={uploadTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_TIMEOUT_MS",fallback:6e5,min:5e3,max:36e5},noProgressAbortMs:{env:"CHECKSUM_RUNTIME_UPLOAD_NO_PROGRESS_MS",fallback:6e4,min:5e3,max:6e5},assetDeadlineMs:{env:"CHECKSUM_RUNTIME_UPLOAD_ASSET_DEADLINE_MS",fallback:12e5,min:3e4,max:54e5},maxAttempts:{env:"CHECKSUM_RUNTIME_UPLOAD_MAX_ATTEMPTS",fallback:6,min:1,max:20},stallTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_STALL_TIMEOUT_MS",fallback:6e5,min:3e4,max:36e5},minProgressBytes:{env:"CHECKSUM_RUNTIME_UPLOAD_MIN_PROGRESS_BYTES",fallback:65536,min:1,max:67108864},finalizeBudgetMs:{env:"CHECKSUM_RUNTIME_UPLOAD_FINALIZE_BUDGET_MS",fallback:18e5,min:6e4,max:54e5},finalizeCeilingMs:{env:"CHECKSUM_RUNTIME_UPLOAD_FINALIZE_CEILING_MS",fallback:24e5,min:12e4,max:72e5},cliHardCapMs:{env:"CHECKSUM_RUNTIME_UPLOAD_CLI_HARD_CAP_MS",fallback:27e5,min:12e4,max:72e5},watchTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_WATCH_TIMEOUT_MS",fallback:12e4,min:5e3,max:18e5},ipcTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_IPC_TIMEOUT_MS",fallback:5e3,min:500,max:6e4},onEndFlushTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_ONEND_FLUSH_TIMEOUT_MS",fallback:5e3,min:500,max:6e4},resumableChunkBytes:{env:"CHECKSUM_RUNTIME_UPLOAD_RESUMABLE_CHUNK_BYTES",fallback:8388608,min:262144,max:268435456},connectTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_CONNECT_TIMEOUT_MS",fallback:1e4,min:1e3,max:6e4},headersTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_HEADERS_TIMEOUT_MS",fallback:3e5,min:5e3,max:18e5},bodyTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_BODY_TIMEOUT_MS",fallback:3e5,min:5e3,max:18e5},maxConcurrentUploads:{env:"CHECKSUM_RUNTIME_UPLOAD_MAX_CONCURRENT",fallback:15,min:1,max:64}};function r3e(i,n,c,s){if(i===void 0||i.trim()==="")return n;let r=Number(i);return Number.isInteger(r)?Math.min(s,Math.max(c,r)):n}u(r3e,"clampEnvInt");var i3e=[["cliHardCapMs",["finalizeCeilingMs"],.9],["finalizeCeilingMs",["finalizeBudgetMs"],1],["finalizeBudgetMs",["stallTimeoutMs","assetDeadlineMs","watchTimeoutMs"],1],["assetDeadlineMs",["uploadTimeoutMs"],1],["uploadTimeoutMs",["noProgressAbortMs"],.5]];function a3e(i){let n={...i},c=[];for(let[s,r,f]of i3e)for(let p of r){let d=Math.floor(n[s]*f);n[p]>d&&(c.push(`${xw[p].env} (${n[p]}ms) exceeds its bound under ${xw[s].env} (${n[s]}ms); using ${d}ms`),n[p]=d)}return{tunables:n,warnings:c}}u(a3e,"coerceScopeHierarchy");function c3e(i){let n={};for(let c of Object.keys(xw)){let s=xw[c];n[c]=r3e(i[s.env],s.fallback,s.min,s.max)}return n.resumableChunkBytes=Math.max(1,Math.floor(n.resumableChunkBytes/262144))*262144,a3e(n)}u(c3e,"resolveUploadTunablesDetailed");function UM(i){return c3e(i).tunables}u(UM,"resolveUploadTunables");var gBt=UM({});var l3e=4,ore=3,s3e=500,Pw=class i{constructor(n){this.workerInfo=n;this.hasMonitor=!1;i.monitorAgentPort?this.hasMonitor=!0:ye("CHECKSUM_UPLOAD_AGENT_PORT is not defined"),this.sendPlaywrightConfig()}static{u(this,"TestRunMonitorBridge")}static{this.monitorAgentHost="http://localhost"}static{this.monitorAgentPort=process.env.CHECKSUM_UPLOAD_AGENT_PORT}static{this.playwrightConfigSent=!1}static{this.tunables=UM(process.env)}addAsset(n){this.signalUpload(n,["trace","har","rrweb-recording"].includes(n.type))}addChecksumTestMetadata(n){let c={type:"checksumTestMetadata",payload:n};this.sendMessage(c)}addTestInfo(n,c,s=!1){this.sendMessage({type:"testInfo",payload:{checksumTestId:n,pwTestId:c,usingChecksumTestIdPlaceholder:s}})}addSingleTestStats(n,c){this.sendMessage({type:"testStats",payload:{passed:n,healed:c}})}sendPlaywrightConfig(){if(i.playwrightConfigSent)return;let n=this.buildPlaywrightConfig();this.sendMessage({type:"playwrightConfig",payload:n}),i.playwrightConfigSent=!0}buildPlaywrightConfig(){let{use:n,testDir:c,testMatch:s,testIgnore:r,timeout:f,outputDir:p,retries:d}=this.workerInfo.project,{reporter:h,configFile:o,projects:a}=this.workerInfo.config,e=Object.keys(a).filter(t=>[n,c,s,r,f,p,d].includes(t)).reduce((t,l)=>({...t,[l]:a[Number(l)]}),{});return{reporter:h,...o!==void 0?{configFile:o}:{},filteredProjects:e,use:n,testDir:c,testMatch:s,testIgnore:r,timeout:f,outputDir:p,retries:d}}sendMessage(n){return this.hasMonitor&&i.monitorAgentPort?MM(n,{port:i.monitorAgentPort,timeoutMs:i.tunables.ipcTimeoutMs,onError:u(c=>ye("Failed to send message to test run monitor",n,c),"onError")}):void 0}async signalUpload(n,c=!1){let s=i.monitorAgentPort;if(!this.hasMonitor||!s)return;let r={type:"asset",payload:n,watch:c},f;await FM(r,{port:s,timeoutMs:i.tunables.ipcTimeoutMs*l3e,attempts:ore,retryDelayMs:s3e,onError:u(d=>{f=d,ye("Failed to register asset with test run monitor",r,d)},"onError")})||pv("asset_registration_failed",{test_suite_run_id:process.env.CHECKSUM_TEST_SUITE_ID,outcome:"error",asset_type:n.type,asset_path:n.path,attempts:ore,error:vp(f)})}};var rre=require("@playwright/test"),ire=require("puppeteer-extra-plugin"),are=require("module");var _w=(0,are.createRequire)(__filename),Bw=class i{constructor(n){this.options=n;this.importPluginPackages()}static{u(this,"StealthProvider")}importPluginPackages(){i.pw??=_w("playwright-extra"),i.StealthPlugin??=_w("puppeteer-extra-plugin-stealth")}static createFreshInstance(){try{let{addExtra:n}=_w("playwright-extra");return n(i.pw.chromium)}catch(n){throw console.error("[StealthProvider] Error creating fresh instance:",n),n}}buildChromiumWithPlugins(n){let{project:c}=this.options,s=c.use.userAgent,r=c.use.playwrightExtra??[],f=i.StealthPlugin();if(r.push(f),this.isCustomUserAgent(s)){f.enabledEvasions.delete("user-agent-override");let h=_w("puppeteer-extra-plugin-stealth/evasions/user-agent-override")({userAgent:s});r.push(h)}let p=n??i.pw.chromium;return r.forEach((d,h)=>{try{!(d instanceof ire.PuppeteerExtraPlugin)&&d!==f&&console.warn(`Plugin at index ${h} in the project's checksum.config.ts file is not an instance of PuppeteerExtraPlugin.`),p.use(d)}catch(o){console.warn(o)}}),p}isCustomUserAgent(n){return n?!Object.values(rre.devices).some(c=>n===c.userAgent):!1}};function cre(i,n){return{testSuiteRunId:n,appName:"generic-app",commitHash:"generic-commit-hash",envName:"generic-env-name",branch:"generic-branch",checksumRuntimeVersion:i}}u(cre,"createDefaultTestSuiteRunInfo");var ure=require("crypto");var RBt=require("@playwright/test");var UBt=require("@playwright/test");function lre(i,n){return Reflect.get(i,n)}u(lre,"readDynamicProperty");var Rw=class i{constructor(n){this.context=n;this._pages={};this._pagesInProgress=new Map;this._testAssets=null;this.pageGuidMap=new WeakMap;this.instanceId=++i.instanceCounter,this.proxy=this.createContextProxy()}static{u(this,"ChecksumBrowserContext")}static{this.instanceCounter=0}static{this.guidCounter=0}static makeContext(n){return new i(n).proxy}_rawContext(){return this.context}setTestAssets(n){this._testAssets=n,this.setupPageListener()}getTestAssets(){return this._testAssets}cleanup(){this._pagesInProgress.clear(),this._pages={}}async newPage(){let n=await this.context.newPage();return this.makePage(n)}async makePage(n){if(n._isChecksumPage===!0)return n;if(n.isClosed())throw new Error("Cannot initialize closed page");let c=this.getPageGuid(n),s=this.getPageByGuid(c);if(s)return s;let r=this._pagesInProgress.get(c);if(r)return r;let f=this._createPageInstance(n);this._pagesInProgress.set(c,f);try{let p=await f;return this._pagesInProgress.delete(c),this.addPage(p),p}catch(p){throw this._pagesInProgress.delete(c),p}}addPage(n){let c=this.getPageGuid(n);this._pages[c]=n,n.once("close",()=>{this.removePage(c)})}removePage(n){this._pages[n]&&delete this._pages[n]}async _createPageInstance(n){if(n.isClosed())throw new Error("Cannot initialize page: Page has already been closed");if(this._testAssets)try{return await Sw.init(n,this.proxy,this._testAssets.testRunAnalytics,this._testAssets.monitorBridge,this._testAssets.variableStore,this._testAssets.testInfo,this._testAssets.checksumTestId,this._testAssets.test,this._testAssets.config,this._testAssets.isReplMode)}catch(c){throw new Error(`Failed to initialize RuntimePage: ${c instanceof Error?c.message:String(c)}. Test assets must be properly configured.`)}throw new Error("Cannot create page: Test assets not set. Use setTestAssets() before creating pages.")}createContextProxy(){return new Proxy(this,{get:u(function(c,s){return c.getContextMethod(s)},"get")})}setupPageListener(){this.context.on("page",async n=>{try{if(n.isClosed())return;await this.makePage(n)}catch(c){let s=c instanceof Error?c.message:String(c);if(s.includes("Page has already been closed")||s.includes("Target page, context or browser has been closed"))return;throw console.error("[ChecksumBrowserContext] Failed to initialize page created by application:",c),c}})}getPageGuid(n){let c=this.pageGuidMap.get(n);return c||(c=`page@checksumctx_${this.instanceId}_${++i.guidCounter}`,this.pageGuidMap.set(n,c)),c}getPageByGuid(n){return this._pages[n]}getAllPages(){return Object.values(this._pages)}getContextMethod(n){if(n in this){let s=lre(this,n);return typeof s=="function"?s.bind(this):s}let c=lre(this.context,n);return typeof c=="function"?c.bind(this.context):c}pages(){return this.getAllPages()}getPage(n){let c=this.getAllPages(),s=c[n];if(!s)throw new Error(`Page with index ${n} not found. Total pages: ${c.length}`);return s}};var jM={},fre=u((i,n,c={},s=!1)=>{let{environments:r}=n,f=r?.find(d=>d.default),p=i.extend({baseURL:f?.baseURL,bypassCSP:!0,permissions:u(async({},d,h)=>{await d(h.project.use.permissions)},"permissions"),proxy:u(async({proxy:d},h)=>{d?await h({...d,bypass:"127.0.0.1,localhost"}):await h(d)},"proxy"),browser:u(async({browser:d,launchOptions:h},o,a)=>{let e=u(()=>(a.project.use.playwrightExtra||[]).some(g=>g.constructor.name==="StealthPlugin"),"checkIfStealthPluginExists"),t=u(async()=>{let g=await(await new Bw({project:a.project}).buildChromiumWithPlugins()).launch(h);await o(g)},"launchBrowserWithStealthPlugin");Fe.useRemoteDebugging.enabled&&e()?await t():await o(d)},"browser"),launchOptions:u(async({launchOptions:d},h)=>{let o=d.args?[...d.args]:[],a=u(e=>{o.includes(e)||o.push(e)},"pushArg");c.useMockData&&a("--disable-web-security"),Fe.bypassProxyForLocalhost&&a("--proxy-bypass-list=localhost,127.0.0.1"),Fe.useRemoteDebugging.enabled&&a(`--remote-debugging-port=${Fe.useRemoteDebugging.port}`),await h({...d,args:o})},"launchOptions"),variableStore:u(async({},d)=>{let h=new Jf;await d(h)},"variableStore"),vs:u(async({variableStore:d},h)=>{await h(d)},"vs"),variablesStore:u(async({variableStore:d},h)=>{await h(d)},"variablesStore"),testRunAnalytics:u(async({},d,h)=>{let o=(()=>{try{if(process.env.CHECKSUM_TEST_SUITE_INFO)return JSON.parse(process.env.CHECKSUM_TEST_SUITE_INFO);throw new Error("Missing Checksum test suite info")}catch{return console.warn("\u26A0\uFE0F Warning: It seems like you ran the test suite directly via Playwright. This can lead to degraded functionality and unexpected issues. To ensure a fully supported and stable test run, please use: 'npx checksumai test'."),cre("playwright-run-version-unknown",(0,ure.randomUUID)())}})(),a=sre(h)??"",e=Xo.getTestRunInstance({...o,checksumTestId:a},process.env.CHECKSUM_ISOLATED_MODE==="true",h);await d(e)},"testRunAnalytics"),monitorBridge:[async({},d,h)=>{let o=new Pw(h);await d(o)},{scope:"worker"}],context:u(async({context:d,monitorBridge:h,variableStore:o,testRunAnalytics:a},e,t)=>{let l=Rw.makeContext(d);l.setTestAssets({testRunAnalytics:a,monitorBridge:h,variableStore:o,testInfo:t,checksumTestId:sre(t),test:p,config:n,isReplMode:s}),await e(l),l.cleanup()},"context"),page:u(async({page:d,context:h},o,a)=>{let e=await h.makePage(d);Object.defineProperty(e.constructor,"name",{value:"Page"}),await o(e),e&&typeof e.onTestComplete=="function"&&await e.onTestComplete(a.status==="passed"),e&&typeof e.shutdown=="function"&&await e.shutdown()},"page")});return{test:p,defineChecksumTest:u3e}},"createChecksumTestExtension"),u3e=u((i,n,c)=>{let r=(new Error().stack?.split(`
|
|
419
|
-
`)??[]).find(f=>f.includes(".checksum.spec.ts"));if(!r)throw new Error("Could not locate test location. Make sure test is run from valid checksum test file");return jM[r]=n,i},"defineChecksumTest");function sre(i){let{file:n,line:c}=i,s=Object.keys(jM).filter(f=>f.trim().includes(n.trim()));if(!s.length)return;let r=4;for(let f=0;f<r;f++)for(let p of s){let d;try{d=parseInt(p.split(":").reverse()[1]??"")}catch{continue}if(d-f===c)return jM[p]}}u(sre,"getCurrentTestIdFromMapping");var mRt=require("@playwright/test");var cRt=require("@playwright/test");var f3e=["toMatchSnapshot"],d3e=["toBe","toBeCloseTo","toBeDefined","toBeFalsy","toBeGreaterThan","toBeGreaterThanOrEqual","toBeInstanceOf","toBeLessThan","toBeLessThanOrEqual","toBeNaN","toBeNull","toBeTruthy","toBeUndefined","toContain","toContainEqual","toEqual","toHaveLength","toHaveProperty","toMatch","toMatchObject","toStrictEqual","toThrow","toThrowError"],dre=[...d3e,...f3e];var Dw=class{constructor(n,c,s=!1,r=!1,f={}){this.page=n;this.soft=s;this.skipAutoRecovery=r;this.configuration=f;this.fallbackEnabled=!1;this.withChecksumAI=!1;this.withChecksumAIMatcher=u(()=>(this.withChecksumAI=!0,Promise.reject(new Error)),"withChecksumAIMatcher");this.setThought(c)}static{u(this,"ExpectCallProxyHandler")}setThought(n){n&&(this.checksumAIThought=this.page.addNewThought(n,"assertion"),this.useChecksumAIOptions=this.page.getRuntimeOptions().useChecksumAI,this.useChecksumAIOptions.assertions&&(this.page.setAIFallback(n,"assertion"),this.fallbackEnabled=!0))}get(n,c,s){if(typeof c!="string")return Reflect.get(n,c);if(c==="checksumAI")return f=>(this.setThought(f),s);if(c==="withChecksumAI"||typeof Reflect.get(n,c)=="function"){let f=c==="withChecksumAI"?this.withChecksumAIMatcher:Reflect.get(n,c);return(...p)=>dre.includes(c)?f.call(n,...p):this.checksumAIThought?this.executeMatcherWithinStep(f,n,...p):this.executeMatcher(f,n,...p)}let r=Reflect.get(n,c);return new Proxy(r,this)}findNestedErrors(n,c){n.error&&n.infectParentStepsWithError&&c.push(n.error);for(let s of n.steps)this.findNestedErrors(s,c)}async callMatcher(n,c,...s){this.beforeMatcherCall();let r=n.call(c,...s),f=r instanceof Promise?await r:r;if(this.step){let p=[];if(this.step.error?p.push(this.step.error):this.findNestedErrors(this.step,p),p.length)throw p[0]}return f}executeMatcherWithinStep(n,c,...s){let r=this.checksumAIThought;if(!r)throw new Error("ExpectCallProxyHandler: checksumAIThought is not set");return this.page.step(r.thought,()=>this.callMatcher(n,c,...s).catch(this.onMatcherFailure.bind(this)),!1,{obtainStep:u(f=>this.step=f,"obtainStep")}).catch(f=>{if(!this.soft&&!(this.withChecksumAI&&f.message===sc))throw f}).finally(this.afterMatcherExecute.bind(this))}async executeMatcher(n,c,...s){try{return await this.callMatcher(n,c,...s)}catch(r){await this.onMatcherFailure(r);return}finally{this.afterMatcherExecute()}}beforeMatcherCall(){this.page.setExpectConfiguration(this.configuration)}afterMatcherExecute(){this.checksumAIThought=void 0,this.fallbackEnabled=!1,this.withChecksumAI=!1,this.page.resetFallbacks(),this.page.setExpectConfiguration(void 0)}shouldInitiateFallback(n){return!(!this.fallbackEnabled||Reflect.get(n,"matcherResult")?.name==="toHaveScreenshot"&&!this.useChecksumAIOptions?.visualComparison)}async onMatcherFailure(n){if(!this.shouldInitiateFallback(n))throw ye("[onMatcherFailure] fallback disabled, continuing with error."),this.page.testRunAnalytics.testRunAssertionExecutionFailure({failedThought:this.checksumAIThought?.thought??"",error:n.message,matcher:n.matcherResult?.name}),n;if(Bm()){if(ye("[onMatcherFailure] assertion failed inside a locator handler, skipping fallback"),this.soft)return;throw n}if(ye("[onMatcherFailure] initiating fallback sequence with thought:",this.checksumAIThought?.thought),this.skipAutoRecovery){if(this.soft)return;throw n}try{await this.page.initiateFallbackSequence({type:"assertion",error:n,withChecksumAI:this.withChecksumAI,testInfo:this.page.testInfo})}catch(c){if(this.soft)return;throw c}throw this.soft=!0,n}};var Nw=class i{constructor(n,c={}){this.page=n;this.configuration=c}static{u(this,"ExpectProxyHandler")}get(n,c){if(c==="setPage")return r=>{this.page=r};if(c==="extend")return(...r)=>{let f=n.extend(...r);return new Proxy(f,this)};if(c==="configure")return r=>{let f=n.configure(r);return new Proxy(f,new i(this.page,{...this.configuration,...r}))};if(c==="soft")return(...r)=>{let f=this.manipulateArgsAndExtractThought(r),p=n.soft(...r);return new Proxy(p,this.makeExpectCallProxyHandler(f,!0))};if(c==="poll")return(...r)=>{let f=this.manipulateArgsAndExtractThought(r),p=n.poll(...r);return new Proxy(p,this.makeExpectCallProxyHandler(f))};if(c==="skipAutoRecovery")return new Proxy(()=>{},{apply:u((f,p,d)=>{let h=this.manipulateArgsAndExtractThought(d),o=n.apply(p,d);return new Proxy(o,this.makeExpectCallProxyHandler(h,void 0,!0))},"apply"),get:u((f,p)=>{let d=new Proxy(n,new i(this.page,{...this.configuration,skipAutoRecovery:!0}));return Reflect.get(d,p)},"get")});let s=Reflect.get(n,c);return s instanceof Function?s.bind(n):s}apply(n,c,s){let r=this.manipulateArgsAndExtractThought(s),f=n.apply(c,s);return new Proxy(f,this.makeExpectCallProxyHandler(r))}makeExpectCallProxyHandler(n,c,s){if(!this.page)throw new Error("ExpectProxyHandler: page is not set");return new Dw(this.page,n,c===!0?!0:this.configuration.soft,s===!0?!0:this.configuration.skipAutoRecovery,this.configuration)}manipulateArgsAndExtractThought(n){let c,s=n[1];if(typeof s=="string")c=s,n[1]=void 0;else if(s!==null&&typeof s=="object"){let r=s;if(r.checksumAI===!1){r.checksumAI=void 0;return}r.checksumAI&&typeof r.checksumAI=="string"?(c=r.checksumAI,r.checksumAI=void 0):r.message&&(c=r.message,r.message=void 0)}return c}};var Lw=class i{constructor(n){this.expect=n;
|
|
419
|
+
`)??[]).find(f=>f.includes(".checksum.spec.ts"));if(!r)throw new Error("Could not locate test location. Make sure test is run from valid checksum test file");return jM[r]=n,i},"defineChecksumTest");function sre(i){let{file:n,line:c}=i,s=Object.keys(jM).filter(f=>f.trim().includes(n.trim()));if(!s.length)return;let r=4;for(let f=0;f<r;f++)for(let p of s){let d;try{d=parseInt(p.split(":").reverse()[1]??"")}catch{continue}if(d-f===c)return jM[p]}}u(sre,"getCurrentTestIdFromMapping");var mRt=require("@playwright/test");var cRt=require("@playwright/test");var f3e=["toMatchSnapshot"],d3e=["toBe","toBeCloseTo","toBeDefined","toBeFalsy","toBeGreaterThan","toBeGreaterThanOrEqual","toBeInstanceOf","toBeLessThan","toBeLessThanOrEqual","toBeNaN","toBeNull","toBeTruthy","toBeUndefined","toContain","toContainEqual","toEqual","toHaveLength","toHaveProperty","toMatch","toMatchObject","toStrictEqual","toThrow","toThrowError"],dre=[...d3e,...f3e];var Dw=class{constructor(n,c,s=!1,r=!1,f={}){this.page=n;this.soft=s;this.skipAutoRecovery=r;this.configuration=f;this.fallbackEnabled=!1;this.withChecksumAI=!1;this.withChecksumAIMatcher=u(()=>(this.withChecksumAI=!0,Promise.reject(new Error)),"withChecksumAIMatcher");this.setThought(c)}static{u(this,"ExpectCallProxyHandler")}setThought(n){n&&(this.checksumAIThought=this.page.addNewThought(n,"assertion"),this.useChecksumAIOptions=this.page.getRuntimeOptions().useChecksumAI,this.useChecksumAIOptions.assertions&&(this.page.setAIFallback(n,"assertion"),this.fallbackEnabled=!0))}get(n,c,s){if(typeof c!="string")return Reflect.get(n,c);if(c==="checksumAI")return f=>(this.setThought(f),s);if(c==="withChecksumAI"||typeof Reflect.get(n,c)=="function"){let f=c==="withChecksumAI"?this.withChecksumAIMatcher:Reflect.get(n,c);return(...p)=>dre.includes(c)?f.call(n,...p):this.checksumAIThought?this.executeMatcherWithinStep(f,n,...p):this.executeMatcher(f,n,...p)}let r=Reflect.get(n,c);return new Proxy(r,this)}findNestedErrors(n,c){n.error&&n.infectParentStepsWithError&&c.push(n.error);for(let s of n.steps)this.findNestedErrors(s,c)}async callMatcher(n,c,...s){this.beforeMatcherCall();let r=n.call(c,...s),f=r instanceof Promise?await r:r;if(this.step){let p=[];if(this.step.error?p.push(this.step.error):this.findNestedErrors(this.step,p),p.length)throw p[0]}return f}executeMatcherWithinStep(n,c,...s){let r=this.checksumAIThought;if(!r)throw new Error("ExpectCallProxyHandler: checksumAIThought is not set");return this.page.step(r.thought,()=>this.callMatcher(n,c,...s).catch(this.onMatcherFailure.bind(this)),!1,{obtainStep:u(f=>this.step=f,"obtainStep")}).catch(f=>{if(!this.soft&&!(this.withChecksumAI&&f.message===sc))throw f}).finally(this.afterMatcherExecute.bind(this))}async executeMatcher(n,c,...s){try{return await this.callMatcher(n,c,...s)}catch(r){await this.onMatcherFailure(r);return}finally{this.afterMatcherExecute()}}beforeMatcherCall(){this.page.setExpectConfiguration(this.configuration)}afterMatcherExecute(){this.checksumAIThought=void 0,this.fallbackEnabled=!1,this.withChecksumAI=!1,this.page.resetFallbacks(),this.page.setExpectConfiguration(void 0)}shouldInitiateFallback(n){return!(!this.fallbackEnabled||Reflect.get(n,"matcherResult")?.name==="toHaveScreenshot"&&!this.useChecksumAIOptions?.visualComparison)}async onMatcherFailure(n){if(!this.shouldInitiateFallback(n))throw ye("[onMatcherFailure] fallback disabled, continuing with error."),this.page.testRunAnalytics.testRunAssertionExecutionFailure({failedThought:this.checksumAIThought?.thought??"",error:n.message,matcher:n.matcherResult?.name}),n;if(Bm()){if(ye("[onMatcherFailure] assertion failed inside a locator handler, skipping fallback"),this.soft)return;throw n}if(ye("[onMatcherFailure] initiating fallback sequence with thought:",this.checksumAIThought?.thought),this.skipAutoRecovery){if(this.soft)return;throw n}try{await this.page.initiateFallbackSequence({type:"assertion",error:n,withChecksumAI:this.withChecksumAI,testInfo:this.page.testInfo})}catch(c){if(this.soft)return;throw c}throw this.soft=!0,n}};var Nw=class i{constructor(n,c={}){this.page=n;this.configuration=c}static{u(this,"ExpectProxyHandler")}get(n,c){if(c==="setPage")return r=>{this.page=r};if(c==="extend")return(...r)=>{let f=n.extend(...r);return new Proxy(f,this)};if(c==="configure")return r=>{let f=n.configure(r);return new Proxy(f,new i(this.page,{...this.configuration,...r}))};if(c==="soft")return(...r)=>{let f=this.manipulateArgsAndExtractThought(r),p=n.soft(...r);return new Proxy(p,this.makeExpectCallProxyHandler(f,!0))};if(c==="poll")return(...r)=>{let f=this.manipulateArgsAndExtractThought(r),p=n.poll(...r);return new Proxy(p,this.makeExpectCallProxyHandler(f))};if(c==="skipAutoRecovery")return new Proxy(()=>{},{apply:u((f,p,d)=>{let h=this.manipulateArgsAndExtractThought(d),o=n.apply(p,d);return new Proxy(o,this.makeExpectCallProxyHandler(h,void 0,!0))},"apply"),get:u((f,p)=>{let d=new Proxy(n,new i(this.page,{...this.configuration,skipAutoRecovery:!0}));return Reflect.get(d,p)},"get")});let s=Reflect.get(n,c);return s instanceof Function?s.bind(n):s}apply(n,c,s){let r=this.manipulateArgsAndExtractThought(s),f=n.apply(c,s);return new Proxy(f,this.makeExpectCallProxyHandler(r))}makeExpectCallProxyHandler(n,c,s){if(!this.page)throw new Error("ExpectProxyHandler: page is not set");return new Dw(this.page,n,c===!0?!0:this.configuration.soft,s===!0?!0:this.configuration.skipAutoRecovery,this.configuration)}manipulateArgsAndExtractThought(n){let c,s=n[1];if(typeof s=="string")c=s,n[1]=void 0;else if(s!==null&&typeof s=="object"){let r=s;if(r.checksumAI===!1){r.checksumAI=void 0;return}r.checksumAI&&typeof r.checksumAI=="string"?(c=r.checksumAI,r.checksumAI=void 0):r.message&&(c=r.message,r.message=void 0)}return c}};var Lw=class i{constructor(n){this.expect=n;let c=new Proxy(this.expect,new Nw);this.proxy=c}static{u(this,"ChecksumExpect")}static init(n){return new i(n).proxy}};var pre=require("@playwright/test");function p3e(i,n=AI()){let{options:c,apiKey:s,environments:r,defaultEnvironmentName:f}=n,p=r?.find(g=>g.default);if(f&&(p=r?.find(g=>g.name===f)),!p)throw new Error("No default environment found. Please set the default field to true on one of the environments in the checksum.config.ts file.");if(!p.baseURL)throw new Error("A baseURL is required. Please set the baseURL field in the default environment in the checksum.config.ts file.");if(!p.users?.find(g=>g.default))throw new Error("A default user within the default environment is required. Please set one of the default environment users as default in the checksum.config.ts file.");if(!s)throw new Error("An API key is required. Please set the apiKey field in the checksum.config.ts file.");let h=process.env.CHECKSUM_REPL==="true",{test:o,defineChecksumTest:a}=fre(i??pre.test,n,c,h),e=Lw.init(o.expect),t=h3e();o._checksum={expect:e,checksumAI:t},h&&(o.beforeEach(async()=>{o.setTimeout(0)}),o.afterEach(async()=>{for(;;)await ct(1e3)}));let l=u(({name:g,userRole:A})=>{let{envName:y,role:v}=LM({...g!==void 0?{envName:g}:{},...A!==void 0?{role:A}:{}}),{environment:O,user:m}=QM(n,{...y!==void 0?{environment:y}:{},...v!==void 0?{role:v}:{}},!0),k=tre({config:n,throwIfEnvInfoInvalid:!0},{environmentName:O.name,userRole:m.role});return{environment:O,user:m,login:k}},"getEnvironment");return{test:o,expect:e,login:ds({config:n}),defineChecksumTest:a,getEnvironment:l,checksumAI:t}}u(p3e,"init");var HM=u(i=>new Proxy(i,{apply:u(function(c,s,r){let f={...c.options,...r[2]};return c.page.checksumAI(r[0],r[1],f)},"apply"),get:u(function(c,s){return s==="withDialog"?(c.options.withDialog=!0,HM(i)):s==="skipAutoRecovery"?(c.options.skipAutoRecovery=!0,HM(i)):c[s]},"get"),set:u(function(c,s,r){return s!=="page"?!1:(c[s]=r,!!r)},"set")}),"makeChecksumAIProxy"),h3e=u(()=>{let i=u(function(){},"func");return i.page=void 0,i.options={withDialog:!1,skipAutoRecovery:!1},HM(i)},"makeChecksumAI");0&&(module.exports={AutoRecoveryMode,RunMode,getChecksumConfig,getLogin,init});
|
|
420
420
|
/*! Bundled license information:
|
|
421
421
|
|
|
422
422
|
playwright-extra/dist/index.cjs.js:
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Checksum.ai test runtime",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@playwright/test": "1.
|
|
6
|
+
"@playwright/test": "1.62.1",
|
|
7
7
|
"dotenv": "17.4.2",
|
|
8
8
|
"jsdom": "30.0.1",
|
|
9
9
|
"playwright-extra": "4.3.6",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"url": "https://github.com/checksum-ai/checksum-ai-monorepo/issues"
|
|
46
46
|
},
|
|
47
47
|
"homepage": "https://github.com/checksum-ai/checksum-ai-monorepo/tree/main/packages/runtime#readme",
|
|
48
|
-
"version": "4.16.
|
|
48
|
+
"version": "4.16.2-beta.1"
|
|
49
49
|
}
|
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const crypto = require("crypto");
|
|
3
|
+
const { join } = require("path");
|
|
4
|
+
|
|
5
|
+
// Args
|
|
6
|
+
const on = process.argv[2] !== "off";
|
|
7
|
+
|
|
8
|
+
// -------- [Modifiers] -------- //
|
|
9
|
+
|
|
10
|
+
// Amends the file with the given entry point text and append text
|
|
11
|
+
// When "on" is true, the append text is added to the entry point,
|
|
12
|
+
// otherwise the append text is completely removed from the file
|
|
13
|
+
function amend(filePath, entryPointText, appendText) {
|
|
14
|
+
const data = fs.readFileSync(filePath, "utf8");
|
|
15
|
+
if (!data.includes(entryPointText)) {
|
|
16
|
+
throw new Error("Entry point not found!", entryPointText);
|
|
17
|
+
}
|
|
18
|
+
// Ignore if the append text is already present
|
|
19
|
+
if (on && data.includes(appendText)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Add or clear according to on state
|
|
23
|
+
const result = on
|
|
24
|
+
? data.replace(entryPointText, entryPointText + appendText)
|
|
25
|
+
: data.replace(appendText, "");
|
|
26
|
+
|
|
27
|
+
// Write
|
|
28
|
+
fs.writeFileSync(filePath, result, "utf8");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Bracket each injected block with a per-patch unique marker derived from a
|
|
32
|
+
// hash of `originalContent`. This guarantees OFF mode reverts only the patch
|
|
33
|
+
// that produced the marker, instead of accidentally matching another patch's
|
|
34
|
+
// shared `/* checksumai */ ` prefix (which previously caused
|
|
35
|
+
// `alwaysInjectScripts` OFF — whose newContent collapses to the bare marker —
|
|
36
|
+
// to clobber the FIRST `/* checksumai */ ` it found, corrupting whichever
|
|
37
|
+
// patch happened to live at the lowest line number).
|
|
38
|
+
//
|
|
39
|
+
// Backward-compat for the legacy single-marker format: in OFF mode, if the
|
|
40
|
+
// new bracketed form is not present but the legacy `/* checksumai */ <body>`
|
|
41
|
+
// form is, revert that and exit. New ON installs always write the bracketed
|
|
42
|
+
// form.
|
|
43
|
+
function replaceContent(filePath, originalContent, newContent) {
|
|
44
|
+
const fileContent = fs.readFileSync(filePath, "utf8");
|
|
45
|
+
|
|
46
|
+
const id = crypto
|
|
47
|
+
.createHash("sha1")
|
|
48
|
+
.update(originalContent)
|
|
49
|
+
.digest("hex")
|
|
50
|
+
.slice(0, 8);
|
|
51
|
+
const openMarker = `/*checksumai:${id}*/`;
|
|
52
|
+
const closeMarker = `/*checksumai:end:${id}*/`;
|
|
53
|
+
const taggedNewContent = `${openMarker}${newContent}${closeMarker}`;
|
|
54
|
+
|
|
55
|
+
if (on) {
|
|
56
|
+
if (fileContent.includes(taggedNewContent)) {
|
|
57
|
+
// Already patched.
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (!fileContent.includes(originalContent)) {
|
|
61
|
+
// Nothing to replace. Either already migrated to a different shape or
|
|
62
|
+
// the playwright internals changed and this patch needs updating.
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
fs.writeFileSync(
|
|
66
|
+
filePath,
|
|
67
|
+
fileContent.replace(originalContent, taggedNewContent),
|
|
68
|
+
"utf8"
|
|
69
|
+
);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// OFF: precise revert via the unique bracketed block.
|
|
74
|
+
if (fileContent.includes(taggedNewContent)) {
|
|
75
|
+
fs.writeFileSync(
|
|
76
|
+
filePath,
|
|
77
|
+
fileContent.replace(taggedNewContent, originalContent),
|
|
78
|
+
"utf8"
|
|
79
|
+
);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// OFF (legacy): older patched files used `/* checksumai */ ${newContent}`
|
|
84
|
+
// with a shared marker. Revert that exact body if present so users coming
|
|
85
|
+
// from a previous runtime version aren't stranded with stale injections.
|
|
86
|
+
const legacyTagged = `/* checksumai */ ${newContent}`;
|
|
87
|
+
if (fileContent.includes(legacyTagged)) {
|
|
88
|
+
fs.writeFileSync(
|
|
89
|
+
filePath,
|
|
90
|
+
fileContent.replace(legacyTagged, originalContent),
|
|
91
|
+
"utf8"
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function doesFileExist(filePath) {
|
|
97
|
+
if (!fs.existsSync(filePath)) {
|
|
98
|
+
console.warn("File not found", filePath);
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// -------- [Modifications] -------- //
|
|
105
|
+
|
|
106
|
+
// File targets are unchanged from 1.60 (the big lib/ -> esbuild-bundle
|
|
107
|
+
// collapse landed there):
|
|
108
|
+
// playwright-core/lib/coreBundle.js
|
|
109
|
+
// playwright/lib/worker/workerProcessEntry.js
|
|
110
|
+
// playwright/lib/common/index.js
|
|
111
|
+
// playwright/lib/index.js
|
|
112
|
+
// playwright/lib/runner/index.js
|
|
113
|
+
//
|
|
114
|
+
// 1.60 -> 1.62 moved three anchors:
|
|
115
|
+
// - `_wrapApiCall(func, options2)` -> `_wrapApiCall(func, options)`; the
|
|
116
|
+
// esbuild dedup suffix on `options` disappeared, so every `options2`
|
|
117
|
+
// reference in the channelOwner patch reverts to `options`.
|
|
118
|
+
// - `_failWithError(error)` -> `_failWithError(root)`; the method now walks
|
|
119
|
+
// an error tree via a local `visit()`.
|
|
120
|
+
// - Inside workerProcessEntry the helpers are no longer namespaced imports:
|
|
121
|
+
// `(0, import_util2.testInfoError)` -> `testInfoError` and
|
|
122
|
+
// `(0, import_utils.stringifyStackFrames)` -> `stringifyStackFrames2`.
|
|
123
|
+
// `import_fs5`, `toPosixPath2` and `import_path8` in runner/index.js kept
|
|
124
|
+
// their 1.60 suffixes — but these are build-pipeline artifacts, so re-validate
|
|
125
|
+
// every anchor on each upgrade rather than assuming the previous patch applies.
|
|
126
|
+
|
|
127
|
+
// Remove conditions for injecting Playwright scripts
|
|
128
|
+
function alwaysInjectScripts(projectRoot) {
|
|
129
|
+
const file = join(
|
|
130
|
+
projectRoot,
|
|
131
|
+
"node_modules/playwright-core/lib/coreBundle.js"
|
|
132
|
+
);
|
|
133
|
+
if (!doesFileExist(file)) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const originalContent = 'if (debugMode() === "console")';
|
|
138
|
+
|
|
139
|
+
const newContent = "";
|
|
140
|
+
|
|
141
|
+
replaceContent(file, originalContent, newContent);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Add implementation for generateSelectorAndLocator and inject to Playwright console API
|
|
145
|
+
function addGenerateSelectorAndLocator(projectRoot) {
|
|
146
|
+
const file = join(
|
|
147
|
+
projectRoot,
|
|
148
|
+
"node_modules/playwright-core/lib/coreBundle.js"
|
|
149
|
+
);
|
|
150
|
+
if (!doesFileExist(file)) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const entryPointText1 = "this._generateLocator(element, language),\\n ";
|
|
154
|
+
const appendText1 =
|
|
155
|
+
"generateSelectorAndLocator: (element, language) => this._generateSelectorAndLocator(element, language),\\n asLocator,\\n ";
|
|
156
|
+
amend(file, entryPointText1, appendText1);
|
|
157
|
+
|
|
158
|
+
const entryPointText2 = `return asLocator(language || "javascript", selector);\\n }\\n `;
|
|
159
|
+
const appendText2 =
|
|
160
|
+
'_generateSelectorAndLocator(element, language) {\\n if (!(element instanceof Element))\\n throw new Error(`Usage: playwright.locator(element).`);\\n const selector = this._injectedScript.generateSelectorSimple(element);\\n return {selector, locator: asLocator(language || \\"javascript\\", selector)};\\n }\\n ';
|
|
161
|
+
amend(file, entryPointText2, appendText2);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// -------- [Runtime modifications] -------- //
|
|
165
|
+
|
|
166
|
+
function expect(projectRoot) {
|
|
167
|
+
const file = join(
|
|
168
|
+
projectRoot,
|
|
169
|
+
"node_modules/playwright/lib/matchers/expect.js"
|
|
170
|
+
);
|
|
171
|
+
if (!doesFileExist(file)) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
let originalContent, newContent;
|
|
175
|
+
|
|
176
|
+
// originalContent = `return (...args) => {
|
|
177
|
+
// const testInfo = (0, _globals.currentTestInfo)();`;
|
|
178
|
+
// newContent = `return (...args) => {
|
|
179
|
+
// let noSoft = false;
|
|
180
|
+
// if (args.find(arg=>arg==='no-soft')){
|
|
181
|
+
// noSoft = true;
|
|
182
|
+
// args.pop();
|
|
183
|
+
// }
|
|
184
|
+
// const testInfo = (0, _globals.currentTestInfo)();`;
|
|
185
|
+
// replaceContent(file, originalContent, newContent);
|
|
186
|
+
|
|
187
|
+
// originalContent = `step.complete({
|
|
188
|
+
// error
|
|
189
|
+
// })`;
|
|
190
|
+
// newContent = `step.complete({
|
|
191
|
+
// error,
|
|
192
|
+
// noSoft
|
|
193
|
+
// })`;
|
|
194
|
+
// replaceContent(file, originalContent, newContent);
|
|
195
|
+
|
|
196
|
+
// originalContent = `if (this._info.isSoft) testInfo._failWithError(error);else throw error;`;
|
|
197
|
+
// newContent = `if (this._info.isSoft && !noSoft) testInfo._failWithError(error);else throw error;`;
|
|
198
|
+
// replaceContent(file, originalContent, newContent);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function testInfo(projectRoot) {
|
|
202
|
+
const file = join(
|
|
203
|
+
projectRoot,
|
|
204
|
+
"node_modules/playwright/lib/worker/workerProcessEntry.js"
|
|
205
|
+
);
|
|
206
|
+
if (!doesFileExist(file)) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
let originalContent, newContent;
|
|
210
|
+
let entryPointText, appendText;
|
|
211
|
+
|
|
212
|
+
// originalContent = `const filteredStack = (0, _util.filteredStackTrace)((0, _utils.captureRawStack)());`;
|
|
213
|
+
// newContent = `const filteredStack = (0, _util.filteredStackTrace)((0, _utils.captureRawStack)().filter(s=>!s.includes('@checksum-ai/runtime')));`;
|
|
214
|
+
// replaceContent(file, originalContent, newContent);
|
|
215
|
+
|
|
216
|
+
entryPointText = `location = location || filteredStack[0];`;
|
|
217
|
+
appendText = `\nif (this._checksumInternal) {
|
|
218
|
+
location = undefined;
|
|
219
|
+
this._checksumInternal = false;
|
|
220
|
+
}
|
|
221
|
+
if (this._checksumNoLocation){
|
|
222
|
+
location = undefined;
|
|
223
|
+
}`;
|
|
224
|
+
amend(file, entryPointText, appendText);
|
|
225
|
+
|
|
226
|
+
originalContent = `if (childStep.error && childStep.infectParentStepsWithError) {`;
|
|
227
|
+
newContent = `if (childStep.error && childStep.infectParentStepsWithError && !step.preventInfectParentStepsWithError) {`;
|
|
228
|
+
replaceContent(file, originalContent, newContent);
|
|
229
|
+
|
|
230
|
+
originalContent = `_failWithError(root) {`;
|
|
231
|
+
newContent = `addError(error, message) {
|
|
232
|
+
const serialized = testInfoError(error);
|
|
233
|
+
serialized.message = [message, serialized.message].join('\\n\\n');
|
|
234
|
+
serialized.stack = [message, serialized.stack].join('\\n\\n');
|
|
235
|
+
const step = error[stepSymbol];
|
|
236
|
+
if (step && step.boxedStack) serialized.stack = \`\${error.name}: \${error.message}\\n\${stringifyStackFrames2(step.boxedStack).join('\\n')}\`;
|
|
237
|
+
this.errors.push(serialized);
|
|
238
|
+
}
|
|
239
|
+
_failWithError(root) {`;
|
|
240
|
+
replaceContent(file, originalContent, newContent);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function testType(projectRoot) {
|
|
244
|
+
const file = join(projectRoot, "node_modules/playwright/lib/common/index.js");
|
|
245
|
+
if (!doesFileExist(file)) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
entryPointText = `return await currentZone().with("stepZone", step).run(async () => {`;
|
|
250
|
+
appendText = `\nif (options.obtainStep){
|
|
251
|
+
options.obtainStep(step);
|
|
252
|
+
}`;
|
|
253
|
+
amend(file, entryPointText, appendText);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function indexContent(projectRoot) {
|
|
257
|
+
const file = join(projectRoot, "node_modules/playwright/lib/index.js");
|
|
258
|
+
if (!doesFileExist(file)) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
let originalContent, newContent;
|
|
262
|
+
originalContent = `const browser = await playwright[browserName].launch();`;
|
|
263
|
+
newContent = `
|
|
264
|
+
let browser = playwright[browserName];
|
|
265
|
+
try {
|
|
266
|
+
const { playwrightExtra } = workerInfo?.project?.use || {};
|
|
267
|
+
if (playwrightExtra && playwrightExtra?.length) {
|
|
268
|
+
const pw = require("playwright-extra")
|
|
269
|
+
const PupeteerExtraPlugin = require("puppeteer-extra-plugin").PuppeteerExtraPlugin
|
|
270
|
+
const chromium = pw.chromium;
|
|
271
|
+
|
|
272
|
+
playwrightExtra.forEach((plugin, i) => {
|
|
273
|
+
try {
|
|
274
|
+
if(!(plugin instanceof PupeteerExtraPlugin)){
|
|
275
|
+
console.warn(\`Plugin at index \${i} is not an instance of PupeteerExtraPlugin\`);
|
|
276
|
+
}
|
|
277
|
+
chromium.use(plugin);
|
|
278
|
+
} catch (e) {
|
|
279
|
+
console.warn(e);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
browser = chromium;
|
|
283
|
+
}
|
|
284
|
+
} catch (e) {
|
|
285
|
+
console.warn(
|
|
286
|
+
"CHECKSUM: Failed to load Playwright Extra, using Playwright instead.",
|
|
287
|
+
e
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
browser = await browser.launch();
|
|
291
|
+
`;
|
|
292
|
+
replaceContent(file, originalContent, newContent);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function channelOwner(projectRoot) {
|
|
296
|
+
const file = join(
|
|
297
|
+
projectRoot,
|
|
298
|
+
"node_modules/playwright-core/lib/coreBundle.js"
|
|
299
|
+
);
|
|
300
|
+
if (!doesFileExist(file)) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
let originalContent, newContent;
|
|
304
|
+
let entryPointText, appendText;
|
|
305
|
+
|
|
306
|
+
entryPointText = `async _wrapApiCall(func, options) {`;
|
|
307
|
+
|
|
308
|
+
appendText = `\nif (this._checksumInternal){
|
|
309
|
+
options = options || {};
|
|
310
|
+
options.internal = true;
|
|
311
|
+
}`;
|
|
312
|
+
amend(file, entryPointText, appendText);
|
|
313
|
+
|
|
314
|
+
entryPointText = `const apiZone = { title: options?.title, apiName: stackTrace.apiName, frames: stackTrace.frames, internal: options?.internal ?? false, reported: false, userData: void 0, stepId: void 0 };`;
|
|
315
|
+
|
|
316
|
+
appendText = `\nif (!apiZone.internal && this._checksumTitle){
|
|
317
|
+
apiZone.apiName = this._checksumTitle;
|
|
318
|
+
this._checksumTitle = undefined;
|
|
319
|
+
}
|
|
320
|
+
if (!apiZone.apiName){
|
|
321
|
+
options = options || {};
|
|
322
|
+
options.internal = true;
|
|
323
|
+
apiZone.internal = true;
|
|
324
|
+
apiZone.reported = true;
|
|
325
|
+
}
|
|
326
|
+
if (apiZone.apiName && apiZone.apiName.startsWith('proxy')) {
|
|
327
|
+
apiZone.apiName = apiZone.apiName.replace('proxy', 'page');
|
|
328
|
+
}`;
|
|
329
|
+
amend(file, entryPointText, appendText);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function stackTrace(projectRoot) {
|
|
333
|
+
const file = join(
|
|
334
|
+
projectRoot,
|
|
335
|
+
"node_modules/playwright-core/lib/coreBundle.js"
|
|
336
|
+
);
|
|
337
|
+
if (!doesFileExist(file)) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
let originalContent, newContent;
|
|
342
|
+
|
|
343
|
+
// Create a regex for getting a file for each line in the stacktrace that overrides the original regex
|
|
344
|
+
// This regex is only used for getting files, the original regex is sitll used for the rest of the content
|
|
345
|
+
originalContent = `let file = match[7];`;
|
|
346
|
+
const fileRe = /(\/.*?\.[a-zA-Z0-9]+)(?=:\d+:\d+)/;
|
|
347
|
+
newContent = `
|
|
348
|
+
const fileRe = new RegExp(${JSON.stringify(fileRe.source)}, "${
|
|
349
|
+
fileRe.flags
|
|
350
|
+
}");
|
|
351
|
+
const m = fileRe.exec(match[0] ?? "");
|
|
352
|
+
let file = m ? m[1] : undefined;
|
|
353
|
+
`;
|
|
354
|
+
replaceContent(file, originalContent, newContent);
|
|
355
|
+
|
|
356
|
+
// Filter out checksum-ai/runtime from stack traces
|
|
357
|
+
originalContent = `return stack.split("\\n");`;
|
|
358
|
+
newContent = `return stack.split("\\n").filter(s=>!s.includes('@checksum-ai/runtime'));`;
|
|
359
|
+
replaceContent(file, originalContent, newContent);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function reportTraceFile(projectRoot) {
|
|
363
|
+
const file = join(projectRoot, "node_modules/playwright/lib/runner/index.js");
|
|
364
|
+
if (!doesFileExist(file)) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
let originalContent, newContent;
|
|
369
|
+
|
|
370
|
+
originalContent = `const buffer = import_fs5.default.readFileSync(a.path);`;
|
|
371
|
+
newContent = `let buffer = import_fs5.default.readFileSync(a.path);
|
|
372
|
+
if (a.name === "trace") {
|
|
373
|
+
let retries = 2;
|
|
374
|
+
while (!buffer.slice(0,100).toString().startsWith("checksum-playwright-trace") && retries > 0) {
|
|
375
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 5000);
|
|
376
|
+
buffer = import_fs5.default.readFileSync(a.path)
|
|
377
|
+
retries--;
|
|
378
|
+
}
|
|
379
|
+
}`;
|
|
380
|
+
replaceContent(file, originalContent, newContent);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function htmlReporter(projectRoot) {
|
|
384
|
+
const file = join(projectRoot, "node_modules/playwright/lib/runner/index.js");
|
|
385
|
+
if (!doesFileExist(file)) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
let originalContent, newContent;
|
|
390
|
+
|
|
391
|
+
// Filter out runtime files from snippet generation
|
|
392
|
+
originalContent = `function createSnippets(stepsInFile) {
|
|
393
|
+
for (const file of stepsInFile.keys()) {
|
|
394
|
+
let source;
|
|
395
|
+
try {
|
|
396
|
+
source = import_fs5.default.readFileSync(file, "utf-8") + "\\n//";
|
|
397
|
+
} catch (e) {
|
|
398
|
+
continue;
|
|
399
|
+
}`;
|
|
400
|
+
newContent = `function createSnippets(stepsInFile) {
|
|
401
|
+
for (const file of stepsInFile.keys()) {
|
|
402
|
+
// Skip runtime files to reduce report size
|
|
403
|
+
if (file.includes('@checksum-ai/runtime') || file.includes('node_modules')) {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
let source;
|
|
407
|
+
try {
|
|
408
|
+
source = import_fs5.default.readFileSync(file, "utf-8") + "\\n//";
|
|
409
|
+
} catch (e) {
|
|
410
|
+
continue;
|
|
411
|
+
}`;
|
|
412
|
+
replaceContent(file, originalContent, newContent);
|
|
413
|
+
|
|
414
|
+
// Also filter from error codeframe generation
|
|
415
|
+
originalContent = `function createErrorCodeframe(message, location) {
|
|
416
|
+
let source;
|
|
417
|
+
try {
|
|
418
|
+
source = import_fs5.default.readFileSync(location.file, "utf-8") + "\\n//";
|
|
419
|
+
} catch (e) {
|
|
420
|
+
return;
|
|
421
|
+
}`;
|
|
422
|
+
newContent = `function createErrorCodeframe(message, location) {
|
|
423
|
+
// Skip runtime files to reduce report size
|
|
424
|
+
if (location.file && (location.file.includes('@checksum-ai/runtime') || location.file.includes('node_modules'))) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
let source;
|
|
428
|
+
try {
|
|
429
|
+
source = import_fs5.default.readFileSync(location.file, "utf-8") + "\\n//";
|
|
430
|
+
} catch (e) {
|
|
431
|
+
return;
|
|
432
|
+
}`;
|
|
433
|
+
replaceContent(file, originalContent, newContent);
|
|
434
|
+
|
|
435
|
+
// Filter out steps with locations in runtime/node_modules files completely
|
|
436
|
+
originalContent = `_createTestStep(dedupedStep, result) {
|
|
437
|
+
const { step, duration, count } = dedupedStep;
|
|
438
|
+
const skipped = dedupedStep.step.annotations?.find((a) => a.type === "skip");
|
|
439
|
+
let title = step.title;
|
|
440
|
+
if (skipped)
|
|
441
|
+
title = \`\${title} (skipped\${skipped.description ? ": " + skipped.description : ""})\`;
|
|
442
|
+
const testStep = {
|
|
443
|
+
title,
|
|
444
|
+
startTime: step.startTime.toISOString(),
|
|
445
|
+
duration,
|
|
446
|
+
steps: dedupeSteps(step.steps).map((s) => this._createTestStep(s, result)),
|
|
447
|
+
attachments: step.attachments.map((s) => {
|
|
448
|
+
const index = result.attachments.indexOf(s);
|
|
449
|
+
if (index === -1)
|
|
450
|
+
throw new Error("Unexpected, attachment not found");
|
|
451
|
+
return index;
|
|
452
|
+
}),
|
|
453
|
+
location: this._relativeLocation(step.location),
|
|
454
|
+
error: step.error?.message,
|
|
455
|
+
count,
|
|
456
|
+
skipped: !!skipped
|
|
457
|
+
};
|
|
458
|
+
if (step.location)
|
|
459
|
+
this._stepsInFile.set(step.location.file, testStep);
|
|
460
|
+
return testStep;
|
|
461
|
+
}`;
|
|
462
|
+
newContent = `_createTestStep(dedupedStep, result) {
|
|
463
|
+
const { step, duration, count } = dedupedStep;
|
|
464
|
+
// Skip "Evaluate" steps with locations in runtime/node_modules files
|
|
465
|
+
if (step.location && step.title === "Evaluate" && (step.location.file.includes('@checksum-ai/runtime') || step.location.file.includes('node_modules'))) {
|
|
466
|
+
// Return null to indicate this step should be filtered out
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
const skipped = dedupedStep.step.annotations?.find((a) => a.type === "skip");
|
|
470
|
+
let title = step.title;
|
|
471
|
+
if (skipped)
|
|
472
|
+
title = \`\${title} (skipped\${skipped.description ? ": " + skipped.description : ""})\`;
|
|
473
|
+
const testStep = {
|
|
474
|
+
title,
|
|
475
|
+
startTime: step.startTime.toISOString(),
|
|
476
|
+
duration,
|
|
477
|
+
steps: dedupeSteps(step.steps).map((s) => this._createTestStep(s, result)).filter(s => s !== null),
|
|
478
|
+
attachments: step.attachments.map((s) => {
|
|
479
|
+
const index = result.attachments.indexOf(s);
|
|
480
|
+
if (index === -1)
|
|
481
|
+
throw new Error("Unexpected, attachment not found");
|
|
482
|
+
return index;
|
|
483
|
+
}),
|
|
484
|
+
location: this._relativeLocation(step.location),
|
|
485
|
+
error: step.error?.message,
|
|
486
|
+
count,
|
|
487
|
+
skipped: !!skipped
|
|
488
|
+
};
|
|
489
|
+
if (step.location)
|
|
490
|
+
this._stepsInFile.set(step.location.file, testStep);
|
|
491
|
+
return testStep;
|
|
492
|
+
}`;
|
|
493
|
+
replaceContent(file, originalContent, newContent);
|
|
494
|
+
|
|
495
|
+
// Also filter steps when creating test results
|
|
496
|
+
originalContent = `steps: dedupeSteps(result.steps).map((s) => this._createTestStep(s, result)),`;
|
|
497
|
+
newContent = `steps: dedupeSteps(result.steps).map((s) => this._createTestStep(s, result)).filter(s => s !== null),`;
|
|
498
|
+
replaceContent(file, originalContent, newContent);
|
|
499
|
+
|
|
500
|
+
// Normalize locations for steps from runtime/index.js - hide location if it's index.js from runtime
|
|
501
|
+
originalContent = `_relativeLocation(location) {
|
|
502
|
+
if (!location)
|
|
503
|
+
return void 0;
|
|
504
|
+
const file = toPosixPath2(import_path8.default.relative(this._config.rootDir, location.file));
|
|
505
|
+
return {
|
|
506
|
+
file,
|
|
507
|
+
line: location.line,
|
|
508
|
+
column: location.column
|
|
509
|
+
};
|
|
510
|
+
}`;
|
|
511
|
+
newContent = `_relativeLocation(location) {
|
|
512
|
+
if (!location)
|
|
513
|
+
return void 0;
|
|
514
|
+
// Hide location for steps from runtime/index.js to reduce clutter
|
|
515
|
+
if (location.file && location.file.includes('@checksum-ai/runtime') && location.file.endsWith('index.js')) {
|
|
516
|
+
return void 0;
|
|
517
|
+
}
|
|
518
|
+
const file = toPosixPath2(import_path8.default.relative(this._config.rootDir, location.file));
|
|
519
|
+
return {
|
|
520
|
+
file,
|
|
521
|
+
line: location.line,
|
|
522
|
+
column: location.column
|
|
523
|
+
};
|
|
524
|
+
}`;
|
|
525
|
+
replaceContent(file, originalContent, newContent);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// -------- [Run] -------- //
|
|
529
|
+
|
|
530
|
+
const isRuntime = true || process.env.RUNTIME === "true";
|
|
531
|
+
|
|
532
|
+
function run(projectPath) {
|
|
533
|
+
try {
|
|
534
|
+
if (fs.existsSync(projectPath)) {
|
|
535
|
+
alwaysInjectScripts(projectPath);
|
|
536
|
+
addGenerateSelectorAndLocator(projectPath);
|
|
537
|
+
if (isRuntime) {
|
|
538
|
+
expect(projectPath);
|
|
539
|
+
testInfo(projectPath);
|
|
540
|
+
testType(projectPath);
|
|
541
|
+
channelOwner(projectPath);
|
|
542
|
+
stackTrace(projectPath);
|
|
543
|
+
indexContent(projectPath);
|
|
544
|
+
// Skipped in merge mode (CHECKSUM_SKIP_TRACE_PATCH): this patch makes
|
|
545
|
+
// the HTML reporter sleep ~10s per `trace` attachment waiting for a
|
|
546
|
+
// `checksum-playwright-trace` file that only the live run produces; in
|
|
547
|
+
// the merge path (real Playwright traces) it is pure dead time.
|
|
548
|
+
if (process.env.CHECKSUM_SKIP_TRACE_PATCH !== "true") {
|
|
549
|
+
reportTraceFile(projectPath);
|
|
550
|
+
}
|
|
551
|
+
htmlReporter(projectPath);
|
|
552
|
+
}
|
|
553
|
+
} else {
|
|
554
|
+
console.warn("Project path not found", projectPath);
|
|
555
|
+
}
|
|
556
|
+
} catch (e) {
|
|
557
|
+
// ignore
|
|
558
|
+
console.error(e);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
module.exports = run;
|