chainwright 0.8.16 → 0.9.0
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/cli/index.js +1 -1
- package/dist/wallets/keplr/index.js +1 -1
- package/dist/wallets/metamask/index.d.ts +2 -5
- package/dist/wallets/metamask/index.js +3 -3
- package/dist/wallets/meteor/index.js +1 -1
- package/dist/wallets/petra/index.js +1 -1
- package/dist/wallets/phantom/index.js +1 -1
- package/dist/wallets/solflare/index.js +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env -S node --import tsx
|
|
2
2
|
import z from"path";import{styleText as g}from"util";import Fe from"@inquirer/checkbox";import{Command as Te}from"commander";import $ from"fs";import H from"path";import{fileURLToPath as te}from"url";var oe=te(import.meta.url),re=H.dirname(oe),P=H.resolve(re,"..","..","generated-profile-name.types.ts"),ae=e=>e.replace(/(^\w)/g,o=>o.toUpperCase());async function G({walletName:e,profileName:o}){let t=ae(e),a=`export type ${t}Profiles = "${o}";`;if($.existsSync(P)){let r=$.readFileSync(P,"utf-8"),n=r.match(new RegExp(`export type ${t}Profiles = ("[^"]+"(?:\\s*\\|\\s*"[^"]+")*)`));if(n){let l=n[0];if(!l.includes(`"${o}"`)){let s=l.concat(` | "${o}"`),c=r.replace(l,s);try{$.writeFileSync(P,c)}catch(i){console.error("Error updating existing profile name type: ",i)}}}else try{$.appendFileSync(P,`
|
|
3
3
|
${a}`,{encoding:"utf-8"})}catch(l){console.error("Error appending new profile name type: ",l)}}else try{$.writeFileSync(P,a)}catch(r){console.error("Error writing new profile name type: ",r)}}import se from"path";import{pathToFileURL as ie}from"url";import{styleText as le}from"util";import{glob as pe}from"glob";import ne from"path";function I(e){let o=ne.basename(e),t=o.match(/^([a-z0-9_]+)(?:-[a-z0-9_]+)*\.setup\.(?:ts|js|mjs)$/i);if(!t)throw new Error(`Invalid wallet setup filename: ${o} (expected "<name>[ -variant].setup.{ts,js,mjs}")`);return t[1]}var ce=e=>e.replace(/\\/g,"/"),me=e=>`${ce(se.resolve(e))}/**/*.setup.{ts,js,}`,fe=e=>import(new URL(ie(e)).href);async function N({walletSetupDir:e,selectedWallets:o}){let t=me(e),a=(await pe(t,{dot:!0,absolute:!0,nodir:!0,windowsPathsNoEscape:!0})).sort(),r=o.length===1?o[0]:o,n=["metamask","solflare","petra","meteor","keplr","phantom"];Array.isArray(r)&&r.forEach(i=>{n.includes(i)||console.warn(le("magenta",`Unsupported wallet: "${i}". Supported wallets are: ${n.join(", ")}`,{validateStream:!1}))});let s=(r==="all"?a:Array.isArray(r)?a.filter(i=>r.some(p=>i.includes(p))):a.filter(i=>i.includes(r))).map(i=>({filePath:i,walletName:I(i)}));if(!s.length||s.length===0)throw new Error([`No wallet setup file found at ${e} for wallet: "${o}".`,'Setup files must use a ".setup.{ts,js,mjs}" extension and include a valid wallet name.','Examples: "metamask.setup.ts", "solflare.setup.ts", "phantom.setup.ts", "metamask-connected.setup.ts"'].join(`
|
|
4
|
-
`));return await Promise.all(s.map(async({filePath:i,walletName:p})=>{let f=await(await fe(i)).default,{fn:E,config:h,password:w}=f;return{walletName:p,fileList:s,config:h,walletPassword:w,setupFunction:E}}))}import x from"fs";import R from"path";import{styleText as S}from"util";import{chromium as be}from"@playwright/test";import xe from"path";var V=".wallet-cache";var X="wallet-setup",K="13.
|
|
4
|
+
`));return await Promise.all(s.map(async({filePath:i,walletName:p})=>{let f=await(await fe(i)).default,{fn:E,config:h,password:w}=f;return{walletName:p,fileList:s,config:h,walletPassword:w,setupFunction:E}}))}import x from"fs";import R from"path";import{styleText as S}from"util";import{chromium as be}from"@playwright/test";import xe from"path";var V=".wallet-cache";var X="wallet-setup",K="13.33.0",C="https://github.com/amaify/chainwright/releases/download/v0.1.0/",ue=`https://github.com/MetaMask/metamask-extension/releases/download/v${K}/metamask-chrome-${K}.zip`,de=`${C}solflare-wallet-extension-v2.19.1.zip`,we=`${C}petra-wallet-extension-v2.4.8.zip`,ge=`${C}phantom-wallet-extension-v26.10.0.zip`,he=`${C}meteor-wallet-extension-v0.7.0.zip`,ye=`${C}keplr-wallet-extension-v0.13.3.zip`,T={metamask:{downloadUrl:ue,extensionName:"MetaMask"},solflare:{downloadUrl:de,extensionName:"Solflare Wallet"},petra:{downloadUrl:we,extensionName:"Petra Aptos Wallet"},phantom:{downloadUrl:ge,extensionName:"Phantom"},meteor:{downloadUrl:he,extensionName:"Meteor Wallet"},keplr:{downloadUrl:ye,extensionName:"Keplr"}};function W(e){return xe.resolve(process.cwd(),V,e)}import{z as D}from"zod";var Se=D.object({id:D.string(),name:D.string()}),Ee=D.array(Se);async function Y(e,o){let t=await e.newPage();await t.goto("chrome://extensions");let a=await t.evaluate("chrome.management.getAll()"),r=Ee.parse(a),n=r.find(l=>l.name.toLowerCase()===o.toLowerCase());if(!n)throw new Error([`[GetExtensionId] Extension with name ${o} not found.`,`Available extensions: ${r.map(l=>l.name).join(", ")}`].join(`
|
|
5
5
|
`));return await t.close(),n.id}import v from"fs";import U from"path";import{styleText as _}from"util";import Pe from"adm-zip";import{createWriteStream as Ae}from"fs";import{Readable as ve}from"stream";import{styleText as k}from"util";import Le from"cli-progress";var $e=12e4;async function q({url:e,destination:o}){let t=new AbortController,a=setTimeout(()=>t.abort(),$e),r=await fetch(e,{redirect:"follow",signal:t.signal});r.ok||(console.error(k("redBright",`\u274C Download failed: HTTP ${r.status}`,{validateStream:!1})),t.abort(),process.exit(1));let n=parseInt(r.headers.get("content-length")||"0",10),l=0,s=ve.fromWeb(r.body);try{let c=new Le.SingleBar({format:`Downloading ${k("cyan","{bar}",{validateStream:!1})} {percentage}%`,clearOnComplete:!0,barCompleteChar:"\u2588",barIncompleteChar:"\u2591",hideCursor:!0});c.start(n,0,{speed:"N/A"}),await new Promise((i,p)=>{let m=Ae(o);s.pipe(m),s.on("data",f=>{l+=f.length,c.update(l)}),m.on("error",p),m.on("finish",()=>{c.stop(),i(void 0)})})}catch(c){console.error(k("redBright",`\u274C Download failed: ${c}`,{validateStream:!1})),process.exit(1)}finally{clearTimeout(a)}}var L=!1,M="";async function Z({downloadUrl:e,name:o,force:t}){let a=W(o),n=T[o].extensionName,l=U.join(a,`${o}-extension.zip`),s=U.join(a,`${o}-extension`);if(L?M!==n&&L&&(L=!1,M=n):M=n,t&&v.existsSync(a)&&!L&&(v.rmSync(a,{recursive:!0}),console.info(_("magenta",`\u{1F9F9} Removed ${n} because of the force flag`,{validateStream:!1}))),v.existsSync(a)||v.mkdir(a,{recursive:!0},i=>{if(i)throw Error("Failed to create cache directory");console.info(`\u2705 ${n} Cache directory created successfully.`)}),v.existsSync(s)?console.info(`\u2705 ${n} Version is downloaded already.`):(console.info(_("cyanBright",`\u{1F4E5} Downloading ${n} extension...`,{validateStream:!1})),await q({url:e,destination:l}),console.info(_("green",`\u2705 ${o.toUpperCase()} Extension downloaded successfully.`,{validateStream:!1}))),!v.existsSync(s))console.info("\u{1F4E6} Extracting extension..."),new Pe(l).extractAllTo(s,!0),console.info(`\u2705 ${n} Extension extracted successfully.`);else{if(L)return console.info(_("magentaBright",`Using the cached ${n} extension for profile creation.`,{validateStream:!1})),s;console.info(_("yellow",`\u26A0\uFE0F Skipping ${n} cache creation: Cache already exists at ${s}. Use --force to overwrite.`,{validateStream:!1}))}let c=U.join(s,"manifest.json");if(!v.existsSync(c))throw new Error(`\u274C (${n}) Invalid extension: manifest.json not found`);return L=!0,s}import{styleText as Ce}from"util";function B(e){return new Promise(o=>setTimeout(o,e))}var O=20,We=6e3,J=4e3;async function _e(e){return e.pages().find(a=>{try{return a.url().startsWith("chrome-extension://")}catch(r){return console.error("[WaitForExtensionOnLoadPage] Error checking page URL:",r),!1}})}async function Q(e,o){let t=0,a=null;if(o==="meteor")return await e.newPage();for(console.info(`Waiting ${J}ms for browser to initialize...`),await B(J);t<=O;)try{if(console.info(`Looking for extension page (attempt ${t+1}/${O})...`),t===O)throw new Error("Extension page not found after maximum retries");let r=await _e(e);if(r){console.info(`Found extension page after ${t+1} polling attempts`),a=r;break}r||(t++,console.info(`Extension page not found, retrying (${t}/${O})...`),await B(We))}catch(r){throw console.error("Error waiting for extension page:",r instanceof Error?r.message:"Unknown error"),new Error(`Extension failed to load properly after ${t} attempts!`)}return console.info(Ce("greenBright","\u2705 Extension page is properly loaded and ready",{validateStream:!1})),a}async function j({walletName:e,force:o,config:t,fileList:a,walletPassword:r,setupFunction:n}){let{downloadUrl:l,extensionName:s}=T[e],c=W(e),i=t?.profileName,p=i?`${i}`:"wallet-data",m=R.resolve(c,"extension-id.txt"),f=R.resolve(c,"extension-path.txt"),E=R.resolve(c,"password.txt"),h=R.resolve(c,p),w=await Z({downloadUrl:l,name:e,force:o}),y=[`--disable-extensions-except=${w}`,`--load-extension=${w}`];if(x.existsSync(h)&&a.length>1)throw Error([S("yellowBright",[`\u274C ${p} directory already exists for ${s}.`,`
|
|
6
6
|
To setup another wallet profile, add a profile name to the wallet setup function.`,S(["blueBright","italic"],'Example: defineWalletSetup(async ({ context, walletPage }) => { ... }, { profileName: "profile-name" });'),S("italic","You can also use the --force flag to overwrite the existing cache.")].join(`
|
|
7
7
|
`),{validateStream:!1})].join(`
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import Z from"fs";import vt from"path";import{chromium as bt}from"@playwright/test";import yt from"path";var Y=".wallet-cache",q=".wallet-context";var J="13.22.0",_="https://github.com/amaify/chainwright/releases/download/v0.1.0/",Kt=`https://github.com/MetaMask/metamask-extension/releases/download/v${J}/metamask-chrome-${J}.zip`,Ut=`${_}solflare-wallet-extension-v2.19.1.zip`,Mt=`${_}petra-wallet-extension-v2.4.8.zip`,Vt=`${_}phantom-wallet-extension-v26.10.0.zip`,Ht=`${_}meteor-wallet-extension-v0.7.0.zip`,jt=`${_}keplr-wallet-extension-v0.13.3.zip`;async function N(t){return yt.resolve(process.cwd(),q,t)}import At from"path";function w(t){return At.resolve(process.cwd(),Y,t)}import Q from"fs";import Pt from"path";async function R(t){try{let e=w(t),o=Pt.resolve(e,"extension-path.txt");if(!Q.existsSync(o))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let a=Q.readFileSync(o,"utf-8").trim();if(!a)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return a}catch(e){throw new Error(`\u274C Failed to get ${t} extension path: ${e.message}`)}}async function tt({wallet:t,workerInfo:e,profileName:o,slowMo:a}){let r=await N(e.workerIndex.toString()),s=w(t.name),c=vt.resolve(s,o??"wallet-data");if(!Z.existsSync(c))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);Z.cpSync(c,r,{recursive:!0,force:!0});let p=await R(t.name),m=await bt.launchPersistentContext(r,{headless:!1,args:[`--disable-extensions-except=${p}`],slowMo:process.env.HEADLESS?0:a}),u=await t.indexUrl(),l=m.pages()[0];return l||(l=await m.newPage()),await l.goto(u),{context:m,walletPage:l,contextPath:r}}import{expect as nt}from"@playwright/test";function T(t){return new Promise(e=>setTimeout(e,t))}async function C(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}import et from"fs";import kt from"path";async function L(t){let e=w(t),o=kt.resolve(e,"password.txt");try{if(!et.existsSync(o))throw new Error("\u274C password.txt not found. Run setup script first.");return et.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} password from cache: ${a.message}`)}}import{expect as Ct}from"@playwright/test";async function ot({context:t,path:e,locator:o}){let a;try{await Ct.poll(async()=>(a=t.pages().filter(r=>r.url().startsWith("chrome-extension://")).find(r=>r.url().match(e)),!!a),{timeout:3e4}).toBe(!0)}catch{let r=t.pages().filter(s=>s.url().startsWith("chrome-extension://")).map(s=>s.url());throw new Error(`Popup page with path "${e}" not found in context after 30s. Pages in context: ${JSON.stringify(r)}`)}if(!a)throw new Error(`Popup page with path ${e} not found in context.`);return await St(a,o),await a.setViewportSize({width:360,height:592}),a}async function St(t,e){await t.waitForLoadState("load",{timeout:4e4}),await t.waitForLoadState("domcontentloaded",{timeout:4e4}),await t.locator(e).first().waitFor({state:"attached",timeout:4e4})}import at from"fs";import Bt from"path";async function rt(t){let e=w(t),o=Bt.resolve(e,"extension-id.txt");try{if(!at.existsSync(o))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return at.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${a.message}`)}}var h=class{name="keplr";onboardingPath="register.html";async indexUrl(){return`chrome-extension://${await this.extensionId()}/sidePanel.html`}async onboardingUrl(){return`chrome-extension://${await this.extensionId()}/${this.onboardingPath}`}async promptUrl(){return`chrome-extension://${await this.extensionId()}/popup.html`}async extensionId(){return await rt(this.name)}async promptPage(e){let o=await this.promptUrl();return await ot({context:e,path:o,locator:"div[data-simplebar='init']"})}};var g={importExistingWalletButton:"button:has-text('Import an existing wallet')",usePrivateKeyButton:"button:has-text('Use recovery phrase or private key')",privateKeyTabButton:"button:has-text('Private key')",privateKeyInput:"input[type='password']",importButton:"button:has-text('Import')",walletNameInput:"input[name='name']",walletPasswordInput:"input[name='password']",confirmWalletPasswordInput:"input[name='confirmPassword']",nextButton:"button:has-text('Next')",searchNetworkInput:"input[placeholder='Search networks']",saveButton:"button:has-text('Save')",finishButton:"button:has-text('Finish')"};function Tt(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}async function W({page:t,privateKey:e,walletName:o,chains:a,mode:r="onboard"}){let s=await L("keplr"),c=new h;if(await t.locator(g.importExistingWalletButton).click(),await t.locator(g.usePrivateKeyButton).click(),await t.getByRole("button",{name:"Private key",exact:!0}).click(),await t.locator(g.privateKeyInput).fill(e),await t.getByRole("button",{name:"Import",exact:!0}).click(),await t.locator(g.walletNameInput).fill(o),r==="onboard"){let A=t.locator(g.walletPasswordInput),F=t.locator(g.confirmWalletPasswordInput);await A.fill(s),await F.fill(s)}await t.locator(g.nextButton).click();let x=t.locator("div:has-text('All Native Chains')").nth(-4),P=t.locator("div[cursor='pointer']:has-text('Cosmos Hub')"),b=await x.locator("input[type='checkbox']").getAttribute("checked"),k=await P.locator("input[type='checkbox']").getAttribute("checked");b!==null&&await x.click(),k!==null&&await P.click();let D=t.locator(g.searchNetworkInput);for(let A of a){await D.fill(A);let B=t.locator("div[class='simplebar-content']").locator("div[cursor] > div").first().locator("div").filter({hasText:new RegExp(`^${Tt(A)}$`,"i")}).nth(2).locator("../../../../..");await B.waitFor({state:"visible",timeout:2e4}),await B.locator("input[type='checkbox']").getAttribute("checked")===null&&await B.click()}let S=t.locator(g.saveButton);if(await S.scrollIntoViewIfNeeded(),await S.click(),await T(2e3),r==="onboard"){await t.goto(await c.indexUrl());return}if(r==="add-account-single"){let A=t.locator(g.finishButton);await A.waitFor({state:"visible",timeout:2e4}),await nt(A).toBeEnabled({timeout:2e4}),await A.click()}}async function $(t){let o=await new h().onboardingUrl();await t.getByRole("link",{name:"Settings",exact:!0}).click(),await t.locator("div[cursor='pointer']").first().click(),await t.getByRole("button",{name:"Add Wallet",exact:!0}).click();let c;if(await nt.poll(async()=>(c=t.context().pages().find(p=>p.url().match(o)),!!c),{timeout:3e4}).toBe(!0).catch(p=>{console.error(`Failed to find onboarding page with URL matching ${o}. Original error: ${p}`)}),!c)throw new Error(`Onboarding page not found. Expected URL: ${o}`);return await C(c),await c.bringToFront(),c}async function it({page:t,privateKey:e,chains:o,walletName:a,mode:r}){let s=await $(t);await W({page:s,privateKey:e,walletName:a,chains:o,mode:r}),await t.locator("div:has(div:has-text('Select Wallet'))").nth(-4).locator("div:has(> div > svg)").first().click(),await t.getByRole("link",{name:"Home",exact:!0}).click()}import{expect as Wt}from"@playwright/test";var K={approveButton:"button:has-text('Approve')",rejectButton:"button[color='secondary']"};async function ct(t){let e=t.locator(K.approveButton);await Wt(e).toBeEnabled({timeout:2e4}),await e.click()}async function st(t){t.getByRole("button",{name:"Approve",exact:!0}).click(),await T(1e3)}import{expect as Et}from"@playwright/test";import f from"zod";var lt=f.discriminatedUnion("chain",[f.object({chain:f.literal(["Injective","Injective (Testnet)","Polygon"]),walletName:f.string().min(1,"Wallet name cannot be an empty string")}),f.object({chain:f.literal(["Bitcoin","Bitcoin Signet","Bitcoin Testnet"]),chainTag:f.literal(["Taproot","Native Segwit"]),walletName:f.string().min(1,"Wallet name cannot be an empty string")})]),pt=f.object({currentAccountName:f.string().min(1,"Current account name cannot be an empty string"),newAccountName:f.string().min(1,"New account name cannot be an empty string")});async function mt({page:t,...e}){let o=lt.parse({...e});await t.getByRole("textbox",{name:"Search for asset or chain (i.e. ATOM, Cosmos)",exact:!0}).fill(o.chain);let r=t.locator(`div:has-text("${o.chain}")`).nth(-2).filter({hasNot:t.locator("span")});if(await r.waitFor({state:"attached",timeout:2e4}),!await r.isVisible().catch(()=>!1))throw Error(`Make sure "${o.chain}" is activated.`);let c=await r.locator("div").all();Et(c.length).toBeGreaterThan(0),await t.locator(`div:has(div:has-text('${o.walletName}'))`).nth(-3).locator("div:has(> div > svg)").click();let u=t.locator("div:has(> div[data-simplebar='init'])").last(),d=u.locator("div:has(> div > input)").locator("input");await d.fill(o.chain);let v=await u.locator("div[cursor='pointer']",{hasText:o.chain}).all(),x;for(let b of v){let k;"chainTag"in e&&(k=e.chainTag);let D=b.locator("div",{hasText:o.chain}).last(),S=k?b.locator("div",{hasText:k}).last():null,F=(S?await S?.isVisible().catch(()=>!1):!1)?await S?.textContent():null,B=await D.textContent(),X=F?`${B} ${F}`:B,xt=k?`${o.chain} ${k}`:o.chain;if(X===xt){x=D.locator("xpath=../../../.."),await d.clear();break}}if(!x)throw Error(`Address for ${o.walletName} account on "${o.chain}" chain not found.`);return await x.hover(),await x.scrollIntoViewIfNeeded(),await x.click(),await x.waitFor({state:"detached",timeout:7e3}),await t.evaluate(async()=>await navigator.clipboard.readText())}var O={openSidebarMenuButton:"div[cursor='pointer']:has(> div[cursor='pointer'])",menuPopupContent:"div[id='modal-root-3']",lockWalletButton:"div:has(> div:has-text('Lock Wallet'))",settingsButton:"div:has(a[href='#/settings'])"},H={unlockButton:"button[type='submit']:has-text('Unlock')",passwordInput:"input[placeholder='Type Your Password']"};async function ut(t){await t.locator(O.openSidebarMenuButton).click(),await t.locator(O.lockWalletButton).nth(-1).click(),await t.getByText("Welcome Back").waitFor({state:"visible",timeout:3e4})}import{styleText as dt}from"util";import{expect as It}from"@playwright/test";async function U(t,e){let o=t.locator("div[color]").nth(1);if(await o.textContent()===e){console.info(`
|
|
1
|
+
import Z from"fs";import vt from"path";import{chromium as bt}from"@playwright/test";import yt from"path";var Y=".wallet-cache",q=".wallet-context";var J="13.33.0",_="https://github.com/amaify/chainwright/releases/download/v0.1.0/",Kt=`https://github.com/MetaMask/metamask-extension/releases/download/v${J}/metamask-chrome-${J}.zip`,Ut=`${_}solflare-wallet-extension-v2.19.1.zip`,Mt=`${_}petra-wallet-extension-v2.4.8.zip`,Vt=`${_}phantom-wallet-extension-v26.10.0.zip`,Ht=`${_}meteor-wallet-extension-v0.7.0.zip`,jt=`${_}keplr-wallet-extension-v0.13.3.zip`;async function N(t){return yt.resolve(process.cwd(),q,t)}import At from"path";function w(t){return At.resolve(process.cwd(),Y,t)}import Q from"fs";import Pt from"path";async function R(t){try{let e=w(t),o=Pt.resolve(e,"extension-path.txt");if(!Q.existsSync(o))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let a=Q.readFileSync(o,"utf-8").trim();if(!a)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return a}catch(e){throw new Error(`\u274C Failed to get ${t} extension path: ${e.message}`)}}async function tt({wallet:t,workerInfo:e,profileName:o,slowMo:a}){let r=await N(e.workerIndex.toString()),s=w(t.name),c=vt.resolve(s,o??"wallet-data");if(!Z.existsSync(c))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);Z.cpSync(c,r,{recursive:!0,force:!0});let p=await R(t.name),m=await bt.launchPersistentContext(r,{headless:!1,args:[`--disable-extensions-except=${p}`],slowMo:process.env.HEADLESS?0:a}),u=await t.indexUrl(),l=m.pages()[0];return l||(l=await m.newPage()),await l.goto(u),{context:m,walletPage:l,contextPath:r}}import{expect as nt}from"@playwright/test";function T(t){return new Promise(e=>setTimeout(e,t))}async function C(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}import et from"fs";import kt from"path";async function L(t){let e=w(t),o=kt.resolve(e,"password.txt");try{if(!et.existsSync(o))throw new Error("\u274C password.txt not found. Run setup script first.");return et.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} password from cache: ${a.message}`)}}import{expect as Ct}from"@playwright/test";async function ot({context:t,path:e,locator:o}){let a;try{await Ct.poll(async()=>(a=t.pages().filter(r=>r.url().startsWith("chrome-extension://")).find(r=>r.url().match(e)),!!a),{timeout:3e4}).toBe(!0)}catch{let r=t.pages().filter(s=>s.url().startsWith("chrome-extension://")).map(s=>s.url());throw new Error(`Popup page with path "${e}" not found in context after 30s. Pages in context: ${JSON.stringify(r)}`)}if(!a)throw new Error(`Popup page with path ${e} not found in context.`);return await St(a,o),await a.setViewportSize({width:360,height:592}),a}async function St(t,e){await t.waitForLoadState("load",{timeout:4e4}),await t.waitForLoadState("domcontentloaded",{timeout:4e4}),await t.locator(e).first().waitFor({state:"attached",timeout:4e4})}import at from"fs";import Bt from"path";async function rt(t){let e=w(t),o=Bt.resolve(e,"extension-id.txt");try{if(!at.existsSync(o))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return at.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${a.message}`)}}var h=class{name="keplr";onboardingPath="register.html";async indexUrl(){return`chrome-extension://${await this.extensionId()}/sidePanel.html`}async onboardingUrl(){return`chrome-extension://${await this.extensionId()}/${this.onboardingPath}`}async promptUrl(){return`chrome-extension://${await this.extensionId()}/popup.html`}async extensionId(){return await rt(this.name)}async promptPage(e){let o=await this.promptUrl();return await ot({context:e,path:o,locator:"div[data-simplebar='init']"})}};var g={importExistingWalletButton:"button:has-text('Import an existing wallet')",usePrivateKeyButton:"button:has-text('Use recovery phrase or private key')",privateKeyTabButton:"button:has-text('Private key')",privateKeyInput:"input[type='password']",importButton:"button:has-text('Import')",walletNameInput:"input[name='name']",walletPasswordInput:"input[name='password']",confirmWalletPasswordInput:"input[name='confirmPassword']",nextButton:"button:has-text('Next')",searchNetworkInput:"input[placeholder='Search networks']",saveButton:"button:has-text('Save')",finishButton:"button:has-text('Finish')"};function Tt(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}async function W({page:t,privateKey:e,walletName:o,chains:a,mode:r="onboard"}){let s=await L("keplr"),c=new h;if(await t.locator(g.importExistingWalletButton).click(),await t.locator(g.usePrivateKeyButton).click(),await t.getByRole("button",{name:"Private key",exact:!0}).click(),await t.locator(g.privateKeyInput).fill(e),await t.getByRole("button",{name:"Import",exact:!0}).click(),await t.locator(g.walletNameInput).fill(o),r==="onboard"){let A=t.locator(g.walletPasswordInput),F=t.locator(g.confirmWalletPasswordInput);await A.fill(s),await F.fill(s)}await t.locator(g.nextButton).click();let x=t.locator("div:has-text('All Native Chains')").nth(-4),P=t.locator("div[cursor='pointer']:has-text('Cosmos Hub')"),b=await x.locator("input[type='checkbox']").getAttribute("checked"),k=await P.locator("input[type='checkbox']").getAttribute("checked");b!==null&&await x.click(),k!==null&&await P.click();let D=t.locator(g.searchNetworkInput);for(let A of a){await D.fill(A);let B=t.locator("div[class='simplebar-content']").locator("div[cursor] > div").first().locator("div").filter({hasText:new RegExp(`^${Tt(A)}$`,"i")}).nth(2).locator("../../../../..");await B.waitFor({state:"visible",timeout:2e4}),await B.locator("input[type='checkbox']").getAttribute("checked")===null&&await B.click()}let S=t.locator(g.saveButton);if(await S.scrollIntoViewIfNeeded(),await S.click(),await T(2e3),r==="onboard"){await t.goto(await c.indexUrl());return}if(r==="add-account-single"){let A=t.locator(g.finishButton);await A.waitFor({state:"visible",timeout:2e4}),await nt(A).toBeEnabled({timeout:2e4}),await A.click()}}async function $(t){let o=await new h().onboardingUrl();await t.getByRole("link",{name:"Settings",exact:!0}).click(),await t.locator("div[cursor='pointer']").first().click(),await t.getByRole("button",{name:"Add Wallet",exact:!0}).click();let c;if(await nt.poll(async()=>(c=t.context().pages().find(p=>p.url().match(o)),!!c),{timeout:3e4}).toBe(!0).catch(p=>{console.error(`Failed to find onboarding page with URL matching ${o}. Original error: ${p}`)}),!c)throw new Error(`Onboarding page not found. Expected URL: ${o}`);return await C(c),await c.bringToFront(),c}async function it({page:t,privateKey:e,chains:o,walletName:a,mode:r}){let s=await $(t);await W({page:s,privateKey:e,walletName:a,chains:o,mode:r}),await t.locator("div:has(div:has-text('Select Wallet'))").nth(-4).locator("div:has(> div > svg)").first().click(),await t.getByRole("link",{name:"Home",exact:!0}).click()}import{expect as Wt}from"@playwright/test";var K={approveButton:"button:has-text('Approve')",rejectButton:"button[color='secondary']"};async function ct(t){let e=t.locator(K.approveButton);await Wt(e).toBeEnabled({timeout:2e4}),await e.click()}async function st(t){t.getByRole("button",{name:"Approve",exact:!0}).click(),await T(1e3)}import{expect as Et}from"@playwright/test";import f from"zod";var lt=f.discriminatedUnion("chain",[f.object({chain:f.literal(["Injective","Injective (Testnet)","Polygon"]),walletName:f.string().min(1,"Wallet name cannot be an empty string")}),f.object({chain:f.literal(["Bitcoin","Bitcoin Signet","Bitcoin Testnet"]),chainTag:f.literal(["Taproot","Native Segwit"]),walletName:f.string().min(1,"Wallet name cannot be an empty string")})]),pt=f.object({currentAccountName:f.string().min(1,"Current account name cannot be an empty string"),newAccountName:f.string().min(1,"New account name cannot be an empty string")});async function mt({page:t,...e}){let o=lt.parse({...e});await t.getByRole("textbox",{name:"Search for asset or chain (i.e. ATOM, Cosmos)",exact:!0}).fill(o.chain);let r=t.locator(`div:has-text("${o.chain}")`).nth(-2).filter({hasNot:t.locator("span")});if(await r.waitFor({state:"attached",timeout:2e4}),!await r.isVisible().catch(()=>!1))throw Error(`Make sure "${o.chain}" is activated.`);let c=await r.locator("div").all();Et(c.length).toBeGreaterThan(0),await t.locator(`div:has(div:has-text('${o.walletName}'))`).nth(-3).locator("div:has(> div > svg)").click();let u=t.locator("div:has(> div[data-simplebar='init'])").last(),d=u.locator("div:has(> div > input)").locator("input");await d.fill(o.chain);let v=await u.locator("div[cursor='pointer']",{hasText:o.chain}).all(),x;for(let b of v){let k;"chainTag"in e&&(k=e.chainTag);let D=b.locator("div",{hasText:o.chain}).last(),S=k?b.locator("div",{hasText:k}).last():null,F=(S?await S?.isVisible().catch(()=>!1):!1)?await S?.textContent():null,B=await D.textContent(),X=F?`${B} ${F}`:B,xt=k?`${o.chain} ${k}`:o.chain;if(X===xt){x=D.locator("xpath=../../../.."),await d.clear();break}}if(!x)throw Error(`Address for ${o.walletName} account on "${o.chain}" chain not found.`);return await x.hover(),await x.scrollIntoViewIfNeeded(),await x.click(),await x.waitFor({state:"detached",timeout:7e3}),await t.evaluate(async()=>await navigator.clipboard.readText())}var O={openSidebarMenuButton:"div[cursor='pointer']:has(> div[cursor='pointer'])",menuPopupContent:"div[id='modal-root-3']",lockWalletButton:"div:has(> div:has-text('Lock Wallet'))",settingsButton:"div:has(a[href='#/settings'])"},H={unlockButton:"button[type='submit']:has-text('Unlock')",passwordInput:"input[placeholder='Type Your Password']"};async function ut(t){await t.locator(O.openSidebarMenuButton).click(),await t.locator(O.lockWalletButton).nth(-1).click(),await t.getByText("Welcome Back").waitFor({state:"visible",timeout:3e4})}import{styleText as dt}from"util";import{expect as It}from"@playwright/test";async function U(t,e){let o=t.locator("div[color]").nth(1);if(await o.textContent()===e){console.info(`
|
|
2
2
|
Already on ${e} account. No need to switch.`);return}await o.click();let r=t.locator("div[class='simplebar-content'] > div").locator("> div",{hasText:e});if(!await r.isVisible().catch(()=>!1))throw new Error(`Account "${e}" not found. Make sure the account is onboarded or verify the account name.`);let c=t.locator("div:has-text('Select Wallet')").last();await r.click(),await c.waitFor({state:"detached",timeout:3e4})}async function j({page:t,onboard:e}){if(console.info(dt("yellowBright",`
|
|
3
3
|
Keplr onboarding started...`,{validateStream:!1})),e.length===1)for(let{privateKey:o,walletName:a,chains:r}of e)await W({page:t,privateKey:o,walletName:a,chains:r,mode:"onboard"});if(e.length>1){let o=e[0];if(o){let{privateKey:l,walletName:d,chains:y}=o;await W({page:t,privateKey:l,walletName:d,chains:y,mode:"onboard"})}let a=e.slice(1);for(let{privateKey:l,walletName:d,chains:y}of a){let v=await $(t);await W({page:v,privateKey:l,walletName:d,chains:y,mode:"add-account-single"})}await t.locator("div",{hasText:"Select Wallet"}).last().locator("../../..").locator("div > svg").click(),await t.getByRole("link",{name:"Home",exact:!0}).click();let p=t.locator(O.openSidebarMenuButton);await It(p).toBeVisible({timeout:3e4});let m=e.at(-1)?.walletName,u=e[0]?.walletName;m&&u&&await U(t,u)}await T(3e3),console.info(dt("greenBright","\u2728 Keplr onboarding completed successfully",{validateStream:!1}))}async function wt(t){let e=t.locator(K.rejectButton);await e.waitFor({state:"visible",timeout:2e4}),await e.click()}async function ht({page:t,currentAccountName:e,newAccountName:o}){let a=pt.parse({currentAccountName:e,newAccountName:o});await t.getByRole("link",{name:"Settings",exact:!0}).click(),await t.locator("div[cursor='pointer']").first().click();let c=t.locator("div",{hasText:a.currentAccountName}).nth(-4);if(!await c.isVisible().catch(()=>!1))throw Error(`Account with name "${a.currentAccountName}" not found`);await c.locator("div[cursor='pointer'] svg").click(),await t.locator("div > div[cursor='pointer'] > div:has-text('Change Wallet Name')").last().click(),await t.locator("input[name='name']").fill(a.newAccountName),await t.locator("button:has-text('Save')").click()}async function M(t){let e=await L("keplr");await t.locator(H.passwordInput).fill(e),await t.locator(H.unlockButton).click(),await t.locator("div:has-text('Deposit')").last().waitFor({state:"visible",timeout:3e4})}var E=class extends h{page;constructor(e){super(),this.page=e}async onboard(e){await j({page:this.page,onboard:e})}async unlock(){await M(this.page)}async lock(){await ut(this.page)}async renameAccount({currentAccountName:e,newAccountName:o}){await ht({page:this.page,currentAccountName:e,newAccountName:o})}async switchAccount(e){await U(this.page,e)}async getAccountAddress({...e}){return await mt({page:this.page,...e})}async addAccount({chains:e,privateKey:o,walletName:a,mode:r="add-account-multiple"}){await it({page:this.page,privateKey:o,walletName:a,chains:e,mode:r})}async connectToApp(){await st(await this.promptPage(this.page.context()))}async confirmTransaction(){await ct(await this.promptPage(this.page.context()))}async rejectTransaction(){await wt(await this.promptPage(this.page.context()))}};import ft from"fs";import Ot from"path";import{test as Dt,chromium as Rt}from"@playwright/test";import{expect as Ft}from"@playwright/test";async function z(t,e){let o=await t.newPage();return await Ft(async()=>{await o.goto(e),await C(o)}).toPass(),o}async function G(t,e){let o=await e.newPage();for(let{origin:a,localStorage:r}of t){let s=o.mainFrame();await s.goto(a),await s.evaluate(c=>{c.forEach(({name:p,value:m})=>{window.localStorage.setItem(p,m)})},r)}await o.close()}import _t from"fs/promises";async function gt(t){await _t.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var Nt=35e3;async function V(t,e){try{await Promise.race([t.close(),new Promise((o,a)=>setTimeout(()=>a(new Error("Context close timed out")),Nt))])}catch(o){console.warn(`Browser context close did not complete cleanly: ${o.message}`)}try{await gt(e)}catch(o){console.error(`Failed to remove temporary context directory at ${e}. Error:`,o)}}var I,Pa=({slowMo:t=0,profileName:e}={})=>Dt.extend({contextPath:async({browserName:o},a,r)=>{let s=await N(`${o}-${r.testId}`);await a(s)},context:async({context:o,contextPath:a},r)=>{let s=new h,c=w(s.name),p=await R(s.name),m=Ot.resolve(c,e??"wallet-data");if(!ft.existsSync(m))throw new Error("\u274C Cache for Keplr wallet data not found. Create it first");ft.cpSync(m,a,{recursive:!0,force:!0});let u=[`--disable-extensions-except=${p}`,`--load-extension=${p}`];process.env.HEADLESS&&(u.push("--headless=new"),t>0&&console.warn("\u26A0\uFE0F Slow motion makes no sense in headless mode. It will be ignored!"));let l=await Rt.launchPersistentContext(a,{headless:!1,args:u,slowMo:process.env.HEADLESS?0:t});await l.grantPermissions(["clipboard-read"]);let{cookies:d,origins:y}=await o.storageState();d&&await l.addCookies(d),y&&y.length>0&&G(y,l);let v=await s.indexUrl();I=l.pages().find(P=>P.url().startsWith(v))||await z(l,v),await C(I);for(let P of l.pages()){let b=P.url();(b.includes("about:blank")||b.includes(s.onboardingPath))&&await P.close()}await I.bringToFront(),await M(I),await r(l),await V(l,a)},keplrPage:async({context:o},a)=>{await a(I)},keplr:async({context:o},a)=>{let r=new E(I);await a(r)}});import{test as Lt}from"@playwright/test";var Wa=({slowMo:t,profileName:e}={})=>Lt.extend({workerScopeContents:[async({browser:o},a,r)=>{let s=new h,{context:c,contextPath:p,walletPage:m}=await tt({wallet:s,workerInfo:r,profileName:e,slowMo:t});await c.grantPermissions(["clipboard-read"]);for(let l of c.pages())l.url().includes("about:blank")&&await l.close();let u=new E(m);await u.unlock(),await a({wallet:u,walletPage:m,context:c}),await V(c,p)},{scope:"worker"}]});export{E as Keplr,Pa as keplrFixture,Wa as keplrWorkerScopeFixture,tt as workerScopeContext};
|
|
@@ -408,13 +408,10 @@ declare class Metamask extends MetamaskProfile {
|
|
|
408
408
|
addCustomNetwork({ chainId, currencySymbol, networkName, rpcUrl }: AddCustomNetwork): Promise<void>;
|
|
409
409
|
/**
|
|
410
410
|
* Connects to an app by clicking on the "Connect to app" button.
|
|
411
|
-
* If an account is provided, it will be selected before connecting to the app.
|
|
412
|
-
* @param {string} [account] - The account to select before connecting to the app.
|
|
413
|
-
* @example
|
|
414
411
|
* const metamask = new Metamask(page);
|
|
415
|
-
* await metamask.connectToApp(
|
|
412
|
+
* await metamask.connectToApp();
|
|
416
413
|
*/
|
|
417
|
-
connectToApp(
|
|
414
|
+
connectToApp(): Promise<void>;
|
|
418
415
|
/**
|
|
419
416
|
* Confirms a transaction in the wallet by clicking on the "Confirm" button.
|
|
420
417
|
* @example
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
\u26A0\uFE0F Skipping test: ${e}`),Ot.skip())}var w={buyButton:"eth-overview-buy",swapButton:"eth-overview-swap",sendButton:"eth-overview-send",receiveButton:"eth-overview-receive",openSettingsButton:"account-options-menu-button",accountMenuButton:"account-menu-icon",accountCell:"multichain-account-cell-entropy",openNetworkSelectorButton:"sort-by-networks",accountAddressesButton:"networks-subtitle-test-id",accountAddressesElements:"multichain-address-row",accountAddressQRCode:"multichain-address-row-qr-button"},_={lockButton:"global-menu-lock",networksButton:"global-menu-networks"},O={passwordInput:"unlock-password",unlockButton:"unlock-submit"},P={accountOptionsMenuButton:"multichain-account-cell-end-accessory",accountDetailsLabel:"Account details",renameAccountLabel:"Rename",addressesLabel:"Addresses",pinToTopLabel:"Pin to top",hideAccountLabel:"Hide account",backButton:"back",addMultichainAccountButton:"add-multichain-account-button",addWalletButton:"account-list-add-wallet-button",importWalletButton:"add-wallet-modal-import-wallet",importAccountButton:"add-wallet-modal-import-account"};var g={createWalletButton:"onboarding-create-wallet",importWalletButton:"onboarding-import-wallet",useSecretRecoveryPhraseButton:"onboarding-create-with-srp-button",createNewPasswordInput:"create-password-new-input",confirmNewPasswordInput:"create-password-confirm-input",confirmPasswordCheckbox:"create-password-terms",createPasswordButton:"create-password-submit",revealSecretRecoveryPhraseButton:"recovery-phrase-reveal",recoveryPhraseRemindMeLaterButton:"recovery-phrase-remind-later",metamaskMetricsIAgreeButton:"metametrics-i-agree",onboardingDoneButton:"onboarding-complete-done",importUsingSecretRecoveryPhraseButton:"onboarding-import-with-srp-button",secretRecoveryPhraseTextAreaInput:"srp-input-import__srp-note",importWalletConfirmButton:"import-srp-confirm",importAccountConfirmButton:"import-account-confirm-button",importSRPError:"bannerAlert"};async function pt({page:t,privateKey:e,accountName:o}){let n=ut.string().min(1,"Account name cannot be an empty string").trim().parse(o),r=ut.string().min(1,"Private key cannot be an empty string").trim().parse(e),a=t.getByTestId(w.accountMenuButton);await x(a).toBeVisible({timeout:3e4}),await a.click(),await x(t.getByRole("heading",{name:/accounts/i})).toBeVisible();let i=t.getByTestId(P.addWalletButton),c=await i.textContent();c?.includes("Syncing")&&await x.poll(async()=>(await i.textContent())?.trim()??"",{timeout:12e4}).not.toBe(c),await x(i).toBeEnabled({timeout:6e4}),await i.click();let s=t.getByRole("dialog");await x(s).toContainText(/add wallet/i),await t.getByTestId(P.importAccountButton).click(),await t.locator("input[id='private-key-box']").fill(r);let u=t.getByTestId(g.importAccountConfirmButton);await x(u).toBeEnabled(),await u.click();let f=t.getByTestId(g.importSRPError),B=await f.isVisible().catch(()=>!1);B&&mt(B,`${(await f.textContent())?.split(".")[0]}`);let S=t.locator("div:has(> div[data-testid^='multichain-account-cell-keyring'][class*='mm-box--background-color-background-muted'])"),A=(await S.textContent())?.split("$")[0];A&&await $t({page:t,accountName:n,activeAccountLocator:S,activeAccountName:A}),await t.locator("button[aria-label='Back']").first().click()}async function $t({page:t,accountName:e,activeAccountLocator:o,activeAccountName:n}){let r=o.locator(`div[aria-label='${n} options']`);await x(r).toBeVisible(),await r.click(),await x(t.getByRole("tooltip")).toBeVisible();let a=t.locator(`div[aria-label='${P.renameAccountLabel}']`);await x(a).toBeVisible(),await a.click();let i=t.getByRole("dialog"),c=i.getByRole("heading",{name:/rename/i});await x(c).toBeVisible();let s=i.getByRole("textbox");await x(s).toBeVisible(),await s.fill(e);let p=i.getByRole("button",{name:/confirm/i});await x(p).toBeEnabled(),await p.click(),await i.waitFor({state:"detached",timeout:2e4});let l=t.locator("div:has(> div[data-testid^='multichain-account-cell-keyring'][class*='mm-box--background-color-background-muted'])");await x(l).toContainText(e)}import{expect as $}from"@playwright/test";import M from"zod";var wt=M.object({networkName:M.string().min(1,"Network name cannot be an empty string"),rpcUrl:M.url(),chainId:M.number().or(M.string().includes("0x")),currencySymbol:M.string().toUpperCase().min(1,"Currency symbol cannot be an empty string")});import{expect as Ht}from"@playwright/test";async function j(t){let e=t.locator("div:has(> p[data-testid='notifications-tag-counter__unread-dot'])"),o=t.getByTestId(w.openSettingsButton);await e.isVisible().catch(()=>!1)?await e.click():(await Ht(o).toBeVisible(),await o.click())}async function ft({page:t,...e}){let{chainId:o,currencySymbol:n,networkName:r,rpcUrl:a}=wt.parse({...e},{reportInput:!0});await j(t),await t.getByTestId(_.networksButton).click();let c=t.locator("section[role='dialog']");await $(c).toContainText(/manage networks/i),await t.getByRole("button",{name:/add a custom network/i}).click(),await $(c).toContainText(/Add a custom network/i);let p=t.getByTestId("network-form-network-name"),l=t.getByTestId("test-add-rpc-drop-down"),u=t.getByTestId("network-form-chain-id"),f=t.getByTestId("network-form-ticker-input");await p.fill(r),await l.click(),await t.getByRole("tooltip").locator("div:has(> button:has-text('Add RPC URL'))").click(),await $(c).toContainText(/Add RPC URL/i);let A=t.getByTestId("rpc-url-input-test"),k=t.getByRole("button",{name:/Add URL/i});await A.fill(a),await k.click(),await $(c).toContainText(/Add a custom network/i);let y=t.getByTestId("network-form-chain-id-error");if(await y.isVisible().catch(()=>!1)){let T=await y.textContent();throw Error(`RPC error: ${T}`)}await u.fill(`${o}`),await f.fill(n);let I=t.getByRole("button",{name:/save/i});await $(I).toBeEnabled(),await I.click()}import{expect as gt}from"@playwright/test";function v(t){return new Promise(e=>setTimeout(e,t))}var q={confirmButton:"confirm-footer-button",cancelButton:"confirm-footer-cancel-button"};async function yt(t,e){let o=t.getByTestId(q.confirmButton);await v(2e3);let r=(await o.textContent())?.includes("Review alert"),a=await o.isDisabled().catch(()=>!1);if(r&&a){await t.getByTestId("edit-gas-fees-row").locator("> div").first().click();let l=t.getByRole("dialog");await gt(l).toBeVisible();let u=l.locator("h4",{hasText:"Insufficient funds"}),f=await l.getByTestId("alert-modal__selected-alert").textContent();if(await u.isVisible().catch(()=>!1))throw Error(`${f}`)}if(e){let s=t.getByTestId("edit-gas-fee-icon");if(await s.scrollIntoViewIfNeeded(),await s.click(),e.feeType!=="advanced"&&await t.getByTestId(`gas-option-${e.feeType}`).click(),e.feeType==="advanced"){await t.getByTestId("gas-option-advanced").click();let l=t.getByRole("textbox",{name:"Max base fee"}),u=t.getByRole("textbox",{name:"Priority fee"}),f=t.getByRole("button",{name:"Save",exact:!0});await l.fill(e.maxBaseFee),await u.fill(e.priorityFee),await f.click()}}await gt(o).toBeEnabled(),await o.click();let i=t.getByRole("dialog");await i.isVisible().catch(()=>!1)&&await i.locator("h4",{hasText:"Your assets may be at risk"}).isVisible().catch(()=>!1)&&(await i.getByTestId("alert-modal-acknowledge-checkbox").click(),await i.getByTestId("confirm-alert-modal-submit-button").click()),await t.waitForEvent("close",{timeout:15e3})}import{expect as Gt}from"@playwright/test";import{expect as Y}from"@playwright/test";async function L({page:t,accountName:e}){let o=t.getByTestId(w.accountMenuButton);if(await o.textContent()===e){console.info(`Can't switch account to "${e}", it is already selected.`);return}await Y(o).toBeVisible({timeout:15e3}),await o.click(),await Y(t.getByRole("heading",{name:/accounts/i})).toBeVisible();let r=t.getByTestId(P.addMultichainAccountButton),a=await r.textContent();a?.includes("Syncing")&&await Y.poll(async()=>(await r.textContent())?.trim()??"",{timeout:6e4}).not.toBe(a);let i=await t.getByTestId(/^multichain-account-cell-(?:entropy|keyring):/).all(),c=null;for(let s of i)if(await s.scrollIntoViewIfNeeded(),(await s.textContent())?.includes(e)){c=s;break}if(!c)throw Error(`Account with name "${e}" not found.`);await c?.click()}async function ht(t,e){e&&await L({page:t,accountName:e});let o=t.getByRole("button",{name:"Connect",exact:!0});await o.waitFor({state:"visible",timeout:25e3}),await o.click(),await t.getByRole("heading",{name:"Connecting",exact:!0}).waitFor({state:"detached",timeout:3e4});let r;await Gt.poll(async()=>(r=await t.locator("div[class='permissions-connect']").isVisible().catch(()=>!1),r),{timeout:25e3}).toBe(!0).catch(()=>console.error("Notice dialog did not appear within the timeout period."));let a=t.getByTestId("page-container-footer-next");await a.waitFor({state:"visible",timeout:25e3}),await a.click(),await t.waitForEvent("close",{predicate:()=>!0,timeout:25e3}).catch(()=>console.error("Extension popup did not close within the timeout period when connecting to the DApp."))}async function xt(t,e){await t.getByTestId(w.accountAddressesButton).hover(),await t.getByTestId("multichain-address-rows-list").getByRole("button",{name:/view all/i}).click(),await t.getByRole("searchbox",{name:/search networks/i}).fill(e),await t.locator(`div[data-testid='${w.accountAddressesElements}']:has-text('${e}')`).getByTestId(w.accountAddressQRCode).click();let l=await t.getByRole("dialog").locator("div > p[data-testid='account-address']").textContent();if(!l)throw new Error("Account address not found");return await t.getByLabel("Close",{exact:!0}).click(),await t.getByTestId("multichain-account-address-list-page-back-button").click(),l}import{expect as qt}from"@playwright/test";import{errors as zt}from"@playwright/test";async function E(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}var Bt={loadingOverlay:"loading-overlay",loadingSpinner:"spinner loading-overlay__spinner"};var Kt=6e4,jt=async(t,e,o)=>{await E(e);try{await e.locator(`div[class="${t}"]`).waitFor({state:"detached",timeout:o})}catch(n){if(n instanceof zt.TimeoutError)console.info(`Loading indicator '${t}' not found - continuing.`);else throw console.error(`Error while waiting for loading indicator '${t}' to disappear`),n}},X=async t=>{try{await jt(Bt.loadingSpinner,t,Kt)}catch(e){console.warn("Warning during MetaMask load:",e)}return await v(300),t};async function kt(t){if(await t.getByTestId(O.unlockButton).isVisible().catch(()=>!1)){console.info("\u{1F4A1} Wallet is already locked");return}await j(t);let n=t.getByTestId(_.lockButton);await qt(n).toBeVisible(),await n.click(),await X(t)}import{styleText as Pt}from"util";import{expect as D}from"@playwright/test";import bt from"fs";import Xt from"path";async function Q(t){let e=h(t),o=Xt.resolve(e,"password.txt");try{if(!bt.existsSync(o))throw new Error("\u274C password.txt not found. Run setup script first.");return bt.readFileSync(o,"utf-8")}catch(n){throw new Error(`\u274C Failed to get ${t} password from cache: ${n.message}`)}}import{expect as Qt}from"@playwright/test";async function At({context:t,path:e,locator:o}){let n;try{await Qt.poll(async()=>(n=t.pages().filter(r=>r.url().startsWith("chrome-extension://")).find(r=>r.url().match(e)),!!n),{timeout:3e4}).toBe(!0)}catch{let r=t.pages().filter(a=>a.url().startsWith("chrome-extension://")).map(a=>a.url());throw new Error(`Popup page with path "${e}" not found in context after 30s. Pages in context: ${JSON.stringify(r)}`)}if(!n)throw new Error(`Popup page with path ${e} not found in context.`);return await Jt(n,o),await n.setViewportSize({width:360,height:592}),n}async function Jt(t,e){await t.waitForLoadState("load",{timeout:4e4}),await t.waitForLoadState("domcontentloaded",{timeout:4e4}),await t.locator(e).first().waitFor({state:"attached",timeout:4e4})}import Ct from"fs";import Yt from"path";async function Tt(t){let e=h(t),o=Yt.resolve(e,"extension-id.txt");try{if(!Ct.existsSync(o))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return Ct.readFileSync(o,"utf-8")}catch(n){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${n.message}`)}}var C=class{name="metamask";onboardingPath="/home.html#onboarding";async indexUrl(){return`chrome-extension://${await this.extensionId()}/home.html`}async promptUrl(){return`chrome-extension://${await this.extensionId()}/notification.html`}async extensionId(){return await Tt(this.name)}async promptPage(e){let o=await this.promptUrl();return await At({context:e,path:o,locator:"div[data-testid='multichain-page']"})}};import{expect as Z}from"@playwright/test";async function W({page:t}){await t.locator(`div:has(> button[data-testid='${w.openSettingsButton}'])`).click(),await t.getByTestId(_.networksButton).click();let n=t.locator("section[role='dialog']");await Z(n).toBeVisible(),await Z(n).toContainText(/manage networks/i);let r="div:has(> p:has-text('Show test networks'))";await n.locator(r).scrollIntoViewIfNeeded();let a=n.locator(r);if(!await a.locator("label[class='toggle-button toggle-button--off']").isVisible().catch(()=>!1)){await n.getByRole("button",{name:/close/i}).click(),console.info("Testnet networks are already visible.");return}await a.locator("label[class='toggle-button toggle-button--off']").click(),await t.getByTestId("Sepolia").scrollIntoViewIfNeeded(),await Z(t.getByTestId("Sepolia")).toBeVisible(),await n.getByRole("button",{name:/close/i}).click()}async function tt({page:t,mainAccountName:e,...o}){console.info(Pt("yellowBright",`
|
|
3
|
-
\u{1F98A} MetaMask onboarding started...`,{validateStream:!1}));let n=await Q("metamask"),r=new C,a=t.locator("img[class='loading-spinner']"),i=t.getByTestId(g.createWalletButton),c=t.getByTestId(g.importWalletButton),s=t.getByTestId(g.createNewPasswordInput),p=t.getByTestId(g.confirmNewPasswordInput),l=t.getByTestId(g.confirmPasswordCheckbox),u=t.getByTestId(g.createPasswordButton),f=t.getByTestId(g.metamaskMetricsIAgreeButton),B=t.getByTestId(g.onboardingDoneButton);if(await a.waitFor({state:"detached",timeout:3e4}),o.mode==="create"){let I=t.getByTestId(g.useSecretRecoveryPhraseButton);await i.click(),await I.click(),await s.fill(n),await p.fill(n),await l.click(),await u.click(),await t.getByTestId(g.revealSecretRecoveryPhraseButton).click(),await t.getByTestId(g.recoveryPhraseRemindMeLaterButton).click(),await f.click()}if(o.mode==="import"){let{secretRecoveryPhrase:I}=o,T=I.split(" "),z=t.getByTestId(g.importUsingSecretRecoveryPhraseButton);await c.click(),await z.click();let at=t.getByTestId(g.secretRecoveryPhraseTextAreaInput);await at.fill(T[0]),await at.press("Space");for(let K=1;K<T.length;K++){let rt=t.getByTestId(`import-srp__srp-word-${K}`);await rt.fill(T[K]),await rt.press("Space")}await t.getByTestId(g.importWalletConfirmButton).click(),await s.fill(n),await p.fill(n),await l.click(),await u.click(),await f.click();let Mt=t.getByTestId("wallet-ready");await D(Mt).toContainText(/your wallet is ready/i)}await B.click();let A=`chrome-extension://${await r.extensionId()}/sidepanel.html`,y=await t.context().browser()?.newBrowserCDPSession(),N;await D.poll(async()=>{if(y){let{targetInfos:I}=await y.send("Target.getTargets"),T=I.find(z=>z.url===A);return N=T,!!T}},{timeout:15e3}).toBe(!0),N&&await y?.send("Target.closeTarget",{targetId:N.targetId}),await t.goto(await r.indexUrl()),await a.waitFor({state:"detached",timeout:3e4}),await D(t.getByTestId(w.buyButton)).toBeVisible(),await D(t.getByTestId(w.swapButton)).toBeVisible(),await D(t.getByTestId(w.sendButton)).toBeVisible(),await D(t.getByTestId(w.receiveButton)).toBeVisible(),await W({page:t}),e&&await L({page:t,accountName:e}),await v(5e3),console.info(Pt("greenBright","\u2728 MetaMask onboarding completed successfully",{validateStream:!1}))}import{expect as Zt}from"@playwright/test";async function St(t){let e=t.getByTestId(q.cancelButton);await v(1e3),await Zt(e).toBeEnabled(),await e.click()}import{expect as b}from"@playwright/test";async function It({page:t,currentAccountName:e,newAccountName:o}){let n=t.getByTestId(w.accountMenuButton);if(await n.textContent()===o)throw Error(`The account to be renamed "${o}" already exists.`);await b(n).toBeVisible({timeout:15e3}),await n.click(),await b(t.getByRole("heading",{name:/accounts/i})).toBeVisible();let a=t.getByTestId(P.addMultichainAccountButton),i=await a.textContent();i?.includes("Syncing")&&await b.poll(async()=>(await a.textContent())?.trim()??"",{timeout:6e4}).not.toBe(i);let c=await t.getByTestId(/^multichain-account-cell/).all(),s=null;for(let y of c)if((await y.textContent())?.includes(e)){s=y;break}if(!s)throw Error(`Account with name "${e}" not found.`);if((await s.textContent())?.split("$")[0]===o)throw Error(`The new account name "${o}" is the same as the old account name "${e}".`);let l=t.locator(`div[aria-label='${e} options']`);await b(l).toBeVisible(),await l.click(),await b(t.getByRole("tooltip")).toBeVisible();let u=t.locator(`div[aria-label='${P.renameAccountLabel}']`);await b(u).toBeVisible(),await u.click();let f=t.getByRole("dialog"),B=f.getByRole("heading",{name:/rename/i});await b(B).toBeVisible();let S=f.getByRole("textbox");await b(S).toBeVisible(),await S.fill(o);let A=f.getByRole("button",{name:/confirm/i});await b(A).toBeEnabled(),await A.click();for(let y of c)if((await y.textContent())?.includes(o)){await b(y).toBeVisible(),await b(y).toContainText(o);break}await t.locator("button[aria-label='Back']").first().click()}import{expect as et}from"@playwright/test";async function vt({page:t,networkType:e,chainName:o}){let n=t.getByTestId(w.openNetworkSelectorButton);await n.click();let r=t.getByTestId("modal-header-close-button");if(e==="testnet"||e==="custom"){let s=t.getByRole("tab",{name:"Custom"});await s.click(),await t.locator("p:has-text('Testnets')").isVisible().catch(()=>!1)||(await r.click(),await W({page:t}),await n.click(),await s.click());let u=t.locator(`div div[data-testid='${o}']`),f=await u.textContent();et(f).toBe(o),await u.click();return}await t.getByRole("tab",{name:"Popular"}).click();let i=t.locator(`div div[data-testid='${o}']`),c=await i.textContent();et(c).toBe(o),await i.click(),await et(n).toContainText(o,{timeout:3e4})}import{expect as Rt}from"@playwright/test";async function H(t){let e=await Q("metamask"),o=t.getByTestId(O.passwordInput);if(await t.getByTestId(w.openNetworkSelectorButton).isVisible().catch(()=>!1)){console.info("\u{1F4A1} Wallet is already unlocked");return}await o.fill(e);let a=t.getByTestId(O.unlockButton);await Rt(a).toBeVisible(),await a.click(),await X(t),await Rt(t.getByTestId(w.buyButton)).toBeVisible({timeout:3e4})}var V=class extends C{page;constructor(e){super(),this.page=e}async onboard(e){await tt({page:this.page,...e})}async unlock(){await H(this.page)}async lock(){await kt(this.page)}async renameAccount({newAccountName:e,currentAccountName:o}){await It({page:this.page,newAccountName:e,currentAccountName:o})}async addAccount({privateKey:e,accountName:o}){await pt({page:this.page,privateKey:e,accountName:o})}async switchAccount({accountName:e}){await L({page:this.page,accountName:e})}async switchNetwork({...e}){await vt({page:this.page,...e})}async getAccountAddress(e){return await xt(this.page,e)}async toggleShowTestnetNetwork(){await W({page:this.page})}async addCustomNetwork({chainId:e,currencySymbol:o,networkName:n,rpcUrl:r}){await ft({page:this.page,chainId:e,currencySymbol:o,networkName:n,rpcUrl:r})}async connectToApp(e){await ht(await this.promptPage(this.page.context()),e)}async confirmTransaction(e){await yt(await this.promptPage(this.page.context()),e)}async rejectTransaction(){await St(await this.promptPage(this.page.context()))}};import Nt from"fs";import ne from"path";import{test as ae,chromium as re}from"@playwright/test";import{Instance as ie,Pool as se}from"prool";import{expect as te}from"@playwright/test";async function ot(t,e){let o=await t.newPage();return await te(async()=>{await o.goto(e),await E(o)}).toPass(),o}async function nt(t,e){let o=await e.newPage();for(let{origin:n,localStorage:r}of t){let a=o.mainFrame();await a.goto(n),await a.evaluate(i=>{i.forEach(({name:c,value:s})=>{window.localStorage.setItem(c,s)})},r)}await o.close()}import ee from"fs/promises";async function Et(t){await ee.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var oe=35e3;async function J(t,e){try{await Promise.race([t.close(),new Promise((o,n)=>setTimeout(()=>n(new Error("Context close timed out")),oe))])}catch(o){console.warn(`Browser context close did not complete cleanly: ${o.message}`)}try{await Et(e)}catch(o){console.error(`Failed to remove temporary context directory at ${e}. Error:`,o)}}var G,Ua=({slowMo:t=0,profileName:e}={})=>ae.extend({contextPath:async({browserName:o},n,r)=>{let a=await R(`${o}-${r.testId}`);await n(a)},context:async({context:o,contextPath:n},r)=>{let a=new C,i=h(a.name),c=await F(a.name),s=ne.resolve(i,e??"wallet-data");if(!Nt.existsSync(s))throw new Error("\u274C Cache for MetaMask wallet data not found. Create it first");Nt.cpSync(s,n,{recursive:!0,force:!0});let p=[`--disable-extensions-except=${c}`,`--load-extension=${c}`];process.env.HEADLESS&&(p.push("--headless=new"),t>0&&console.warn("\u26A0\uFE0F Slow motion makes no sense in headless mode. It will be ignored!"));let l=await re.launchPersistentContext(n,{headless:!1,args:[`--disable-extensions-except=${c}`],slowMo:process.env.HEADLESS?0:t}),{cookies:u,origins:f}=await o.storageState();u&&await l.addCookies(u),f&&f.length>0&&nt(f,l);let B=await a.indexUrl();await l.waitForEvent("page",{predicate:k=>k.url().startsWith(B),timeout:3e4}),G=l.pages().find(k=>k.url().startsWith(B))??await ot(l,B);for(let k of l.pages())k.url().includes("about:blank")&&await k.close();await G.locator("img[class='loading-spinner']").waitFor({state:"detached"}),await H(G),await r(l),await J(l,n)},metamaskPage:async({context:o},n)=>{await n(G)},metamask:async({context:o},n)=>{let r=new V(G);await n(r)},createAnvilNode:async({context:o},n,r)=>{let a=r.workerIndex,i;await n(async c=>{i=se.define({instance:ie.anvil(c)});let s=await i.start(a),p=`http://${s.host}:${s.port}`,u=c?.chainId??31337;return{rpcUrl:p,anvil:s,chainId:u}}),i&&await i.stop(a)},connectToAnvil:async({context:o,metamask:n,createAnvilNode:r},a)=>{await a(async()=>{let{chainId:i,rpcUrl:c}=await r({chainId:2251});await n.addCustomNetwork({chainId:i,currencySymbol:"ETH",networkName:"Anvil Localnet",rpcUrl:c})})}});import{test as de}from"@playwright/test";import{Instance as me,Pool as ue}from"prool";import Ft from"fs";import ce from"path";import{chromium as le}from"@playwright/test";async function _t({workerInfo:t,profileName:e,slowMo:o}){let n=new C,r=await R(t.workerIndex.toString()),a=h(n.name),i=ce.resolve(a,e??"wallet-data");if(!Ft.existsSync(i))throw new Error(`Cache for ${n.name} does not exist. Create it first!`);Ft.cpSync(i,r,{recursive:!0,force:!0});let c=await F(n.name),s=await le.launchPersistentContext(r,{headless:!1,args:[`--disable-extensions-except=${c}`],slowMo:process.env.HEADLESS?0:o}),p=await n.indexUrl();await s.waitForEvent("page",{predicate:u=>u.url().startsWith(p),timeout:4e4});let l=s.pages().find(u=>u.url().startsWith(p));l||(l=await s.newPage(),await l.goto(p),await E(l));for(let u of s.pages())u.url().includes("about:blank")&&await u.close();return{context:s,walletPage:l,contextPath:r}}var ar=({profileName:t,slowMo:e}={})=>de.extend({workerScopeContents:[async({browser:o},n,r)=>{let{context:a,contextPath:i,walletPage:c}=await _t({workerInfo:r,profileName:t,slowMo:e});await a.grantPermissions(["clipboard-read"]);let s=new V(c);await s.unlock(),await n({wallet:s,walletPage:c,context:a}),await J(a,i)},{scope:"worker"}],createAnvilNode:async({context:o},n,r)=>{let a=r.workerIndex,i;await n(async c=>{i=ue.define({instance:me.anvil(c)});let s=await i.start(a),p=`http://${s.host}:${s.port}`,u=c?.chainId??31337;return{rpcUrl:p,anvil:s,chainId:u}}),i&&await i.stop(a)},connectToAnvil:async({context:o,createAnvilNode:n,workerScopeContents:r},a)=>{await a(async()=>{let{wallet:i}=r,{chainId:c,rpcUrl:s}=await n({chainId:2251});await i.addCustomNetwork({chainId:c,currencySymbol:"ETH",networkName:"Anvil Localnet",rpcUrl:s})})}});export{V as Metamask,Ua as metamaskFixture,ar as metamaskWorkerScopeFixture,Oe as workerScopeContext};
|
|
1
|
+
import lt from"fs";import Vt from"path";import{chromium as Ut}from"@playwright/test";import Lt from"path";var it=".wallet-cache",st=".wallet-context";var rt="13.33.0",U="https://github.com/amaify/chainwright/releases/download/v0.1.0/",fe=`https://github.com/MetaMask/metamask-extension/releases/download/v${rt}/metamask-chrome-${rt}.zip`,ge=`${U}solflare-wallet-extension-v2.19.1.zip`,ye=`${U}petra-wallet-extension-v2.4.8.zip`,he=`${U}phantom-wallet-extension-v26.10.0.zip`,xe=`${U}meteor-wallet-extension-v0.7.0.zip`,Be=`${U}keplr-wallet-extension-v0.13.3.zip`;async function v(t){return Lt.resolve(process.cwd(),st,t)}import Wt from"path";function x(t){return Wt.resolve(process.cwd(),it,t)}import ct from"fs";import Dt from"path";async function F(t){try{let e=x(t),o=Dt.resolve(e,"extension-path.txt");if(!ct.existsSync(o))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let n=ct.readFileSync(o,"utf-8").trim();if(!n)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return n}catch(e){throw new Error(`\u274C Failed to get ${t} extension path: ${e.message}`)}}async function $e({wallet:t,workerInfo:e,profileName:o,slowMo:n}){let r=await v(e.workerIndex.toString()),i=x(t.name),s=Vt.resolve(i,o??"wallet-data");if(!lt.existsSync(s))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);lt.cpSync(s,r,{recursive:!0,force:!0});let c=await F(t.name),a=await Ut.launchPersistentContext(r,{headless:!1,args:[`--disable-extensions-except=${c}`],slowMo:process.env.HEADLESS?0:n}),p=await t.indexUrl(),l=a.pages()[0];return l||(l=await a.newPage()),await l.goto(p),{context:a,walletPage:l,contextPath:r}}import{expect as B}from"@playwright/test";import ut from"zod";import{test as Ot}from"@playwright/test";function dt(t,e){t&&(console.warn(`
|
|
2
|
+
\u26A0\uFE0F Skipping test: ${e}`),Ot.skip())}var w={buyButton:"eth-overview-buy",swapButton:"eth-overview-swap",sendButton:"eth-overview-send",receiveButton:"eth-overview-receive",openSettingsButton:"account-options-menu-button",accountMenuButton:"account-menu-icon",accountCell:"multichain-account-cell-entropy",openNetworkSelectorButton:"sort-by-networks",accountAddressesButton:"networks-subtitle-test-id",accountAddressesElements:"multichain-address-row",accountAddressQRCode:"multichain-address-row-qr-button"},S={lockButton:"global-menu-lock",networksButton:"global-menu-networks",networksPageList:"networks-page-list",headerBackButton:"settings-header-back-button"},O={passwordInput:"unlock-password",unlockButton:"unlock-submit"},C={accountOptionsMenuButton:"multichain-account-cell-end-accessory",accountDetailsLabel:"Account details",renameAccountLabel:"Rename",addressesLabel:"Addresses",pinToTopLabel:"Pin to top",hideAccountLabel:"Hide account",backButton:"back",addMultichainAccountButton:"add-multichain-account-button",addWalletButton:"account-list-add-wallet-button",importWalletButton:"choose-wallet-type-import-wallet",importAccountButton:"choose-wallet-type-import-account"};var g={createWalletButton:"onboarding-create-wallet",importWalletButton:"onboarding-import-wallet",useSecretRecoveryPhraseButton:"onboarding-create-with-srp-button",createNewPasswordInput:"create-password-new-input",confirmNewPasswordInput:"create-password-confirm-input",confirmPasswordCheckbox:"create-password-terms",createPasswordButton:"create-password-submit",revealSecretRecoveryPhraseButton:"recovery-phrase-reveal",recoveryPhraseRemindMeLaterButton:"recovery-phrase-remind-later",metamaskMetricsIAgreeButton:"metametrics-i-agree",onboardingDoneButton:"onboarding-complete-done",importUsingSecretRecoveryPhraseButton:"onboarding-import-with-srp-button",secretRecoveryPhraseTextAreaInput:"srp-input-import__srp-note",importWalletConfirmButton:"import-srp-confirm",importAccountConfirmButton:"import-account-confirm-button",importSRPError:"bannerAlert"};async function mt({page:t,privateKey:e,accountName:o}){let n=ut.string().min(1,"Account name cannot be an empty string").trim().parse(o),r=ut.string().min(1,"Private key cannot be an empty string").trim().parse(e),i=t.getByTestId(w.accountMenuButton);await B(i).toBeVisible({timeout:3e4}),await i.click(),await B(t.getByRole("heading",{name:/accounts/i})).toBeVisible();let s=t.getByTestId(C.addWalletButton),c=await s.textContent();c?.includes("Syncing")&&await B.poll(async()=>(await s.textContent())?.trim()??"",{timeout:12e4}).not.toBe(c),await B(s).toBeEnabled({timeout:6e4}),await s.click();let a=t.getByTestId("multichain-page");await B(a).toContainText(/add a wallet/i),await t.getByTestId(C.importAccountButton).click(),await t.locator("input[id='private-key-box']").fill(r);let m=t.getByTestId(g.importAccountConfirmButton);await B(m).toBeEnabled(),await m.click();let f=t.getByTestId(g.importSRPError),k=await f.isVisible().catch(()=>!1);k&&dt(k,`${(await f.textContent())?.split(".")[0]}`),await t.locator("button[aria-label='Back']").first().click();let A=t.locator("div[data-testid^='multichain-account-cell-keyring'][class*='is-selected']"),h=await A.locator("p[class*='multichain-account-cell__account-name']").textContent();h&&await $t({page:t,accountName:n,activeAccountLocator:A,activeAccountName:h}),await t.locator("button[aria-label='Back']").first().click()}async function $t({page:t,accountName:e,activeAccountLocator:o,activeAccountName:n}){let r=o.locator(`div[aria-label='${n} options']`);await B(r).toBeVisible(),await r.click(),await B(t.getByRole("tooltip")).toBeVisible();let i=t.locator(`div[aria-label='${C.renameAccountLabel}']`);await B(i).toBeVisible(),await i.click();let s=t.getByRole("dialog"),c=s.getByRole("heading",{name:/rename/i});await B(c).toBeVisible();let a=s.getByRole("textbox");await B(a).toBeVisible(),await a.fill(e);let p=s.getByRole("button",{name:/confirm/i});await B(p).toBeEnabled(),await p.click(),await s.waitFor({state:"detached",timeout:2e4});let l=t.locator("div[data-testid^='multichain-account-cell-keyring'][class*='is-selected']");await B(l).toContainText(e)}import{expect as wt}from"@playwright/test";import M from"zod";var pt=M.object({networkName:M.string().min(1,"Network name cannot be an empty string"),rpcUrl:M.url(),chainId:M.number().or(M.string().includes("0x")),currencySymbol:M.string().toUpperCase().min(1,"Currency symbol cannot be an empty string")});import{expect as Ht}from"@playwright/test";async function z(t){let e=t.locator("div:has(> p[data-testid='notifications-tag-counter__unread-dot'])"),o=t.getByTestId(w.openSettingsButton);await e.isVisible().catch(()=>!1)?await e.click():(await Ht(o).toBeVisible(),await o.click())}async function ft({page:t,...e}){let{chainId:o,currencySymbol:n,networkName:r,rpcUrl:i}=pt.parse({...e},{reportInput:!0});await z(t),await t.getByTestId(S.networksButton).click();let c=t.getByTestId(S.networksPageList);await wt(c).toContainText(/networks/i),await t.getByRole("button",{name:/add a custom network/i}).click();let p=t.getByTestId("network-form-network-name"),l=t.getByTestId("test-add-rpc-drop-down"),m=t.getByTestId("network-form-chain-id"),f=t.getByTestId("network-form-ticker-input");await p.fill(r),await l.click(),await t.getByRole("tooltip").locator("div:has(> button:has-text('Add RPC URL'))").click();let A=t.getByTestId("rpc-url-input-test"),h=t.getByRole("button",{name:/Add URL/i});await A.fill(i),await h.click();let y=t.getByTestId("network-form-chain-id-error");if(await y.isVisible().catch(()=>!1)){let _=await y.textContent();throw Error(`RPC error: ${_}`)}await m.fill(`${o}`),await f.fill(n);let P=t.getByRole("button",{name:/save/i});await wt(P).toBeEnabled(),await P.click(),await t.getByTestId(S.headerBackButton).click()}import{expect as gt}from"@playwright/test";function L(t){return new Promise(e=>setTimeout(e,t))}var K={confirmButton:"confirm-footer-button",cancelButton:"confirm-footer-cancel-button"};async function yt(t,e){let o=t.getByTestId(K.confirmButton);await L(2e3);let r=(await o.textContent())?.includes("Review alert"),i=await o.isDisabled().catch(()=>!1);if(r&&i){await t.getByTestId("edit-gas-fees-row").locator("> div").first().click();let l=t.getByRole("dialog");await gt(l).toBeVisible();let m=l.locator("h4",{hasText:"Insufficient funds"}),f=await l.getByTestId("alert-modal__selected-alert").textContent();if(await m.isVisible().catch(()=>!1))throw Error(`${f}`)}if(e){let a=t.getByTestId("edit-gas-fee-icon");if(await a.scrollIntoViewIfNeeded(),await a.click(),e.feeType!=="advanced"&&await t.getByTestId(`gas-option-${e.feeType}`).click(),e.feeType==="advanced"){await t.getByTestId("gas-option-advanced").click();let l=t.getByRole("textbox",{name:"Max base fee"}),m=t.getByRole("textbox",{name:"Priority fee"}),f=t.getByRole("button",{name:"Save",exact:!0});await l.fill(e.maxBaseFee),await m.fill(e.priorityFee),await f.click()}}await gt(o).toBeEnabled(),await o.click();let s=t.getByRole("dialog");await s.isVisible().catch(()=>!1)&&await s.locator("h4",{hasText:"Your assets may be at risk"}).isVisible().catch(()=>!1)&&(await s.getByTestId("alert-modal-acknowledge-checkbox").click(),await s.getByTestId("confirm-alert-modal-submit-button").click()),await t.waitForEvent("close",{timeout:15e3})}import{expect as Gt}from"@playwright/test";async function ht(t){let e=t.getByRole("button",{name:"Connect",exact:!0});await e.waitFor({state:"visible",timeout:25e3}),await t.getByRole("button",{name:"Edit accounts"}).click();let n=t.getByTestId("modal-page");await n.waitFor({state:"visible",timeout:25e3});let r=await t.locator("[data-testid^='multichain-account-cell-entropy:']").all();for(let p of r)await p.locator("input[type='checkbox']").isChecked().catch(()=>!1)||await p.click();await n.getByTestId("connect-more-accounts-button").click(),await e.click(),await t.getByRole("heading",{name:"Connecting",exact:!0}).waitFor({state:"detached",timeout:3e4});let c;await Gt.poll(async()=>(c=await t.locator("div[class='permissions-connect']").isVisible().catch(()=>!1),c),{timeout:25e3}).toBe(!0).catch(()=>console.error("Notice dialog did not appear within the timeout period."));let a=t.getByTestId("page-container-footer-next");await a.waitFor({state:"visible",timeout:25e3}),await a.click(),await t.waitForEvent("close",{predicate:()=>!0,timeout:25e3}).catch(()=>console.error("Extension popup did not close within the timeout period when connecting to the DApp."))}async function xt(t,e){await t.getByTestId(w.accountAddressesButton).hover(),await t.getByTestId("multichain-address-rows-list").getByRole("button",{name:/view all/i}).click(),await t.getByRole("searchbox",{name:/search networks/i}).fill(e),await t.locator(`div[data-testid='${w.accountAddressesElements}']:has-text('${e}')`).getByTestId(w.accountAddressQRCode).click();let l=await t.getByRole("dialog").locator("div > p[data-testid='account-address']").textContent();if(!l)throw new Error("Account address not found");return await t.getByLabel("Close",{exact:!0}).click(),await t.getByTestId("multichain-account-address-list-page-back-button").click(),l}import{expect as qt}from"@playwright/test";import{errors as zt}from"@playwright/test";async function R(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}var Bt={loadingOverlay:"loading-overlay",loadingSpinner:"spinner loading-overlay__spinner"};var Kt=6e4,jt=async(t,e,o)=>{await R(e);try{await e.locator(`div[class="${t}"]`).waitFor({state:"detached",timeout:o})}catch(n){if(n instanceof zt.TimeoutError)console.info(`Loading indicator '${t}' not found - continuing.`);else throw console.error(`Error while waiting for loading indicator '${t}' to disappear`),n}},j=async t=>{try{await jt(Bt.loadingSpinner,t,Kt)}catch(e){console.warn("Warning during MetaMask load:",e)}return await L(300),t};async function kt(t){if(await t.getByTestId(O.unlockButton).isVisible().catch(()=>!1)){console.info("\u{1F4A1} Wallet is already locked");return}await z(t);let n=t.getByTestId(S.lockButton);await qt(n).toBeVisible(),await n.click(),await j(t)}import{styleText as Pt}from"util";import{expect as D}from"@playwright/test";import bt from"fs";import Xt from"path";async function q(t){let e=x(t),o=Xt.resolve(e,"password.txt");try{if(!bt.existsSync(o))throw new Error("\u274C password.txt not found. Run setup script first.");return bt.readFileSync(o,"utf-8")}catch(n){throw new Error(`\u274C Failed to get ${t} password from cache: ${n.message}`)}}import{expect as Qt}from"@playwright/test";async function At({context:t,path:e,locator:o}){let n;try{await Qt.poll(async()=>(n=t.pages().filter(r=>r.url().startsWith("chrome-extension://")).find(r=>r.url().match(e)),!!n),{timeout:3e4}).toBe(!0)}catch{let r=t.pages().filter(i=>i.url().startsWith("chrome-extension://")).map(i=>i.url());throw new Error(`Popup page with path "${e}" not found in context after 30s. Pages in context: ${JSON.stringify(r)}`)}if(!n)throw new Error(`Popup page with path ${e} not found in context.`);return await Jt(n,o),await n.setViewportSize({width:360,height:592}),n}async function Jt(t,e){await t.waitForLoadState("load",{timeout:4e4}),await t.waitForLoadState("domcontentloaded",{timeout:4e4}),await t.locator(e).first().waitFor({state:"attached",timeout:4e4})}import Tt from"fs";import Yt from"path";async function Ct(t){let e=x(t),o=Yt.resolve(e,"extension-id.txt");try{if(!Tt.existsSync(o))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return Tt.readFileSync(o,"utf-8")}catch(n){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${n.message}`)}}var T=class{name="metamask";onboardingPath="/home.html#onboarding";async indexUrl(){return`chrome-extension://${await this.extensionId()}/home.html`}async promptUrl(){return`chrome-extension://${await this.extensionId()}/notification.html`}async extensionId(){return await Ct(this.name)}async promptPage(e){let o=await this.promptUrl();return await At({context:e,path:o,locator:"div[data-testid='multichain-page']"})}};import{expect as J}from"@playwright/test";async function X({page:t,accountName:e}){let o=t.getByTestId(w.accountMenuButton);if(await o.textContent()===e){console.info(`Can't switch account to "${e}", it is already selected.`);return}await J(o).toBeVisible({timeout:15e3}),await o.click(),await J(t.getByRole("heading",{name:/accounts/i})).toBeVisible();let r=t.getByTestId(C.addMultichainAccountButton),i=await r.textContent();i?.includes("Syncing")&&await J.poll(async()=>(await r.textContent())?.trim()??"",{timeout:6e4}).not.toBe(i);let s=await t.getByTestId(/^multichain-account-cell-(?:entropy|keyring):/).all(),c=null;for(let a of s)if(await a.scrollIntoViewIfNeeded(),(await a.textContent())?.includes(e)){c=a;break}if(!c)throw Error(`Account with name "${e}" not found.`);await c?.click()}import{expect as Y}from"@playwright/test";async function W({page:t}){await t.locator(`div:has(> button[data-testid='${w.openSettingsButton}'])`).click(),await t.getByTestId(S.networksButton).click();let n=t.getByTestId("networks-page-list");await Y(n).toBeVisible(),await Y(n).toContainText(/networks/i);let r="div:has(> p:has-text('Show test networks'))";await n.locator(r).scrollIntoViewIfNeeded();let i=n.locator(r),s=await i.locator("label[class='toggle-button toggle-button--off']").isVisible().catch(()=>!1),c=t.getByTestId("settings-header-back-button"),a=t.getByTestId("drawer-close-button");if(!s){await c.click(),await a.click(),console.info("Testnet networks are already visible.");return}await i.locator("label[class='toggle-button toggle-button--off']").click(),await t.getByTestId("Sepolia").scrollIntoViewIfNeeded(),await Y(t.getByTestId("Sepolia")).toBeVisible(),await c.click(),await a.click()}async function Z({page:t,mainAccountName:e,...o}){console.info(Pt("yellowBright",`
|
|
3
|
+
\u{1F98A} MetaMask onboarding started...`,{validateStream:!1}));let n=await q("metamask"),r=new T,i=t.locator("img[class='loading-spinner']"),s=t.getByTestId(g.createWalletButton),c=t.getByTestId(g.importWalletButton),a=t.getByTestId(g.createNewPasswordInput),p=t.getByTestId(g.confirmNewPasswordInput),l=t.getByTestId(g.confirmPasswordCheckbox),m=t.getByTestId(g.createPasswordButton),f=t.getByTestId(g.metamaskMetricsIAgreeButton),k=t.getByTestId(g.onboardingDoneButton);if(await i.waitFor({state:"detached",timeout:3e4}),o.mode==="create"){let P=t.getByTestId(g.useSecretRecoveryPhraseButton);await s.click(),await P.click(),await a.fill(n),await p.fill(n),await l.click(),await m.click(),await t.getByTestId(g.revealSecretRecoveryPhraseButton).click(),await t.getByTestId(g.recoveryPhraseRemindMeLaterButton).click(),await f.click()}if(o.mode==="import"){let{secretRecoveryPhrase:P}=o,I=P.split(" "),_=t.getByTestId(g.importUsingSecretRecoveryPhraseButton);await c.click(),await _.click();let nt=t.getByTestId(g.secretRecoveryPhraseTextAreaInput);await nt.fill(I[0]),await nt.press("Space");for(let G=1;G<I.length;G++){let at=t.getByTestId(`import-srp__srp-word-${G}`);await at.fill(I[G]),await at.press("Space")}await t.getByTestId(g.importWalletConfirmButton).click(),await a.fill(n),await p.fill(n),await l.click(),await m.click(),await t.getByTestId("passkey-maybe-later-button").click(),await f.click();let Mt=t.getByTestId("wallet-ready");await D(Mt).toContainText(/your wallet is ready/i)}await k.click();let A=`chrome-extension://${await r.extensionId()}/sidepanel.html`,y=await t.context().browser()?.newBrowserCDPSession(),N;await D.poll(async()=>{if(y){let{targetInfos:P}=await y.send("Target.getTargets"),I=P.find(_=>_.url===A);return N=I,!!I}},{timeout:15e3}).toBe(!0),N&&await y?.send("Target.closeTarget",{targetId:N.targetId}),await t.goto(await r.indexUrl()),await i.waitFor({state:"detached",timeout:3e4}),await D(t.getByTestId(w.buyButton)).toBeVisible(),await D(t.getByTestId(w.swapButton)).toBeVisible(),await D(t.getByTestId(w.sendButton)).toBeVisible(),await D(t.getByTestId(w.receiveButton)).toBeVisible(),await W({page:t}),e&&await X({page:t,accountName:e}),await L(5e3),console.info(Pt("greenBright","\u2728 MetaMask onboarding completed successfully",{validateStream:!1}))}import{expect as Zt}from"@playwright/test";async function It(t){let e=t.getByTestId(K.cancelButton);await Zt(e).toBeEnabled(),await e.click()}import{expect as b}from"@playwright/test";async function St({page:t,currentAccountName:e,newAccountName:o}){let n=t.getByTestId(w.accountMenuButton);if(await n.textContent()===o)throw Error(`The account to be renamed "${o}" already exists.`);await b(n).toBeVisible({timeout:15e3}),await n.click(),await b(t.getByRole("heading",{name:/accounts/i})).toBeVisible();let i=t.getByTestId(C.addMultichainAccountButton),s=await i.textContent();s?.includes("Syncing")&&await b.poll(async()=>(await i.textContent())?.trim()??"",{timeout:6e4}).not.toBe(s);let c=await t.getByTestId(/^multichain-account-cell/).all(),a=null;for(let y of c)if((await y.textContent())?.includes(e)){a=y;break}if(!a)throw Error(`Account with name "${e}" not found.`);if((await a.textContent())?.split("$")[0]===o)throw Error(`The new account name "${o}" is the same as the old account name "${e}".`);let l=t.locator(`div[aria-label='${e} options']`);await b(l).toBeVisible(),await l.click(),await b(t.getByRole("tooltip")).toBeVisible();let m=t.locator(`div[aria-label='${C.renameAccountLabel}']`);await b(m).toBeVisible(),await m.click();let f=t.getByRole("dialog"),k=f.getByRole("heading",{name:/rename/i});await b(k).toBeVisible();let E=f.getByRole("textbox");await b(E).toBeVisible(),await E.fill(o);let A=f.getByRole("button",{name:/confirm/i});await b(A).toBeEnabled(),await A.click();for(let y of c)if((await y.textContent())?.includes(o)){await b(y).toBeVisible(),await b(y).toContainText(o);break}await t.locator("button[aria-label='Back']").first().click()}import{expect as tt}from"@playwright/test";async function vt({page:t,networkType:e,chainName:o}){let n=t.getByTestId(w.openNetworkSelectorButton);await n.click();let r=t.getByTestId("modal-header-close-button");if(e==="testnet"||e==="custom"){let a=t.getByRole("tab",{name:"Custom"});await a.click(),await t.locator("p:has-text('Testnets')").isVisible().catch(()=>!1)||(await r.click(),await W({page:t}),await n.click(),await a.click());let m=t.locator(`div div[data-testid='${o}']`),f=await m.textContent();tt(f).toBe(o),await m.click();return}await t.getByRole("tab",{name:"Popular"}).click();let s=t.locator(`div div[data-testid='${o}']`),c=await s.textContent();tt(c).toBe(o),await s.click(),await tt(n).toContainText(o,{timeout:3e4})}import{expect as Rt}from"@playwright/test";async function $(t){let e=await q("metamask"),o=t.getByTestId(O.passwordInput);if(await t.getByTestId(w.openNetworkSelectorButton).isVisible().catch(()=>!1)){console.info("\u{1F4A1} Wallet is already unlocked");return}await o.fill(e);let i=t.getByTestId(O.unlockButton);await Rt(i).toBeVisible(),await i.click(),await j(t),await Rt(t.getByTestId(w.buyButton)).toBeVisible({timeout:3e4})}var V=class extends T{page;constructor(e){super(),this.page=e}async onboard(e){await Z({page:this.page,...e})}async unlock(){await $(this.page)}async lock(){await kt(this.page)}async renameAccount({newAccountName:e,currentAccountName:o}){await St({page:this.page,newAccountName:e,currentAccountName:o})}async addAccount({privateKey:e,accountName:o}){await mt({page:this.page,privateKey:e,accountName:o})}async switchAccount({accountName:e}){await X({page:this.page,accountName:e})}async switchNetwork({...e}){await vt({page:this.page,...e})}async getAccountAddress(e){return await xt(this.page,e)}async toggleShowTestnetNetwork(){await W({page:this.page})}async addCustomNetwork({chainId:e,currencySymbol:o,networkName:n,rpcUrl:r}){await ft({page:this.page,chainId:e,currencySymbol:o,networkName:n,rpcUrl:r})}async connectToApp(){await ht(await this.promptPage(this.page.context()))}async confirmTransaction(e){await yt(await this.promptPage(this.page.context()),e)}async rejectTransaction(){await It(await this.promptPage(this.page.context()))}};import Nt from"fs";import ne from"path";import{test as ae,chromium as re}from"@playwright/test";import{Instance as ie,Pool as se}from"prool";import{expect as te}from"@playwright/test";async function et(t,e){let o=await t.newPage();return await te(async()=>{await o.goto(e),await R(o)}).toPass(),o}async function ot(t,e){let o=await e.newPage();for(let{origin:n,localStorage:r}of t){let i=o.mainFrame();await i.goto(n),await i.evaluate(s=>{s.forEach(({name:c,value:a})=>{window.localStorage.setItem(c,a)})},r)}await o.close()}import ee from"fs/promises";async function Et(t){await ee.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var oe=35e3;async function Q(t,e){try{await Promise.race([t.close(),new Promise((o,n)=>setTimeout(()=>n(new Error("Context close timed out")),oe))])}catch(o){console.warn(`Browser context close did not complete cleanly: ${o.message}`)}try{await Et(e)}catch(o){console.error(`Failed to remove temporary context directory at ${e}. Error:`,o)}}var H,Va=({slowMo:t=0,profileName:e}={})=>ae.extend({contextPath:async({browserName:o},n,r)=>{let i=await v(`${o}-${r.testId}`);await n(i)},context:async({context:o,contextPath:n},r)=>{let i=new T,s=x(i.name),c=await F(i.name),a=ne.resolve(s,e??"wallet-data");if(!Nt.existsSync(a))throw new Error("\u274C Cache for MetaMask wallet data not found. Create it first");Nt.cpSync(a,n,{recursive:!0,force:!0});let p=[`--disable-extensions-except=${c}`,`--load-extension=${c}`];process.env.HEADLESS&&(p.push("--headless=new"),t>0&&console.warn("\u26A0\uFE0F Slow motion makes no sense in headless mode. It will be ignored!"));let l=await re.launchPersistentContext(n,{headless:!1,args:[`--disable-extensions-except=${c}`],slowMo:process.env.HEADLESS?0:t}),{cookies:m,origins:f}=await o.storageState();m&&await l.addCookies(m),f&&f.length>0&&ot(f,l);let k=await i.indexUrl();await l.waitForEvent("page",{predicate:h=>h.url().startsWith(k),timeout:3e4}),H=l.pages().find(h=>h.url().startsWith(k))??await et(l,k);for(let h of l.pages())h.url().includes("about:blank")&&await h.close();await H.locator("img[class='loading-spinner']").waitFor({state:"detached"}),await $(H),await r(l),await Q(l,n)},metamaskPage:async({context:o},n)=>{await n(H)},metamask:async({context:o},n)=>{let r=new V(H);await n(r)},createAnvilNode:async({context:o},n,r)=>{let i=r.workerIndex,s;await n(async c=>{s=se.define({instance:ie.anvil(c)});let a=await s.start(i),p=`http://${a.host}:${a.port}`,m=c?.chainId??31337;return{rpcUrl:p,anvil:a,chainId:m}}),s&&await s.stop(i)},connectToAnvil:async({context:o,metamask:n,createAnvilNode:r},i)=>{await i(async()=>{let{chainId:s,rpcUrl:c}=await r({chainId:2251});await n.addCustomNetwork({chainId:s,currencySymbol:"ETH",networkName:"Anvil Localnet",rpcUrl:c})})}});import{test as de}from"@playwright/test";import{Instance as ue,Pool as me}from"prool";import _t from"fs";import ce from"path";import{chromium as le}from"@playwright/test";async function Ft({workerInfo:t,profileName:e,slowMo:o}){let n=new T,r=await v(t.workerIndex.toString()),i=x(n.name),s=ce.resolve(i,e??"wallet-data");if(!_t.existsSync(s))throw new Error(`Cache for ${n.name} does not exist. Create it first!`);_t.cpSync(s,r,{recursive:!0,force:!0});let c=await F(n.name),a=await le.launchPersistentContext(r,{headless:!1,args:[`--disable-extensions-except=${c}`],slowMo:process.env.HEADLESS?0:o}),p=await n.indexUrl();await a.waitForEvent("page",{predicate:m=>m.url().startsWith(p),timeout:4e4});let l=a.pages().find(m=>m.url().startsWith(p));l||(l=await a.newPage(),await l.goto(p),await R(l));for(let m of a.pages())m.url().includes("about:blank")&&await m.close();return{context:a,walletPage:l,contextPath:r}}var nr=({profileName:t,slowMo:e}={})=>de.extend({workerScopeContents:[async({browser:o},n,r)=>{let{context:i,contextPath:s,walletPage:c}=await Ft({workerInfo:r,profileName:t,slowMo:e});await i.grantPermissions(["clipboard-read"]);let a=new V(c);await a.unlock(),await n({wallet:a,walletPage:c,context:i}),await Q(i,s)},{scope:"worker"}],createAnvilNode:async({context:o},n,r)=>{let i=r.workerIndex,s;await n(async c=>{s=me.define({instance:ue.anvil(c)});let a=await s.start(i),p=`http://${a.host}:${a.port}`,m=c?.chainId??31337;return{rpcUrl:p,anvil:a,chainId:m}}),s&&await s.stop(i)},connectToAnvil:async({context:o,createAnvilNode:n,workerScopeContents:r},i)=>{await i(async()=>{let{wallet:s}=r,{chainId:c,rpcUrl:a}=await n({chainId:2251});await s.addCustomNetwork({chainId:c,currencySymbol:"ETH",networkName:"Anvil Localnet",rpcUrl:a})})}});export{V as Metamask,Va as metamaskFixture,nr as metamaskWorkerScopeFixture,$e as workerScopeContext};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import tt from"fs";import gt from"path";import{chromium as yt}from"@playwright/test";import ft from"path";var Y=".wallet-cache",Q=".wallet-context";var J="13.
|
|
1
|
+
import tt from"fs";import gt from"path";import{chromium as yt}from"@playwright/test";import ft from"path";var Y=".wallet-cache",Q=".wallet-context";var J="13.33.0",v="https://github.com/amaify/chainwright/releases/download/v0.1.0/",Rt=`https://github.com/MetaMask/metamask-extension/releases/download/v${J}/metamask-chrome-${J}.zip`,Ut=`${v}solflare-wallet-extension-v2.19.1.zip`,$t=`${v}petra-wallet-extension-v2.4.8.zip`,Vt=`${v}phantom-wallet-extension-v26.10.0.zip`,Kt=`${v}meteor-wallet-extension-v0.7.0.zip`,Ht=`${v}keplr-wallet-extension-v0.13.3.zip`;async function E(t){return ft.resolve(process.cwd(),Q,t)}import ht from"path";function f(t){return ht.resolve(process.cwd(),Y,t)}import Z from"fs";import xt from"path";async function N(t){try{let o=f(t),e=xt.resolve(o,"extension-path.txt");if(!Z.existsSync(e))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let r=Z.readFileSync(e,"utf-8").trim();if(!r)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return r}catch(o){throw new Error(`\u274C Failed to get ${t} extension path: ${o.message}`)}}async function ot({wallet:t,workerInfo:o,profileName:e,slowMo:r}){let i=await E(o.workerIndex.toString()),c=f(t.name),u=gt.resolve(c,e??"wallet-data");if(!tt.existsSync(u))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);tt.cpSync(u,i,{recursive:!0,force:!0});let p=await N(t.name),l=await yt.launchPersistentContext(i,{headless:!1,args:[`--disable-extensions-except=${p}`],slowMo:process.env.HEADLESS?0:r}),s=await t.indexUrl(),w=l.pages()[0];return w||(w=await l.newPage()),await w.goto(s),{context:l,walletPage:w,contextPath:i}}var m={openSidebarMenuButton:"button[aria-label='open sidebar']",addWalletButton:"button:has-text('Add Wallet')",settingsButton:"button:has-text('Settings')",settingsMenuBackButton:"button[aria-label='Back']"};var d={importExistingWalletButton:'button:has-text("Import an existing wallet")',switchNetworkButton:"button[id^='menu-button']",privateKeyButton:"button:has-text('Private Key')",findMyAccountButton:"button:has-text('Find my account')"};async function _(t,o,e){let r=t.locator(d.switchNetworkButton).last();await r.scrollIntoViewIfNeeded();let i=await r.textContent(),c=o.split("net")[0]?.toLowerCase()??"";if(i?.toLowerCase()===c)return console.info(`
|
|
2
2
|
Already on ${o}, no need to switch network.`),"Exit";await r.click();let p=t.locator(e).last().locator(`> button:has-text('${o}')`);await p.click(),await t.locator("div > h2:has-text('Meteor Community')").isVisible().catch(()=>!1)&&await p.click()}async function P({page:t,newAccountName:o}){await t.locator(m.openSidebarMenuButton).click(),await t.locator("div:has(> h2):has(> svg)").click();let i=t.locator("input[placeholder='Ex. My Meteor Wallet']"),c=t.locator("button[type='submit']:has-text('Update')");await i.fill(o),await c.click(),await t.locator("div[id='root'] button[aria-label='Close']").click()}async function F({page:t,privateKey:o,accountName:e,network:r}){await t.locator(m.openSidebarMenuButton).click(),await t.locator(m.addWalletButton).click(),await _(t,r,"section[role='dialog'] div[role='menu']"),await t.locator(d.importExistingWalletButton).click(),await t.locator(d.privateKeyButton).click();let l=t.locator('button:has-text("Continue")');await l.scrollIntoViewIfNeeded(),await l.click(),await t.locator("textarea:not([disabled])").fill(o),await t.locator(d.findMyAccountButton).click(),await t.locator("button[type='submit'][data-loading]").waitFor({state:"detached",timeout:25e3}),await t.locator("button:not([aria-label='Back'],[id^='menu-button']):has-text('Account')").click(),await P({page:t,newAccountName:e})}var A={approveButton:"button:has-text('Approve')",connectButton:"button:has-text('Connect')",cancelButton:"button:has-text('Cancel')"};import et from"fs";import bt from"path";async function I(t){let o=f(t),e=bt.resolve(o,"password.txt");try{if(!et.existsSync(e))throw new Error("\u274C password.txt not found. Run setup script first.");return et.readFileSync(e,"utf-8")}catch(r){throw new Error(`\u274C Failed to get ${t} password from cache: ${r.message}`)}}async function h(t){let o=await I("meteor"),e=t.locator("input[placeholder='Enter Password']"),r=t.locator('button:has-text("Unlock")');await e.fill(o),await r.click()}async function rt(t){await h(t),await t.locator(A.approveButton).click(),await t.locator("h2:has-text('Executing Transaction')").waitFor({state:"attached"}),await t.waitForEvent("close",{timeout:15e3})}async function k(t,o){if((await t.locator("div:has(button[type='button'][aria-label='open sidebar'])").nth(-2).locator("div:has(div > h2)").locator("div > h2").textContent())?.toLowerCase()===o.toLowerCase()){console.info(`
|
|
3
3
|
Switching to the ${o} account aborted. Account is already selected.`);return}await t.locator(m.openSidebarMenuButton).click();let l=await t.locator("div:has(div > button[type='button'][aria-label='Close'])").nth(-2).locator("div").nth(2).locator("> div").nth(1).locator("div").nth(1).locator("div > h2").all(),s=null;for(let w of l)if((await w.textContent())?.toLowerCase()===o.toLowerCase()){s=w;break}if(!s)throw new Error(`Account with name "${o}" not found.`);await s.click()}async function at(t,o){await h(t),o&&await k(t,o);let e=t.getByRole("heading",{name:"Connect Request",exact:!0});await Promise.all([t.locator(A.connectButton).click(),e.waitFor({state:"detached",timeout:3e4})])}async function nt(t){return await t.locator("div:has(button[type='button'][aria-label='open sidebar'])").nth(-2).locator("div:has(div > h2)").locator("div > svg").click(),await t.evaluate(async()=>await navigator.clipboard.readText())}async function it(t){await t.locator(m.openSidebarMenuButton).click(),await t.locator("button:has-text('Lock Wallet')").click()}import{styleText as O}from"util";function T(t){return new Promise(o=>setTimeout(o,t))}import{expect as Pt}from"@playwright/test";async function ct({context:t,path:o,locator:e}){let r;try{await Pt.poll(async()=>(r=t.pages().filter(i=>i.url().startsWith("chrome-extension://")).find(i=>i.url().match(o)),!!r),{timeout:3e4}).toBe(!0)}catch{let i=t.pages().filter(c=>c.url().startsWith("chrome-extension://")).map(c=>c.url());throw new Error(`Popup page with path "${o}" not found in context after 30s. Pages in context: ${JSON.stringify(i)}`)}if(!r)throw new Error(`Popup page with path ${o} not found in context.`);return await At(r,e),await r.setViewportSize({width:360,height:592}),r}async function At(t,o){await t.waitForLoadState("load",{timeout:4e4}),await t.waitForLoadState("domcontentloaded",{timeout:4e4}),await t.locator(o).first().waitFor({state:"attached",timeout:4e4})}import st from"fs";import kt from"path";async function lt(t){let o=f(t),e=kt.resolve(o,"extension-id.txt");try{if(!st.existsSync(e))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return st.readFileSync(e,"utf-8")}catch(r){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${r.message}`)}}var x=class{name="meteor";onboardingPath="ext_index_popup.html";async indexUrl(){return`chrome-extension://${await this.extensionId()}/ext_index_popup.html`}async promptUrl(){return`chrome-extension://${await this.extensionId()}/ext_index.html`}async extensionId(){return await lt(this.name)}async promptPage(o){let e=await this.promptUrl();return await ct({context:o,path:e,locator:"div[id='root']"})}};async function B(t){await t.locator(m.openSidebarMenuButton).click(),await t.locator(m.settingsButton).click()}async function L(t,o){if(await B(t),await _(t,o,"div[role='menu']")==="Exit"){let c=t.locator(m.settingsMenuBackButton);await c.scrollIntoViewIfNeeded(),await c.click();return}let r=t.locator("p:has-text('Available Balance')");if(await T(1e3),!await r.isVisible().catch(()=>!1))throw new Error([`There is no associated account for the ${o} network in your wallet.`,`Please add an account to the ${o} network in your wallet using the "addAccount" method.`,"NOTE: For the account to be persisted across tests, do this when onboarding the wallet."].join(`
|
|
4
4
|
`))}async function R({page:t,privateKey:o,network:e,accountName:r,additionalAccounts:i}){console.info(O("yellowBright",`
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import J from"fs";import yt from"path";import{chromium as gt}from"@playwright/test";import ft from"path";var G=".wallet-cache",X=".wallet-context";var j="13.
|
|
1
|
+
import J from"fs";import yt from"path";import{chromium as gt}from"@playwright/test";import ft from"path";var G=".wallet-cache",X=".wallet-context";var j="13.33.0",W="https://github.com/amaify/chainwright/releases/download/v0.1.0/",Nt=`https://github.com/MetaMask/metamask-extension/releases/download/v${j}/metamask-chrome-${j}.zip`,Rt=`${W}solflare-wallet-extension-v2.19.1.zip`,Ut=`${W}petra-wallet-extension-v2.4.8.zip`,$t=`${W}phantom-wallet-extension-v26.10.0.zip`,Vt=`${W}meteor-wallet-extension-v0.7.0.zip`,Kt=`${W}keplr-wallet-extension-v0.13.3.zip`;async function I(t){return ft.resolve(process.cwd(),X,t)}import xt from"path";function x(t){return xt.resolve(process.cwd(),G,t)}import Z from"fs";import ht from"path";async function O(t){try{let o=x(t),e=ht.resolve(o,"extension-path.txt");if(!Z.existsSync(e))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let r=Z.readFileSync(e,"utf-8").trim();if(!r)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return r}catch(o){throw new Error(`\u274C Failed to get ${t} extension path: ${o.message}`)}}async function Y({wallet:t,workerInfo:o,profileName:e,slowMo:r}){let a=await I(o.workerIndex.toString()),c=x(t.name),s=yt.resolve(c,e??"wallet-data");if(!J.existsSync(s))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);J.cpSync(s,a,{recursive:!0,force:!0});let p=await O(t.name),u=await gt.launchPersistentContext(a,{headless:!1,args:[`--disable-extensions-except=${p}`],slowMo:process.env.HEADLESS?0:r}),d=await t.indexUrl(),l=u.pages()[0];return l||(l=await u.newPage()),await l.goto(d),{context:u,walletPage:l,contextPath:a}}import Bt from"zod";var m={depositButton:"button:has-text('Deposit')",sendButton:"button:has-text('Send')",receiveButton:"button:has-text('Receive')",settingsMenu:"button[aria-label='Settings']",lockButton:"global-menu-lock",accountMenuButton:"button[data-part='trigger']",accountDialog:"div[role='dialog']",backButton:"button[id='back-button']"},$={networkSection:"a[href='/settings/network']",backButton:"button[id='back-button']"},V={passwordInput:"input[name='password']",unlockButton:"button:has-text('Unlock')"},h={accountOptionsMenuButton:"button[data-scope='popover']",editAccountButton:"button[aria-label='Edit account name']",renameAccountInput:"input[name='name']",saveButton:"button:has-text('Save')",cancelButton:"button:has-text('Cancel')",addAccountButton:"button:has-text('Add accounts')",addAccountWithPrivateKeyButton:"button:has-text('Import private key')",addAccountWithMnemonicButton:"button:has-text('Import mnemonic')"};var w={createWalletButton:"button:has-text('Create an account')",createSeedPhraseButton:"button:has-text('Create a seed phrase wallet')",createNewPasswordInput:"input[name='password']",confirmNewPasswordInput:"input[name='confirmPassword']",confirmPasswordCheckbox:"label>div[data-scope='checkbox']",continueButton:"button:has-text('Continue')",skipCopyRecoveryPhraseButton:"button:has-text('Skip')",getStartedButton:"button:has-text('Get started')",onboardingCompleteText:"h1:has-text('Your wallet is ready, you may close this window')",importWalletButton:"button:has-text('Import an account')",importUsingPrivateKeyButton:"button:has-text('Import private key')",importUsingMnemonicButton:"button:has-text('Import mnemonic')",importButton:"button:has-text('Import')",privateKeyInput:"input[name='privateKey']"};import{expect as _}from"@playwright/test";import Pt from"zod";async function A({page:t,newAccountName:o}){let e=Pt.string().min(1,"Account name cannot be an empty string").parse(o);await t.locator(m.settingsMenu).click(),await _(t.getByText("Settings").first()).toBeVisible();let a=t.locator(h.editAccountButton);await _(a).toBeVisible(),await a.click(),await _(t.getByText("Account name").first()).toBeVisible();let c=t.locator(h.renameAccountInput);if(await c.getAttribute("value")===e)throw Error(`The account to be renamed "${e}" already exists.`);await c.fill(e);let p=t.locator(h.saveButton);await _(p).toBeEnabled(),await p.click(),await _(t.getByText(e).first()).toBeVisible(),await t.locator(m.backButton).click(),await Promise.allSettled([t.locator(m.depositButton).waitFor({state:"visible",timeout:2e4}),t.locator(m.sendButton).waitFor({state:"visible",timeout:2e4})])}async function L({page:t,accountName:o,mode:e,...r}){let a=Bt.string().max(14,"For switching accounts reason, account name should not be longer than 14 characters. The reason for this is because the name will be truncated. Hence, it will be difficult to select the account.").parse(o);if(await t.locator(h.accountOptionsMenuButton).first().click(),await t.getByRole("dialog").locator(h.addAccountButton).click(),e==="privateKey"){let u="privateKey"in r?r.privateKey:"";if(await t.locator(h.addAccountWithPrivateKeyButton).click(),await t.locator(w.privateKeyInput).fill(u),await t.locator(w.importButton).click(),(await t.getByRole("status").locator("div[data-part='description']",{hasText:"Account already exists in wallet"}).textContent({timeout:3e3}).catch(()=>null))?.includes("Account already exists in wallet"))throw Error(`Account ${a} already exists in wallet`);await A({page:t,newAccountName:a})}if(e==="mnemonic"){let d=("mnemonicPhrase"in r?r.mnemonicPhrase:"").split(" ");await t.locator(h.addAccountWithMnemonicButton).click();for(let[y,v]of d.entries())await t.locator(`input[name="mnemonic-${String.fromCharCode(97+y)}"]`).fill(v);if(await t.locator(w.continueButton).click(),(await t.getByRole("status").locator("div[data-part='description']",{hasText:"Account already exists in wallet"}).textContent({timeout:3e3}).catch(()=>null))?.includes("Account already exists in wallet"))throw Error(`Account ${a} already exists in wallet`);await A({page:t,newAccountName:a})}}function N(t){return new Promise(o=>setTimeout(o,t))}var S={approveButton:'button:has-text("Approve")',cancelButton:'button:has-text("Cancel")'};var bt=/^[A-Z0-9]+(?:_[A-Z0-9]+)+$/;function q(t){return bt.test(t)?t.toLowerCase().replace(/_/g," ").replace(/\b[a-z]/g,o=>o.toUpperCase()):t}async function At(t,o){for(;;){let r=o();if(r||t.isClosed())break;try{let a=t.locator("div:has(> h2:has-text('Simulation error'))");if(await a.isVisible().catch(()=>!1)){let s=await a.locator("p").textContent();throw new Error(`[Confirm Transaction Error]: ${q(s||"Unexpected error!")}`)}}catch(a){if(t.isClosed())break;throw a instanceof Error?a:new Error(`[Confirm Transaction Error]: ${a}`)}if(r||t.isClosed())break;await N(300)}}async function Q(t){let o=!1;At(t,()=>o).catch(async a=>{t.isClosed()||console.error(a.message)}),await t.locator(S.approveButton).click(),o=!0}import{expect as kt}from"@playwright/test";async function C(t,o){let e=t.locator(h.accountOptionsMenuButton).first();if((await e.textContent())?.split("Switch wallet")[1]?.split("0x")[0]?.toLowerCase().trim().includes(o.toLowerCase().trim())){console.info(`
|
|
2
2
|
Switching to ${o} account aborted because the account is already selected.`);return}await e.click();let c=await t.getByRole("dialog").locator("> div > div > button[type='button']").all(),s=null;for(let p of c)if((await p.textContent())?.toLowerCase()?.trim().includes(o.toLowerCase().trim())){s=p;break}if(!s)throw new Error(`Account with name "${o}" not found.`);await s.click()}async function tt(t,o){o&&await C(t,o);let e=t.locator(S.approveButton);await kt(e).toBeEnabled({timeout:2e4}),await e.click()}async function ot(t){return await t.getByRole("button",{name:"Copy Address",exact:!0}).click(),await t.evaluate(async()=>await navigator.clipboard.readText())}import{expect as et}from"@playwright/test";async function rt(t){let o=t.locator(m.settingsMenu);await et(o).toBeVisible(),await o.click(),await et(t.getByText("Settings").first()).toBeVisible()}async function at(t){await rt(t),await t.getByRole("button",{name:/lock wallet/i}).click(),await t.getByRole("heading",{name:/welcome/i}).waitFor({state:"visible",timeout:2e4})}import{styleText as lt}from"util";import{expect as B}from"@playwright/test";async function F(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}import nt from"fs";import St from"path";async function R(t){let o=x(t),e=St.resolve(o,"password.txt");try{if(!nt.existsSync(e))throw new Error("\u274C password.txt not found. Run setup script first.");return nt.readFileSync(e,"utf-8")}catch(r){throw new Error(`\u274C Failed to get ${t} password from cache: ${r.message}`)}}import{expect as Ct}from"@playwright/test";async function it({context:t,path:o,locator:e}){let r;try{await Ct.poll(async()=>(r=t.pages().filter(a=>a.url().startsWith("chrome-extension://")).find(a=>a.url().match(o)),!!r),{timeout:3e4}).toBe(!0)}catch{let a=t.pages().filter(c=>c.url().startsWith("chrome-extension://")).map(c=>c.url());throw new Error(`Popup page with path "${o}" not found in context after 30s. Pages in context: ${JSON.stringify(a)}`)}if(!r)throw new Error(`Popup page with path ${o} not found in context.`);return await Et(r,e),await r.setViewportSize({width:360,height:592}),r}async function Et(t,o){await t.waitForLoadState("load",{timeout:4e4}),await t.waitForLoadState("domcontentloaded",{timeout:4e4}),await t.locator(o).first().waitFor({state:"attached",timeout:4e4})}import ct from"fs";import Tt from"path";async function st(t){let o=x(t),e=Tt.resolve(o,"extension-id.txt");try{if(!ct.existsSync(e))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return ct.readFileSync(e,"utf-8")}catch(r){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${r.message}`)}}var g=class{name="petra";onboardingPath="/onboarding.html";async indexUrl(){return`chrome-extension://${await this.extensionId()}/index.html`}async promptUrl(){return`chrome-extension://${await this.extensionId()}/prompt.html`}async extensionId(){return await st(this.name)}async promptPage(o){let e=await this.promptUrl();return await it({context:o,path:e,locator:"div[id='prompt']"})}};var E=3e4;async function K({page:t,...o}){console.info(lt("yellowBright",`
|
|
3
3
|
Petra onboarding started...`,{validateStream:!1}));let e=new g,r=await R("petra"),a=t.locator(w.createWalletButton),c=t.locator(w.importWalletButton),s=t.locator(w.createNewPasswordInput),p=t.locator(w.confirmNewPasswordInput),u=t.locator(w.confirmPasswordCheckbox),d=t.locator(w.continueButton),l=t.locator(w.getStartedButton),b=t.locator(w.onboardingCompleteText);if(o.mode==="create"){let f=t.locator(w.createSeedPhraseButton);await a.click(),await f.click(),await s.fill(r),await p.fill(r),await u.click(),await d.click(),await t.locator(w.skipCopyRecoveryPhraseButton).click(),await l.click(),await B(b).toBeVisible({timeout:25e3}),await t.goto(await e.indexUrl()),await B(t.locator(m.depositButton)).toBeVisible({timeout:E}),await B(t.locator(m.sendButton)).toBeVisible({timeout:E})}if(o.mode==="importPrivateKey"){let{privateKey:f}=o,P=t.locator(w.importUsingPrivateKeyButton),k=t.locator(w.privateKeyInput),y=t.locator(w.importButton);await c.click(),await P.click(),await k.fill(f),await y.click(),await s.fill(r),await p.fill(r),await u.click(),await d.click(),await l.click(),await B(b).toBeVisible({timeout:25e3}),await t.goto(await e.indexUrl()),await F(t),await B(t.locator(m.depositButton)).toBeVisible({timeout:E}),await B(t.locator(m.sendButton)).toBeVisible({timeout:E})}if(o.mode==="importMnemonic"){let{secretRecoveryPhrase:f}=o,P=t.locator(w.importUsingMnemonicButton);await c.click(),await P.click();for(let[k,y]of f.split(" ").entries())await t.locator(`input[name="mnemonic-${String.fromCharCode(97+k)}"]`).fill(y);await d.click(),await s.fill(r),await p.fill(r),await u.click(),await d.click(),await l.click(),await B(b).toBeVisible({timeout:25e3}),await t.goto(await e.indexUrl()),await B(t.locator(m.depositButton)).toBeVisible({timeout:E}),await B(t.locator(m.sendButton)).toBeVisible({timeout:E})}if(await A({page:t,newAccountName:o.accountName}),o.additionalAccounts&&o.additionalAccounts.length>0){for(let{...f}of o.additionalAccounts)await L({page:t,...f});await C(t,o.accountName)}await N(1500),console.info(lt("greenBright","\u2728 Petra onboarding completed successfully",{validateStream:!1}))}import{expect as vt}from"@playwright/test";async function pt(t){let o=t.locator(S.cancelButton);await vt(o).toBeEnabled(),await o.click()}async function ut(t,o){await t.locator(m.settingsMenu).click(),await t.locator($.networkSection).click(),await t.locator(`div:has(> span:has-text("${o}"))`).first().click();let c=t.locator($.backButton);await c.click(),await c.click()}import{expect as mt}from"@playwright/test";async function M(t){let o=await R("petra"),e=t.locator(V.passwordInput);if(!await e.isVisible().then(()=>!0).catch(()=>!1)){console.info("\u{1F4A1} Wallet is already unlocked");return}await mt(e).toBeVisible({timeout:15e3}),await e.fill(o);let a=t.locator(V.unlockButton);await mt(a).toBeEnabled(),await a.click(),await Promise.allSettled([t.locator(m.sendButton).waitFor({state:"visible",timeout:2e4}),t.locator(m.receiveButton).waitFor({state:"visible",timeout:2e4})])}var T=class extends g{page;constructor(o){super(),this.page=o}async onboard(o){await K({page:this.page,...o})}async unlock(){await M(this.page)}async lock(){await at(this.page)}async renameAccount({newAccountName:o}){await A({page:this.page,newAccountName:o})}async switchNetwork(o){await ut(this.page,o)}async switchAccount(o){await C(this.page,o)}async getAccountAddress(){return await ot(this.page)}async addAccount({accountName:o,...e}){await L({page:this.page,accountName:o,...e})}async connectToApp(o){await tt(await this.promptPage(this.page.context()),o)}async confirmTransaction(){await Q(await this.promptPage(this.page.context()))}async rejectTransaction(){await pt(await this.promptPage(this.page.context()))}};import dt from"fs";import Ft from"path";import{test as Mt,chromium as Dt}from"@playwright/test";import{expect as Wt}from"@playwright/test";async function z(t,o){let e=await t.newPage();return await Wt(async()=>{await e.goto(o),await F(e)}).toPass(),e}async function H(t,o){let e=await o.newPage();for(let{origin:r,localStorage:a}of t){let c=e.mainFrame();await c.goto(r),await c.evaluate(s=>{s.forEach(({name:p,value:u})=>{window.localStorage.setItem(p,u)})},a)}await e.close()}import It from"fs/promises";async function wt(t){await It.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var _t=35e3;async function U(t,o){try{await Promise.race([t.close(),new Promise((e,r)=>setTimeout(()=>r(new Error("Context close timed out")),_t))])}catch(e){console.warn(`Browser context close did not complete cleanly: ${e.message}`)}try{await wt(o)}catch(e){console.error(`Failed to remove temporary context directory at ${o}. Error:`,e)}}var D,Ir=({slowMo:t=0,profileName:o}={})=>Mt.extend({contextPath:async({browserName:e},r,a)=>{let c=await I(`${e}-${a.testId}`);await r(c)},context:async({context:e,contextPath:r},a)=>{let c=new g,s=x(c.name),p=await O(c.name),u=Ft.resolve(s,o??"wallet-data");if(!dt.existsSync(u))throw new Error("\u274C Cache for Petra wallet data not found. Create it first");dt.cpSync(u,r,{recursive:!0,force:!0});let d=[`--disable-extensions-except=${p}`,`--load-extension=${p}`];process.env.HEADLESS&&(d.push("--headless=new"),t>0&&console.warn("\u26A0\uFE0F Slow motion makes no sense in headless mode. It will be ignored!"));let l=await Dt.launchPersistentContext(r,{headless:!1,args:[`--disable-extensions-except=${p}`],slowMo:process.env.HEADLESS?0:t});await l.grantPermissions(["clipboard-read"]);let{cookies:b,origins:f}=await e.storageState();b&&await l.addCookies(b),f&&f.length>0&&H(f,l);let P=await c.indexUrl();D=l.pages().find(y=>y.url().startsWith(P))||await z(l,P);for(let y of l.pages()){let v=y.url();(v.includes("about:blank")||v.includes(c.onboardingPath))&&await y.close()}await D.bringToFront(),await M(D),await a(l),await U(l,r)},petraPage:async({context:e},r)=>{await r(D)},petra:async({context:e},r)=>{let a=new T(D);await r(a)}});import{test as Ot}from"@playwright/test";var Rr=({slowMo:t,profileName:o}={})=>Ot.extend({workerScopeContents:[async({browser:e},r,a)=>{let c=new g,{context:s,contextPath:p,walletPage:u}=await Y({wallet:c,workerInfo:a,profileName:o,slowMo:t});await s.grantPermissions(["clipboard-read"]);for(let l of s.pages())l.url().includes(c.onboardingPath)&&await l.close();let d=new T(u);await d.unlock(),await r({wallet:d,walletPage:u,context:s}),await U(s,p)},{scope:"worker"}]});export{T as Petra,Ir as petraFixture,Rr as petraWorkerScopeFixture,Y as workerScopeContext};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import ot from"fs";import Ct from"path";import{chromium as At}from"@playwright/test";import Bt from"path";var Z=".wallet-cache",tt=".wallet-context";var Y="13.22.0",N="https://github.com/amaify/chainwright/releases/download/v0.1.0/",zt=`https://github.com/MetaMask/metamask-extension/releases/download/v${Y}/metamask-chrome-${Y}.zip`,jt=`${N}solflare-wallet-extension-v2.19.1.zip`,Xt=`${N}petra-wallet-extension-v2.4.8.zip`,Jt=`${N}phantom-wallet-extension-v26.10.0.zip`,qt=`${N}meteor-wallet-extension-v0.7.0.zip`,Qt=`${N}keplr-wallet-extension-v0.13.3.zip`;async function T(t){return Bt.resolve(process.cwd(),tt,t)}import Pt from"path";function x(t){return Pt.resolve(process.cwd(),Z,t)}import et from"fs";import kt from"path";async function I(t){try{let e=x(t),o=kt.resolve(e,"extension-path.txt");if(!et.existsSync(o))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let a=et.readFileSync(o,"utf-8").trim();if(!a)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return a}catch(e){throw new Error(`\u274C Failed to get ${t} extension path: ${e.message}`)}}async function xe({wallet:t,workerInfo:e,profileName:o,slowMo:a}){let n=await T(e.workerIndex.toString()),r=x(t.name),u=Ct.resolve(r,o??"wallet-data");if(!ot.existsSync(u))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);ot.cpSync(u,n,{recursive:!0,force:!0});let i=await I(t.name),m=await At.launchPersistentContext(n,{headless:!1,args:[`--disable-extensions-except=${i}`],slowMo:process.env.HEADLESS?0:a}),l=await t.indexUrl(),h=m.pages()[0];return h||(h=await m.newPage()),await h.goto(l),{context:m,walletPage:h,contextPath:n}}var g={openMenuButton:"settings-menu-open-button",settingsButton:"sidebar_menu-button-settings",addAccountButton:"sidebar_menu-button-add_account",unlockWalletButton:"unlock-form-submit-button",manageAccountsButton:"sidebar_menu-button-manage_accounts",homeHeaderAccountName:"home-header-account-name"},B={lockWalletButton:"lock-menu-item",closeMenuButton:"settings-menu-close-button",developerSettingsButton:"settings-item-developer-settings",activeNetworksButton:"settings-item-active-networks"},at={accountProfileContainer:"sortable-account-container"};var p={createNewWalletButton:"button:has-text('Create a new wallet')",IAlreadyHaveAWalletButton:"button:has-text('I already have a wallet')",importRecoveryPhraseButton:"button:has-text('Import Recovery Phrase')",importPrivateKeyButton:"button:has-text('Import Private Key')",createSeedPhraseWalletButton:"create-manual-seed-phrase",passwordInput:"onboarding-form-password-input",passwordConfirmInput:"onboarding-form-confirm-password-input",termsCheckBox:"onboarding-form-terms-of-service-checkbox",continueButton:"button:has-text('Continue')",importWalletButton:"button:has-text('Import Wallet')",getStartedButton:"button:has-text('Get Started')",recoveryPhraseSavedCheckbox:"onboarding-form-saved-secret-recovery-phrase-checkbox",recoveryPhraseInput:"secret-recovery-phrase-word-input"};async function D({page:t,privateKey:e,accountName:o,chain:a}){await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.addAccountButton).click(),await t.locator(p.importPrivateKeyButton).click();let i=t.locator("span[id^='button--listbox-input--']"),m=await i.textContent(),l=t.locator("input[name='name']"),h=t.locator("textarea[name='privateKey']");m!==a&&(await i.click(),await t.locator("ul[id^='listbox--listbox-input--']").locator(`li[data-label='${a}']`).click()),await l.fill(o),await h.fill(e),await t.locator("button:has-text('Import')").click()}var S={confirmButton:"primary-button",cancelButton:"secondary-button"};async function nt(t){let e=t.getByTestId(S.confirmButton);await t.getByTestId("approve-transaction").waitFor({state:"attached"});let a=t.getByRole("button",{name:"Confirm anyway",exact:!0});if(await a.isVisible().catch(()=>!1)){await a.click();return}await e.click()}import{expect as Tt}from"@playwright/test";import bt from"zod";async function v(t,e){let o=bt.string().min(1,"Account name cannot be an empty string").parse(e);await t.getByTestId(g.openMenuButton).click();let n=null,r=await t.locator("div[data-testid='account-menu'] div[data-testid='tooltip_interactive-wrapper']").all();for(let u of r)if((await u.textContent())?.includes(o)){n=u;break}if(!n)throw new Error(`Account with name "${o}" not found in the account list.`);await n.click()}async function rt(t,e){e&&await v(t,e);let o=t.getByTestId(S.confirmButton);await Tt(o).toBeEnabled({timeout:15e3}),await o.click()}import It from"zod";var St=t=>t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");async function it({page:t,accountName:e,chain:o}){let a=It.string().min(1,"Account name cannot be an empty string").parse(e);await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.manageAccountsButton).click(),await t.getByTestId(`manage-accounts-sortable-${a}`).click();let i=t.getByRole("button",{name:/Account Address(?:es)?/i});await i.waitFor({state:"visible",timeout:2e4});let l=await i.locator("div[data-name='row.pair'] > div").last().textContent();if(l&&Number(l)===1){await i.locator("> div > div").last().click(),await t.getByTestId("header--back").click();let y=t.getByTestId(B.closeMenuButton);await y.waitFor({state:"visible",timeout:15e3}),await y.click()}else{await i.click();let w=new RegExp(`${St(o.network)}`,"i");await t.getByRole("button",{name:w}).locator("> div").last().locator("> div").last().locator("div > button").last().click(),await t.getByRole("button",{name:"Close",exact:!0}).last().click();let C=t.getByTestId("header--back");await C.waitFor({state:"visible",timeout:15e3}),await C.click();let b=t.getByTestId(B.closeMenuButton);await b.waitFor({state:"visible",timeout:15e3}),await b.click()}return await t.evaluate(async()=>await navigator.clipboard.readText())}async function ct(t){await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.settingsButton).click(),await t.getByTestId(B.lockWalletButton).click()}import{styleText as pt}from"util";import{expect as Nt}from"@playwright/test";function _(t){return new Promise(e=>setTimeout(e,t))}import st from"fs";import vt from"path";async function R(t){let e=x(t),o=vt.resolve(e,"password.txt");try{if(!st.existsSync(o))throw new Error("\u274C password.txt not found. Run setup script first.");return st.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} password from cache: ${a.message}`)}}import{expect as Et}from"@playwright/test";async function lt({context:t,path:e,locator:o}){let a;try{await Et.poll(async()=>(a=t.pages().filter(n=>n.url().startsWith("chrome-extension://")).find(n=>n.url().match(e)),!!a),{timeout:3e4}).toBe(!0)}catch{let n=t.pages().filter(r=>r.url().startsWith("chrome-extension://")).map(r=>r.url());throw new Error(`Popup page with path "${e}" not found in context after 30s. Pages in context: ${JSON.stringify(n)}`)}if(!a)throw new Error(`Popup page with path ${e} not found in context.`);return await Wt(a,o),await a.setViewportSize({width:360,height:592}),a}async function Wt(t,e){await t.waitForLoadState("load",{timeout:4e4}),await t.waitForLoadState("domcontentloaded",{timeout:4e4}),await t.locator(e).first().waitFor({state:"attached",timeout:4e4})}import ut from"fs";import Ft from"path";async function mt(t){let e=x(t),o=Ft.resolve(e,"extension-id.txt");try{if(!ut.existsSync(o))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return ut.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${a.message}`)}}var k=class{name="phantom";onboardingPath="/onboarding.html";async indexUrl(){return`chrome-extension://${await this.extensionId()}/popup.html`}async promptUrl(){return`chrome-extension://${await this.extensionId()}/notification.html`}async extensionId(){return await mt(this.name)}async promptPage(e){let o=await this.promptUrl();return await lt({context:e,path:o,locator:"div[id='root']"})}};async function E(t,e){let a=!1;for(;!e();){let n=e();if(n||a||t.isClosed())break;try{let r=t.locator("div[id='modal']").locator("div > svg").first();await r.isVisible().catch(()=>!1)&&(await r.click(),a=!0)}catch(r){if(t.isClosed())break;console.error("[autoClosePhantomNotification]: ",r)}if(n||a||t.isClosed())break;await _(300)}}async function $({page:t,currentAccountName:e,newAccountName:o}){await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.manageAccountsButton).click();let u=await t.getByTestId(at.accountProfileContainer).locator("div[data-testid^='manage-accounts-sortable'] div > p").all(),i=null;for(let f of u)if((await f.textContent())?.toLowerCase()===e.toLowerCase()){i=f;break}if(!i)throw new Error(`Account with name "${e}" not found`);await i.click(),await t.locator("button:has-text('Account Name')").click();let l=t.locator("input[name='name']");await l.clear(),await l.fill(o),await t.getByTestId("primary-button").click(),await t.getByTestId("header--back").click(),await t.getByTestId(B.closeMenuButton).click()}async function U(t){await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.settingsButton).click()}async function H({page:t,...e}){await U(t);let o=t.locator(`button[id='${B.developerSettingsButton}']`);await o.scrollIntoViewIfNeeded(),await o.click();let a=t.getByTestId("toggleTestNetwork"),r=await a.locator("label[data-testid='toggleTestNetwork-switch'] > input[aria-label='Toggle']").isChecked().catch(()=>!1);if(!r&&e.mode==="on"&&await a.click(),r&&e.mode==="off"){await a.click(),await t.getByTestId("header--back").click(),await t.getByTestId(B.closeMenuButton).click();return}if(e.mode==="on"&&e.chain==="Solana"){let{network:m}=e;await t.locator(`button:has-text("${m}")`).click()}if(e.mode==="on"&&e.chain==="Ethereum"){let{network:m}=e;if(!await t.getByText("EVM",{exact:!0}).isVisible().catch(()=>!1))throw new Error(["EVM testnet options are not available. Please ensure Ethereum is enabled in optional chains.","To enable Ethereum, call the 'toggleOptionalChain' action before switching the network.","toggleOptionalChain({ page: page, toggleMode: 'on', supportedChains: ['Ethereum'] })","Tip: For persistence, enable Ethereum in your setup file after the onboarding step completes."].join(`
|
|
1
|
+
import ot from"fs";import Ct from"path";import{chromium as At}from"@playwright/test";import Bt from"path";var Z=".wallet-cache",tt=".wallet-context";var Y="13.33.0",N="https://github.com/amaify/chainwright/releases/download/v0.1.0/",zt=`https://github.com/MetaMask/metamask-extension/releases/download/v${Y}/metamask-chrome-${Y}.zip`,jt=`${N}solflare-wallet-extension-v2.19.1.zip`,Xt=`${N}petra-wallet-extension-v2.4.8.zip`,Jt=`${N}phantom-wallet-extension-v26.10.0.zip`,qt=`${N}meteor-wallet-extension-v0.7.0.zip`,Qt=`${N}keplr-wallet-extension-v0.13.3.zip`;async function T(t){return Bt.resolve(process.cwd(),tt,t)}import Pt from"path";function x(t){return Pt.resolve(process.cwd(),Z,t)}import et from"fs";import kt from"path";async function I(t){try{let e=x(t),o=kt.resolve(e,"extension-path.txt");if(!et.existsSync(o))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let a=et.readFileSync(o,"utf-8").trim();if(!a)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return a}catch(e){throw new Error(`\u274C Failed to get ${t} extension path: ${e.message}`)}}async function xe({wallet:t,workerInfo:e,profileName:o,slowMo:a}){let n=await T(e.workerIndex.toString()),r=x(t.name),u=Ct.resolve(r,o??"wallet-data");if(!ot.existsSync(u))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);ot.cpSync(u,n,{recursive:!0,force:!0});let i=await I(t.name),m=await At.launchPersistentContext(n,{headless:!1,args:[`--disable-extensions-except=${i}`],slowMo:process.env.HEADLESS?0:a}),l=await t.indexUrl(),h=m.pages()[0];return h||(h=await m.newPage()),await h.goto(l),{context:m,walletPage:h,contextPath:n}}var g={openMenuButton:"settings-menu-open-button",settingsButton:"sidebar_menu-button-settings",addAccountButton:"sidebar_menu-button-add_account",unlockWalletButton:"unlock-form-submit-button",manageAccountsButton:"sidebar_menu-button-manage_accounts",homeHeaderAccountName:"home-header-account-name"},B={lockWalletButton:"lock-menu-item",closeMenuButton:"settings-menu-close-button",developerSettingsButton:"settings-item-developer-settings",activeNetworksButton:"settings-item-active-networks"},at={accountProfileContainer:"sortable-account-container"};var p={createNewWalletButton:"button:has-text('Create a new wallet')",IAlreadyHaveAWalletButton:"button:has-text('I already have a wallet')",importRecoveryPhraseButton:"button:has-text('Import Recovery Phrase')",importPrivateKeyButton:"button:has-text('Import Private Key')",createSeedPhraseWalletButton:"create-manual-seed-phrase",passwordInput:"onboarding-form-password-input",passwordConfirmInput:"onboarding-form-confirm-password-input",termsCheckBox:"onboarding-form-terms-of-service-checkbox",continueButton:"button:has-text('Continue')",importWalletButton:"button:has-text('Import Wallet')",getStartedButton:"button:has-text('Get Started')",recoveryPhraseSavedCheckbox:"onboarding-form-saved-secret-recovery-phrase-checkbox",recoveryPhraseInput:"secret-recovery-phrase-word-input"};async function D({page:t,privateKey:e,accountName:o,chain:a}){await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.addAccountButton).click(),await t.locator(p.importPrivateKeyButton).click();let i=t.locator("span[id^='button--listbox-input--']"),m=await i.textContent(),l=t.locator("input[name='name']"),h=t.locator("textarea[name='privateKey']");m!==a&&(await i.click(),await t.locator("ul[id^='listbox--listbox-input--']").locator(`li[data-label='${a}']`).click()),await l.fill(o),await h.fill(e),await t.locator("button:has-text('Import')").click()}var S={confirmButton:"primary-button",cancelButton:"secondary-button"};async function nt(t){let e=t.getByTestId(S.confirmButton);await t.getByTestId("approve-transaction").waitFor({state:"attached"});let a=t.getByRole("button",{name:"Confirm anyway",exact:!0});if(await a.isVisible().catch(()=>!1)){await a.click();return}await e.click()}import{expect as Tt}from"@playwright/test";import bt from"zod";async function v(t,e){let o=bt.string().min(1,"Account name cannot be an empty string").parse(e);await t.getByTestId(g.openMenuButton).click();let n=null,r=await t.locator("div[data-testid='account-menu'] div[data-testid='tooltip_interactive-wrapper']").all();for(let u of r)if((await u.textContent())?.includes(o)){n=u;break}if(!n)throw new Error(`Account with name "${o}" not found in the account list.`);await n.click()}async function rt(t,e){e&&await v(t,e);let o=t.getByTestId(S.confirmButton);await Tt(o).toBeEnabled({timeout:15e3}),await o.click()}import It from"zod";var St=t=>t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");async function it({page:t,accountName:e,chain:o}){let a=It.string().min(1,"Account name cannot be an empty string").parse(e);await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.manageAccountsButton).click(),await t.getByTestId(`manage-accounts-sortable-${a}`).click();let i=t.getByRole("button",{name:/Account Address(?:es)?/i});await i.waitFor({state:"visible",timeout:2e4});let l=await i.locator("div[data-name='row.pair'] > div").last().textContent();if(l&&Number(l)===1){await i.locator("> div > div").last().click(),await t.getByTestId("header--back").click();let y=t.getByTestId(B.closeMenuButton);await y.waitFor({state:"visible",timeout:15e3}),await y.click()}else{await i.click();let w=new RegExp(`${St(o.network)}`,"i");await t.getByRole("button",{name:w}).locator("> div").last().locator("> div").last().locator("div > button").last().click(),await t.getByRole("button",{name:"Close",exact:!0}).last().click();let C=t.getByTestId("header--back");await C.waitFor({state:"visible",timeout:15e3}),await C.click();let b=t.getByTestId(B.closeMenuButton);await b.waitFor({state:"visible",timeout:15e3}),await b.click()}return await t.evaluate(async()=>await navigator.clipboard.readText())}async function ct(t){await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.settingsButton).click(),await t.getByTestId(B.lockWalletButton).click()}import{styleText as pt}from"util";import{expect as Nt}from"@playwright/test";function _(t){return new Promise(e=>setTimeout(e,t))}import st from"fs";import vt from"path";async function R(t){let e=x(t),o=vt.resolve(e,"password.txt");try{if(!st.existsSync(o))throw new Error("\u274C password.txt not found. Run setup script first.");return st.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} password from cache: ${a.message}`)}}import{expect as Et}from"@playwright/test";async function lt({context:t,path:e,locator:o}){let a;try{await Et.poll(async()=>(a=t.pages().filter(n=>n.url().startsWith("chrome-extension://")).find(n=>n.url().match(e)),!!a),{timeout:3e4}).toBe(!0)}catch{let n=t.pages().filter(r=>r.url().startsWith("chrome-extension://")).map(r=>r.url());throw new Error(`Popup page with path "${e}" not found in context after 30s. Pages in context: ${JSON.stringify(n)}`)}if(!a)throw new Error(`Popup page with path ${e} not found in context.`);return await Wt(a,o),await a.setViewportSize({width:360,height:592}),a}async function Wt(t,e){await t.waitForLoadState("load",{timeout:4e4}),await t.waitForLoadState("domcontentloaded",{timeout:4e4}),await t.locator(e).first().waitFor({state:"attached",timeout:4e4})}import ut from"fs";import Ft from"path";async function mt(t){let e=x(t),o=Ft.resolve(e,"extension-id.txt");try{if(!ut.existsSync(o))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return ut.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${a.message}`)}}var k=class{name="phantom";onboardingPath="/onboarding.html";async indexUrl(){return`chrome-extension://${await this.extensionId()}/popup.html`}async promptUrl(){return`chrome-extension://${await this.extensionId()}/notification.html`}async extensionId(){return await mt(this.name)}async promptPage(e){let o=await this.promptUrl();return await lt({context:e,path:o,locator:"div[id='root']"})}};async function E(t,e){let a=!1;for(;!e();){let n=e();if(n||a||t.isClosed())break;try{let r=t.locator("div[id='modal']").locator("div > svg").first();await r.isVisible().catch(()=>!1)&&(await r.click(),a=!0)}catch(r){if(t.isClosed())break;console.error("[autoClosePhantomNotification]: ",r)}if(n||a||t.isClosed())break;await _(300)}}async function $({page:t,currentAccountName:e,newAccountName:o}){await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.manageAccountsButton).click();let u=await t.getByTestId(at.accountProfileContainer).locator("div[data-testid^='manage-accounts-sortable'] div > p").all(),i=null;for(let f of u)if((await f.textContent())?.toLowerCase()===e.toLowerCase()){i=f;break}if(!i)throw new Error(`Account with name "${e}" not found`);await i.click(),await t.locator("button:has-text('Account Name')").click();let l=t.locator("input[name='name']");await l.clear(),await l.fill(o),await t.getByTestId("primary-button").click(),await t.getByTestId("header--back").click(),await t.getByTestId(B.closeMenuButton).click()}async function U(t){await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.settingsButton).click()}async function H({page:t,...e}){await U(t);let o=t.locator(`button[id='${B.developerSettingsButton}']`);await o.scrollIntoViewIfNeeded(),await o.click();let a=t.getByTestId("toggleTestNetwork"),r=await a.locator("label[data-testid='toggleTestNetwork-switch'] > input[aria-label='Toggle']").isChecked().catch(()=>!1);if(!r&&e.mode==="on"&&await a.click(),r&&e.mode==="off"){await a.click(),await t.getByTestId("header--back").click(),await t.getByTestId(B.closeMenuButton).click();return}if(e.mode==="on"&&e.chain==="Solana"){let{network:m}=e;await t.locator(`button:has-text("${m}")`).click()}if(e.mode==="on"&&e.chain==="Ethereum"){let{network:m}=e;if(!await t.getByText("EVM",{exact:!0}).isVisible().catch(()=>!1))throw new Error(["EVM testnet options are not available. Please ensure Ethereum is enabled in optional chains.","To enable Ethereum, call the 'toggleOptionalChain' action before switching the network.","toggleOptionalChain({ page: page, toggleMode: 'on', supportedChains: ['Ethereum'] })","Tip: For persistence, enable Ethereum in your setup file after the onboarding step completes."].join(`
|
|
2
2
|
`));await t.locator(`button:has-text("${m}")`).click()}await t.getByTestId("header--back").click(),await t.getByTestId(B.closeMenuButton).click()}async function z({page:t,additionalAccounts:e,...o}){console.info(pt("yellowBright",`
|
|
3
3
|
Phantom onboarding started...`,{validateStream:!1}));let a=await R("phantom");if(o.mode==="create"){await t.locator(p.createNewWalletButton).click(),await t.getByTestId(p.createSeedPhraseWalletButton).click();let f=t.getByTestId(p.passwordInput),d=t.getByTestId(p.passwordConfirmInput),A=t.getByTestId(p.termsCheckBox),P=t.locator(p.continueButton);await f.fill(a),await d.fill(a),await A.click(),await P.click(),await P.locator("> div > svg").waitFor({state:"detached",timeout:3e4}),await t.getByTestId(p.recoveryPhraseSavedCheckbox).click(),await P.click(),await _(1e3),await P.click(),await t.locator(p.getStartedButton).last().click()}if(o.mode==="recovery phrase"){let y=o.secretRecoveryPhrase.split(" ");await t.locator(p.IAlreadyHaveAWalletButton).click(),await t.locator(p.importRecoveryPhraseButton).click();for(let[G,O]of Object.entries(y))await t.getByTestId(`${p.recoveryPhraseInput}-${G}`).fill(O);await t.locator(p.importWalletButton).click(),await t.locator("p:has-text('Finding accounts with activity')").waitFor({state:"detached",timeout:6e4});let C=t.locator(p.continueButton);await C.click();let b=t.getByTestId(p.passwordInput),L=t.getByTestId(p.passwordConfirmInput),J=t.getByTestId(p.termsCheckBox);await b.fill(a),await L.fill(a),await J.click(),await C.click(),await C.locator("> div > svg").waitFor({state:"detached",timeout:3e4}),await t.locator(p.getStartedButton).last().click()}if(o.mode==="private key"){await t.locator(p.IAlreadyHaveAWalletButton).click();let{privateKey:y,chain:f,accountName:d}=o;await t.locator(p.importPrivateKeyButton).click();let P=t.locator("span[id='button--listbox-input--1']"),C=await P.textContent(),b=t.locator("input[name='name']"),L=t.locator("textarea[name='privateKey']");C!==f&&(await P.click(),await t.locator("ul[id='listbox--listbox-input--1']").locator(`li[data-label='${f}']`).click()),await b.fill(d),await L.fill(y),await t.locator("button:has-text('Import')").click();let q=t.getByTestId(p.passwordInput),Q=t.getByTestId(p.passwordConfirmInput),G=t.getByTestId(p.termsCheckBox);await q.fill(a),await Q.fill(a),await G.click();let O=t.locator(p.continueButton);await O.click(),await O.locator("> div > svg").waitFor({state:"detached",timeout:3e4}),await t.locator(p.getStartedButton).last().click()}let n=await t.context().newPage(),r=await new k().indexUrl();await n.goto(r);let i=await t.context().browser()?.newBrowserCDPSession(),m;await Nt.poll(async()=>{if(i){let{targetInfos:w}=await i.send("Target.getTargets"),f=w.filter(d=>d.title==="Phantom Wallet").find(d=>!d.attached&&d.url===r);return m=f,!!f}},{timeout:2e4}).toBe(!0),m&&await i?.send("Target.closeTarget",{targetId:m.targetId});let l=await n.getByTestId("home-header-account-name").textContent();if(o.mode==="create"){let{accountName:w}=o;await $({page:n,newAccountName:w,currentAccountName:"Account 1"})}if(e&&e.length>0){let w=!1;E(n,()=>w).catch(d=>console.error({error:d}));for(let{accountName:d,chain:A,privateKey:P}of e)await D({page:n,privateKey:P,accountName:d,chain:A}),w=!0;let f=o.mode==="create"?o.accountName:l;f&&await v(n,f)}o.toggleNetworkMode&&await H({page:n,...o.toggleNetworkMode}),await _(3e3),console.info(pt("greenBright","\u2728 Phantom onboarding completed successfully",{validateStream:!1}))}async function dt(t){let e=t.getByTestId(S.cancelButton);await t.getByTestId("approve-transaction").waitFor({state:"attached"}),await e.click()}async function wt({page:t,supportedChains:e,toggleMode:o="off"}){if(await U(t),await t.locator("button[id='settings-item-active-networks']").click(),e.length===0)throw Error("Supported chains array cannot be empty for toggle mode other than 'onboard'");for(let u of e){let i=t.locator(`button[id='toggle-${u.toLowerCase()}']`),l=await i.locator(`label[data-testid='toggle-${u.toLowerCase()}-switch'] > input[aria-label='Toggle']`).isChecked().catch(()=>!1);o==="off"&&l&&await i.click(),o==="on"&&!l&&await i.click()}await t.getByTestId("header--back").click(),await t.getByTestId(B.closeMenuButton).click()}async function V(t){let e=await R("phantom"),o=t.locator("input[name='password']"),a=t.getByTestId("unlock-form-submit-button");await o.fill(e),await a.click(),await a.waitFor({state:"detached"})}var W=class extends k{page;constructor(e){super(),this.page=e}async onboard({...e}){await z({page:this.page,...e})}async unlock(){await V(this.page)}async lock(){await ct(this.page)}async renameAccount({...e}){await $({page:this.page,...e})}async switchAccount(e){await v(this.page,e)}async getAccountAddress({accountName:e,chain:o}){return await it({page:this.page,accountName:e,chain:o})}async addAccount({...e}){await D({page:this.page,...e})}async toggleOptionalChains({toggleMode:e,supportedChains:o}){await wt({page:this.page,supportedChains:o,toggleMode:e})}async switchNetwork({...e}){await H({page:this.page,...e})}async connectToApp(e){await rt(await this.promptPage(this.page.context()),e)}async confirmTransaction(){await nt(await this.promptPage(this.page.context()))}async rejectTransaction(){await dt(await this.promptPage(this.page.context()))}};import gt from"fs";import Ot from"path";import{test as Dt,chromium as Rt}from"@playwright/test";import{expect as _t}from"@playwright/test";async function j(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}async function M(t,e){let o=await t.newPage();return await _t(async()=>{await o.goto(e),await j(o)}).toPass(),o}async function X(t,e){let o=await e.newPage();for(let{origin:a,localStorage:n}of t){let r=o.mainFrame();await r.goto(a),await r.evaluate(u=>{u.forEach(({name:i,value:m})=>{window.localStorage.setItem(i,m)})},n)}await o.close()}import Mt from"fs/promises";async function ft(t){await Mt.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var Lt=35e3;async function K(t,e){try{await Promise.race([t.close(),new Promise((o,a)=>setTimeout(()=>a(new Error("Context close timed out")),Lt))])}catch(o){console.warn(`Browser context close did not complete cleanly: ${o.message}`)}try{await ft(e)}catch(o){console.error(`Failed to remove temporary context directory at ${e}. Error:`,o)}}var F,Ua=({slowMo:t=0,profileName:e}={})=>Dt.extend({contextPath:async({browserName:o},a,n)=>{let r=await T(`${o}-${n.testId}`);await a(r)},context:async({context:o,contextPath:a},n)=>{let r=new k,u=x(r.name),i=await I(r.name),m=Ot.resolve(u,e??"wallet-data");if(!gt.existsSync(m))throw new Error("\u274C Cache for Phantom wallet data not found. Create it first");gt.cpSync(m,a,{recursive:!0,force:!0}),process.env.HEADLESS&&t>0&&console.warn("\u26A0\uFE0F Slow motion makes no sense in headless mode. It will be ignored!");let l=await Rt.launchPersistentContext(a,{headless:!1,args:[`--disable-extensions-except=${i}`,`--load-extension=${i}`],slowMo:process.env.HEADLESS?0:t});await l.grantPermissions(["clipboard-read"]);let{cookies:h,origins:w}=await o.storageState();h&&await l.addCookies(h),w&&w.length>0&&await X(w,l);let y=await r.indexUrl();F=l.pages().find(d=>d.url().startsWith(y))||await M(l,y);for(let d of l.pages())d.url().includes("about:blank")&&await d.close();await F.bringToFront(),await V(F),await n(l),await K(l,a)},phantomPage:async({context:o},a)=>{await a(F)},phantom:async({context:o},a)=>{let n=new W(F);await a(n)},autoCloseNotification:[async({context:o},a)=>{let n=!1,u=E(F,()=>n);await a(void 0),n=!0,await u.catch(i=>{console.error(`Auto close notification error: ${i.message}`)})},{auto:!0}]});import{test as Ht}from"@playwright/test";import ht from"fs";import $t from"path";import{chromium as Ut}from"@playwright/test";async function yt({workerInfo:t,profileName:e,slowMo:o}){let a=new k,n=await T(t.workerIndex.toString()),r=x(a.name),u=$t.resolve(r,e??"wallet-data");if(!ht.existsSync(u))throw new Error(`Cache for ${a.name} does not exist. Create it first!`);ht.cpSync(u,n,{recursive:!0,force:!0});let i=await I(a.name),m=await Ut.launchPersistentContext(n,{headless:!1,args:[`--disable-extensions-except=${i}`],slowMo:process.env.HEADLESS?0:o}),l=await a.indexUrl(),h=await M(m,l);return{context:m,walletPage:h,contextPath:n}}var rn=({slowMo:t,profileName:e}={})=>Ht.extend({workerScopeContents:[async({browser:o},a,n)=>{let{context:r,contextPath:u,walletPage:i}=await yt({workerInfo:n,profileName:e,slowMo:t});await r.grantPermissions(["clipboard-read"]);for(let l of r.pages())l.url().includes("about:blank")&&await l.close();let m=new W(i);await m.unlock(),await a({wallet:m,walletPage:i,context:r}),await K(r,u)},{scope:"worker"}],autoCloseNotification:[async({workerScopeContents:o},a)=>{let n=!1,r=()=>n,u=E(o.walletPage,r);await a(void 0),n=!0,await u.catch(i=>{console.error(`Auto close notification error: ${i.message}`)})},{auto:!0}]});export{W as Phantom,Ua as phantomFixture,rn as phantomWorkerScopeFixture,xe as workerScopeContext};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import q from"fs";import dt from"path";import{chromium as gt}from"@playwright/test";import ut from"path";var K=".wallet-cache",j=".wallet-context";var H="13.
|
|
1
|
+
import q from"fs";import dt from"path";import{chromium as gt}from"@playwright/test";import ut from"path";var K=".wallet-cache",j=".wallet-context";var H="13.33.0",k="https://github.com/amaify/chainwright/releases/download/v0.1.0/",Wt=`https://github.com/MetaMask/metamask-extension/releases/download/v${H}/metamask-chrome-${H}.zip`,Nt=`${k}solflare-wallet-extension-v2.19.1.zip`,Ft=`${k}petra-wallet-extension-v2.4.8.zip`,Mt=`${k}phantom-wallet-extension-v26.10.0.zip`,_t=`${k}meteor-wallet-extension-v0.7.0.zip`,Dt=`${k}keplr-wallet-extension-v0.13.3.zip`;async function h(t){return ut.resolve(process.cwd(),j,t)}import wt from"path";function u(t){return wt.resolve(process.cwd(),K,t)}import z from"fs";import ft from"path";async function S(t){try{let e=u(t),r=ft.resolve(e,"extension-path.txt");if(!z.existsSync(r))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let o=z.readFileSync(r,"utf-8").trim();if(!o)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return o}catch(e){throw new Error(`\u274C Failed to get ${t} extension path: ${e.message}`)}}async function ae({wallet:t,workerInfo:e,profileName:r,slowMo:o}){let a=await h(e.workerIndex.toString()),n=u(t.name),p=dt.resolve(n,r??"wallet-data");if(!q.existsSync(p))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);q.cpSync(p,a,{recursive:!0,force:!0});let l=await S(t.name),c=await gt.launchPersistentContext(a,{headless:!1,args:[`--disable-extensions-except=${l}`],slowMo:process.env.HEADLESS?0:o}),f=await t.indexUrl(),m=c.pages()[0];return m||(m=await c.newPage()),await m.goto(f),{context:c,walletPage:m,contextPath:a}}var P={networkSettings:"li-settings-network",selectNetwork:"select-network",confirmModal:"modal-confirm",confifmButton:"btn-confirm",securityAndPrivacyButton:"nav-item-security-and-privacy",lockButton:"btn-lock"},A={portfolioButton:"nav-item-portfolio",walletSelectorButton:"icon-section-wallet-picker-arrow-right"};import b from"zod";var G=b.object({walletName:b.string().min(1,"Wallet name cannot be an empty string"),privateKey:b.array(b.number()).length(64)});async function v({page:t,privateKey:e,walletName:r}){let o=G.parse({privateKey:e,walletName:r});await t.getByTestId(A.walletSelectorButton).click(),await t.getByTestId("icon-btn-add").click(),await t.getByTestId("li-add-wallet-privateKey-add").click();let l=t.getByTestId("input-name"),c=t.getByTestId("input-private-key");await l.fill(o.walletName),await c.fill(`${o.privateKey}`),await t.getByTestId("btn-import").click(),await t.locator("span:has-text('My wallets')").waitFor({state:"attached"}),await t.getByRole("dialog").getByTestId("icon-btn-close").click()}import{expect as yt}from"@playwright/test";var E={approveButton:"btn-approve",rejectButton:"btn-reject"};async function X(t){let e=t.getByTestId(E.approveButton);if(await t.getByTestId("section-network-fee").waitFor({state:"attached",timeout:15e3}).catch(()=>!1),await t.getByTestId("info-box-network-mismatch").isVisible().catch(()=>!1)){console.error(`
|
|
2
2
|
|
|
3
3
|
A 'Network mismatch' error was detected in the transaction confirmation popup. Closing the popup and aborting the transaction confirmation process.`),await t.getByRole("button",{name:"Close",exact:!0}).click();return}let n=t.locator("div[data-id='control-label']");await n.isVisible().catch(()=>!1)&&await n.click(),await yt(e).toBeEnabled(),await e.click()}async function W(t,e){await t.getByTestId("icon-section-wallet-picker-arrow-right").click();let o=t.getByTestId("list-item-m-title").filter({hasText:e}).locator("xpath=../..");if(!await o.isVisible().catch(()=>!1))throw new Error(`Account "${e}" not found. Make sure the account is onboarded or verify the account name.`);await o.click()}async function J(t,e){e&&await W(t,e),await t.getByRole("button",{name:"Connect",exact:!0}).click()}async function Q(t){return await t.getByTestId("icon-section-wallet-picker-copy").click(),await t.evaluate(async()=>await navigator.clipboard.readText())}async function N(t){let e=t.getByRole("button",{name:"settings",exact:!0});await e.waitFor({state:"attached",timeout:3e4}),await e.click()}async function Y(t){await N(t),await t.getByTestId(P.securityAndPrivacyButton).click(),await t.getByTestId("li-settings-lock").getByTestId(P.lockButton).click()}import{styleText as tt}from"util";import Z from"fs";import xt from"path";async function F(t){let e=u(t),r=xt.resolve(e,"password.txt");try{if(!Z.existsSync(r))throw new Error("\u274C password.txt not found. Run setup script first.");return Z.readFileSync(r,"utf-8")}catch(o){throw new Error(`\u274C Failed to get ${t} password from cache: ${o.message}`)}}var y={alreadyHaveAWalletButton:"btn-already-have-wallet",recoveryPhraseInput:"input-recovery-phrase",continueButton:"btn-continue",passwordInput:"input-new-password",repeatPasswordInput:"input-repeat-password",quickSetupButton:"btn-quick-setup",IAgreeButton:"btn-explore"};async function M({page:t,currentAccountName:e,newAccountName:r}){await t.getByTestId(A.walletSelectorButton).click();let a=t.locator(`button[data-testid^='li-wallets']:has-text('${e}')`);if(!await a.isVisible().catch(()=>!1))throw new Error(`Account "${e}" not found. Make sure the account is available.`);await a.hover({timeout:2e4}),await a.getByTestId("icon-btn-three-dots").click({timeout:2e4});let l=t.getByTestId("li-manage-wallet-rename-wallet");await l.click();let c=t.getByTestId("input-name");await c.clear(),await c.fill(r),await t.getByTestId("btn-save").click(),await l.waitFor({state:"attached",timeout:15e3}),await t.getByTestId("icon-btn-close").click()}async function _(t,e){await N(t);let o=t.getByTestId("li-settings-network").getByRole("combobox");await o.locator(" > p").textContent()!==e?(await o.click(),await t.getByTestId(P.selectNetwork).getByRole("option",{name:e,exact:!0}).click(),(e==="Devnet"||e==="Testnet")&&await t.getByTestId(P.confirmModal).getByTestId(P.confifmButton).click()):console.info(`Network is already set to ${e}`),await t.getByTestId(A.portfolioButton).click()}async function et({page:t,recoveryPhrase:e,network:r,walletName:o,additionalAccounts:a}){console.info(tt("yellowBright",`
|
|
4
4
|
Solflare onboarding started...`,{validateStream:!1}));let n=await F("solflare");await t.getByTestId(y.alreadyHaveAWalletButton).click();let l=e.split(" ");for(let[I,g]of Object.entries(l))await t.getByTestId(`${y.recoveryPhraseInput}-${Number(I)+1}`).fill(g);let c=t.getByTestId(y.continueButton);await c.click();let f=t.getByTestId(y.passwordInput),m=t.getByTestId(y.repeatPasswordInput);if(await f.fill(n),await m.fill(n),await c.click(),await t.locator("div",{hasText:"Detecting your existing accounts. This process can take up to a minute."}).waitFor({state:"detached"}),await t.getByTestId(y.quickSetupButton).click(),await t.getByTestId(y.IAgreeButton).click(),await M({page:t,currentAccountName:"Main Wallet",newAccountName:o}),r&&await _(t,r),a&&a.length>0)for(let{privateKey:I,walletName:g}of a)await v({page:t,privateKey:I,walletName:g});console.info(tt("greenBright","\u2728 Solflare onboarding completed successfully",{validateStream:!1}))}async function ot(t){await t.getByTestId(E.rejectButton).click()}async function D(t){let e=await F("solflare");await t.getByTestId("input-password").fill(e),await t.getByTestId("btn-unlock").click(),await t.getByTestId("nav-main").waitFor({state:"attached",timeout:3e4})}import{expect as ht}from"@playwright/test";async function rt({context:t,path:e,locator:r}){let o;try{await ht.poll(async()=>(o=t.pages().filter(a=>a.url().startsWith("chrome-extension://")).find(a=>a.url().match(e)),!!o),{timeout:3e4}).toBe(!0)}catch{let a=t.pages().filter(n=>n.url().startsWith("chrome-extension://")).map(n=>n.url());throw new Error(`Popup page with path "${e}" not found in context after 30s. Pages in context: ${JSON.stringify(a)}`)}if(!o)throw new Error(`Popup page with path ${e} not found in context.`);return await Pt(o,r),await o.setViewportSize({width:360,height:592}),o}async function Pt(t,e){await t.waitForLoadState("load",{timeout:4e4}),await t.waitForLoadState("domcontentloaded",{timeout:4e4}),await t.locator(e).first().waitFor({state:"attached",timeout:4e4})}import at from"fs";import St from"path";async function nt(t){let e=u(t),r=St.resolve(e,"extension-id.txt");try{if(!at.existsSync(r))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return at.readFileSync(r,"utf-8")}catch(o){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${o.message}`)}}var x=class{name="solflare";onboardingPath="wallet.html#/onboard";async indexUrl(){return`chrome-extension://${await this.extensionId()}/wallet.html#/portfolio`}async promptUrl(){return`chrome-extension://${await this.extensionId()}/confirm_popup.html`}async extensionId(){return await nt(this.name)}async promptPage(e){let r=await this.promptUrl();return await rt({context:e,path:r,locator:"div[data-testid='page-dapp-connect'], div[data-testid='page-tx-sign']"})}};var B=class extends x{page;constructor(e){super(),this.page=e}async onboard({recoveryPhrase:e,network:r,additionalAccounts:o,walletName:a}){await et({page:this.page,recoveryPhrase:e,network:r,additionalAccounts:o,walletName:a})}async unlock(){await D(this.page)}async lock(){await Y(this.page)}async renameAccount({currentAccountName:e,newAccountName:r}){await M({page:this.page,currentAccountName:e,newAccountName:r})}async switchNetwork(e){await _(this.page,e)}async switchAccount(e){await W(this.page,e)}async getAccountAddress(){return await Q(this.page)}async addAccount({privateKey:e,walletName:r}){await v({page:this.page,privateKey:e,walletName:r})}async connectToApp(e){await J(await this.promptPage(this.page.context()),e)}async confirmTransaction(){await X(await this.promptPage(this.page.context()))}async rejectTransaction(){await ot(await this.promptPage(this.page.context()))}};import ct from"fs";import Ct from"path";import{test as Tt,chromium as It}from"@playwright/test";import{expect as At}from"@playwright/test";async function C(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}async function U(t,e){let r=await t.newPage();return await At(async()=>{await r.goto(e),await C(r)}).toPass(),r}async function V(t,e){let r=await e.newPage();for(let{origin:o,localStorage:a}of t){let n=r.mainFrame();await n.goto(o),await n.evaluate(p=>{p.forEach(({name:l,value:c})=>{window.localStorage.setItem(l,c)})},a)}await r.close()}import Bt from"fs/promises";async function it(t){await Bt.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var kt=35e3;async function O(t,e){try{await Promise.race([t.close(),new Promise((r,o)=>setTimeout(()=>o(new Error("Context close timed out")),kt))])}catch(r){console.warn(`Browser context close did not complete cleanly: ${r.message}`)}try{await it(e)}catch(r){console.error(`Failed to remove temporary context directory at ${e}. Error:`,r)}}function st(t){return new Promise(e=>setTimeout(e,t))}async function L(t,e){let o=!1;for(;!e();){let a=e();if(a||o||t.isClosed())break;try{let n=t.locator("div[role='dialog']").locator("button[data-testid='icon-btn-whats-new-modal-close']");await n.isVisible().catch(()=>!1)&&(await n.click(),o=!0)}catch(n){console.error("[autoCloseSolflareNotification]: ",n)}if(a||o||t.isClosed())break;await st(150)}}var T,fr=({slowMo:t=0,profileName:e}={})=>Tt.extend({contextPath:async({browserName:r},o,a)=>{let n=await h(`${r}-${a.testId}`);await o(n)},context:async({context:r,contextPath:o},a)=>{let n=new x,p=u(n.name),l=await S(n.name),c=Ct.resolve(p,e??"wallet-data");if(!ct.existsSync(c))throw new Error("\u274C Cache for Solflare wallet data not found. Create it first");await ct.promises.cp(c,o,{recursive:!0,force:!0});let f=[`--disable-extensions-except=${l}`,`--load-extension=${l}`];process.env.HEADLESS&&(f.push("--headless=new"),t>0&&console.warn("\u26A0\uFE0F Slow motion makes no sense in headless mode. It will be ignored!"));let m=await It.launchPersistentContext(o,{headless:!1,args:[`--disable-extensions-except=${l}`],slowMo:process.env.HEADLESS?0:t});await m.grantPermissions(["clipboard-read"]);let{cookies:d,origins:w}=await r.storageState();d&&await m.addCookies(d),w&&w.length>0&&V(w,m);let R=await n.indexUrl(),$=R.split("#")[0]??"";await m.waitForEvent("page",{predicate:g=>g.url().includes($),timeout:15e3}),T=m.pages().find(g=>g.url().startsWith($))||await U(m,R);for(let g of m.pages())g.url().includes("about:blank")&&await g.close();await D(T),await a(m),await O(m,o)},solflarePage:async({context:r},o)=>{await o(T)},solflare:async({context:r},o)=>{let a=new B(T);await o(a)},autoCloseNotification:[async({context:r},o)=>{let a=!1,p=L(T,()=>a);await o(void 0),a=!0,await p.catch(l=>{console.error(`Auto close notification error: ${l.message}`)})},{auto:!0}]});import{test as Et}from"@playwright/test";import lt from"fs";import bt from"path";import{chromium as vt}from"@playwright/test";async function pt({workerInfo:t,profileName:e,slowMo:r}){let o=new x,a=await h(t.workerIndex.toString()),n=u(o.name),p=bt.resolve(n,e??"wallet-data");if(!lt.existsSync(p))throw new Error(`Cache for ${o.name} does not exist. Create it first!`);lt.cpSync(p,a,{recursive:!0,force:!0});let l=await S(o.name),c=await vt.launchPersistentContext(a,{headless:!1,args:[`--disable-extensions-except=${l}`],slowMo:process.env.HEADLESS?0:r}),f=await o.indexUrl(),m=f.split("#")[0]??"";await c.waitForEvent("page",{predicate:w=>w.url().includes(m),timeout:15e3});let d=c.pages().find(w=>w.url().startsWith(m));d||(d=await c.newPage(),await d.goto(f),await C(d));for(let w of c.pages())w.url().includes("about:blank")&&await w.close();return{context:c,walletPage:d,contextPath:a}}var Nr=({slowMo:t,profileName:e}={})=>Et.extend({workerScopeContents:[async({browser:r},o,a)=>{let{context:n,contextPath:p,walletPage:l}=await pt({workerInfo:a,profileName:e,slowMo:t});await n.grantPermissions(["clipboard-read"]);let c=new B(l);await c.unlock(),await o({wallet:c,walletPage:l,context:n}),await O(n,p)},{scope:"worker"}],autoCloseNotification:[async({workerScopeContents:r},o)=>{let a=!1,n=()=>a,p=L(r.walletPage,n);await o(void 0),a=!0,await p.catch(l=>{console.error(`Auto close notification error: ${l.message}`)})},{auto:!0}]});export{B as Solflare,fr as solflareFixture,Nr as solflareWorkerScopeFixture,ae as workerScopeContext};
|
package/package.json
CHANGED